home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Datafile PD-CD 3
/
PDCD_3.iso
/
utilities
/
utilsd
/
drwimp
/
TextManual
< prev
Wrap
Text File
|
1995-05-29
|
82KB
|
2,092 lines
-------------------------------------------------
DrWimp
Cures your desktop problems!
1.05 (28-May-95)
© Andrew Ayre 1995
Public Domain - see conditions of use
-------------------------------------------------
*****************************************************************************
Section 1 - Introduction
*****************************************************************************
Prologue
Ever wanted to write high quality multitasking programs? Can't quite get
the hang of manipulating words, bytes, menu structures and message systems?
Have you looked in despair at the amount of programming needed to get a
single window on the desktop?
Forget all your worries and write great applications with great ease;
Doctor Wimp is here!
DrWimp - solves all your multitasking worries!
Banish that dodgy polling code to your disc box! Wipe that broken window
redraw program from your hard drive! Drop that tired out menu creator into
your null: device!!
The DrWimp system consists of:
•The DrWimp library.
•A template !RunImage file.
•This manual in Impression format and text format.
•Example Template files for standard windows.
•Support files for the tutorials.
•!Func'n'Proc quick browser.
•!MakeApp2, !Crunch and !TemplEd PD utilities.
•Example applications written using DrWimp, with fully commented code.
DrWimp - THE system to use!
Conditions of use
DrWimp may be distributed for free and without the documentation,
examples, utilities, etc. if it is being used in a Public Domain, Shareware,
Cover Disc or Disc Magazine program. If you wish to distribute it with a
commercial program then contact the author to obtain permission and
negotiate royalties.
Public Domain libraries may charge for materials, handling, etc. as long
as this does no exceed £2.00 (UK) net.
The DrWimp file may not be reproduced in part. It may only be reproduced
in whole. I recommend using !MakeApp2 and !Crunch for security.
The DrWimp system (apart from !MakeApp2, !Crunch and !TemplEd) may only be
distributed as a whole. For conditions of use of !MakeApp2, !Crunch and
!TemplEd see their own !Help files.
The author retains copyright of DrWimp, documentation and examples at all
times.
Documentation and utilities can be obtained from the Datafile PD library
or direct from the author at:
E-mail: A.J.Ayre@e-eng.hull.ac.uk
Help on any aspect of DrWimp (and the documentation + utils if you include
a DD disc) can be obtained from the author at:
Snail mail: Andrew Ayre
24 Skirbeck Rd,
Gillshill Rd,
Hull,
East Yorkshire
HU8 0HR
England
E-mail: A.J.Ayre@e-eng.hull.ac.uk
Getting started
In this manual all functions (FN) and procedures (PROC) will be referred
to as just functions.
The file DrWimp does all the work, and the !RunImage file is where you
control things from.
DrWimp is just a collection of functions that you can call from the
!RunImage file. All the functions in DrWimp are in lowercase and preceded by
“wimp_”, eg:
PROCwimp_dosomethingamazing(curtain$)
Some of these functions need help from you, so they call a function that
is in the !RunImage file, where you can easily tailor it to your
applications needs. All these functions are also in lowercase, but they are
preceded by “user_”, eg:
FNuser_givemesomehelp(tomato$)
For a “blank” application which does nothing all the “user_” functions
will be empty, and return default values if they are of the “FN” type. These
functions have to be there otherwise your application might complain that
one of them can't be found, regardless of whether they do anything or not.
From now on functions in the !RunImage file preceded by “user_” will be
referred to as “user functions”, and functions in the DrWimp file preceded
by “wimp_” will be referred to as “wimp functions”.
To save you having to type in a standard set of user functions every time
you write an application, there is a template application called “!MyApp”.
Inside !MyApp is a template !RunImage file. This file calls a function that
starts up your application, because you can't do anything multitasking until
you call it. You will have to change the details of this call to suit your
application.
The utility !Fnc'n'Prc (supplied in the “Utils” folder) is a catalogue of
all the user and wimp functions. It details what parameters you have to pass
and what is returned. It is also a demonstration of the DrWimp system, as it
was written using it, and in particular the ability to easily add panes to
windows and saving files.
The source code is included, and is fully commented to help you further
understand how to get DrWimp to do what you want.
It may seem that most of the functions have far too many parameters than
is needed. This is true in that most of the time the parameters will be
largely the same, but having more parameters gives you, the programmer, as
much flexibilty as possible.
The main difference that multi-tasking programs have over the others, is
that they are not linear. The program doesn't start at the top and work its
way to the bottom. Instead, multi-tasking programs jump about depending on
whether an icon has been clicked on, or a window dragged, or a menu item
chosen, etc. All your application has to do is respond to these “events”
when they happen.
Handles
DrWimp expects windows to be loaded in from a templates file. Menus are
created from a shorthand in the !RunImage file. Once you have loaded in a
window or created a menu you need some way of getting at the information so
you can put the menu on the screen, or change some of the window attributes,
etc. The way this is done is by handles, and they form a very important part
in programming the wimp.
When you load in a window, DrWimp asks the machine to reserve some memory
for it to put all the information about the window into. It does this using
the DIM command, eg:
DIM block% 256
This will reserve a chunk of memory 256 bytes long, and the first memory
address in that chunk is in block%. This is so you can find it and change
the contents of the chunk of memory.
So if you load in a window called “save”, then you might reserve a chunk
of memory called save%, so you can easily see that the memory address save%
is the start of the information about the save window, you loaded in when
the application first started.
The handle to the save window is therefore save%.
The same is for menus. When you ask DrWimp to create a menu from the
shorthand that you supply, it gets a chunk of memory and fills it with the
information needed for the wimp to create the menu. eg: if you were creating
a menu for the iconbar icon of your application, then you might call the
handle something like barmenu%.
In general it is very wise to call the handle something that reminds you
of what it is a handle for. If you load in five windows, then it would be a
bit stupid to call the handles a%, b%, c%, d%, e%!
You will find that most wimp and user functions require a handle to a
window or a menu to be passed to them, so you will need to use them a lot.
Look at the following piece of code (the functions will be described in
more detail later on):
find% = FNwimp_loadwindow("Templates","find",1)
PROCwimp_openwindow(find%,1,-1)
The first line calls a wimp function that loads in a window from a
templates file called “find”, so we can assume that it is a window for
entering something to find. The function returns a handle to the window,
which has been called find%. From now on, whenever we want to do something
with the find window, we use the variable find%. Look at the second line.
Here a wimp function is being called that opens a window. Passed to it is
the window handle, telling it which window to open (and some numbers
regarding the positions to open it at).
The handle could have been called anything, eg:
coffee% = FNwimp_loadwindow("Templates","find",1)
Or changed later on, eg:
find% = FNwimp_loadwindow("Templates","find",1)
coffee% = find%
Variables & Strings
One of the first lines of the !RunImage file should be something like:
LIBRARY "<MyApp$Dir>.DrWimp"
This tells the BASIC interpreter that you want to use a library and where
it is. After this call, the two files (DrWimp and !RunImage) may be separate
but they work as if all the code is in one file. Eg: you can call functions
in DrWimp from !RunImage and call functions in !RunImage from DrWimp.
More importantly, any variables or strings that are created in one of the
files and isn't localised, will be available to both files, so either one
can alter the contents. This can cause problems, because you could be using
a variable in the !RunImage file, and then call a wimp function that also
uses it, so when the function is exited, the variable will be different from
what your code expects.
This problem has been largely overcome by localising most of the variables
used in DrWimp. However, there are a handful of variables that cannot be
localised for one reason or another.
All but two of the variables start with a lowercase “w”, so you can easily
choose variable names that don't clash: simply don't start them with a “w”.
The variables that start with “w” should not be changed. The two other
variables finished% and NULL are supposed to be changed:
By setting finished% to TRUE, the application will quit as soon as
possible. This is how the Quit menu option on the iconbar menu works.
By setting NULL to TRUE, the user function PROCuser_null will be called
every time the wimp passes control to the application and nothing is
happening with it, eg: clicking on icons, dragging windows, receiving
messages, etc. This is useful for timed or delayed things. You keep track of
the time and after a certain delay you change a windows contents (say for a
clock) or send a message to another application.
System variables
It is important that you make sure that your application can run from
anywhere, eg: floppy disc, hard drive, CD, etc, but you have to access files
in the application directory, eg: templates, sprites, message files, etc.
System variables differ from BASIC variables in that System variables are
set from the command line using a star command. Unfortunately it isn't very
easy to read the contents of a system variable from BASIC programs. Because
of this, DrWimp provides a wimp function (FNwimp_sysvariable) to do this for
you, and it will be described in more detail later.
When the !Run file of your application is run it sets up a system variable
called “Obey$Dir” which contains the full pathname to your application
directory. So if you have a file called “Templates” inside your application
directory, then its full pathname can be written as <Obey$Dir>.Templates.
But if between your !Run file being run and your application loading in a
file, another !Run file from another application is run, Obey$Dir will
change. So in your !Run file you must make a copy of Obey$Dir that can be
used instead.
If your application is called “MyApp” then you would use:
Set MyApp$Dir <Obey$Dir>
and then you would get to your “Templates” file inside your application
directory by using: <MyApp$Dir>.Templates.
System variables can also be used for other things. Eg: if you wrote a
database application then you might have to set the maximum number of
records allowed for the amount of memory that you have allocated. The limit
could be put in the !Run file instead of the !RunImage file so
non-programmers don't have to go and delve into your code. So you could have
a line in your !Run file like:
Set MaxRecords 5000
Then in your !RunImage file you could read the value with something like:
MaxAllowed% = VAL(FNwimp_sysvariable("MaxRecords"))
Security
If you are going to distribute a new and brilliant application that you
have slaved over for weeks, then you are going to want some security.
!MakeApp2 and !Crunch between them re-filetype and completely mangle BASIC
programs up, and they still run. If you have a !RunImage file and a library
which it uses then you can't mangle the library, only the !RunImage file.
But what you can do is add the library onto the end of your !RunImage file.
!MakeApp2 and !Crunch have their own !Help files, but here is a brief
summary:
•First of all make a copy of your !RunImage file!!
•Add DrWimp onto the end of your !RunImage file (this can be done easily
in !Edit by positioning the caret at the end of !RunImage then dragging
DrWimp into the window)
•Remove the LIBRARY command.
•Resave as !RunImage.
•Load !MakeApp2 and !Crunch and drop !RunImage on !MakeApp2 and save as
something like “Absolute” (it should be filetyped as Absolute now).
•Drag the absolute file onto !Crunch and when it has finished save as
!RunImage. You should get something like 50% compression.
Make sure that you are running the !RunImage file from !Run with something
like:
Run <Obey$Dir>.!RunImage
and not:
BASIC -quit <Obey$Dir>.!RunImage
If you have an Info window in your application then don't put your name
into the icon in the templates file. Instead put it in using
PROCwimp_puticontext from the !RunImage file.
*****************************************************************************
Section 2 - Tutorials
*****************************************************************************
Notes
This is the bit where you get to do some programming at last!, but first
some quick notes.
I would highly recommend using !TemplEd for editing/creating template
files. It is very easy to use and it is included with DrWimp. Full
instructions can be found in Manual inside the !TemplEd directory.
The tutorials use some support files and pre-made templates files. They
can be found inside the Tutorial directory. They template files contain
standard windows like Info and Save windows. Feel free to use these in your
programs (PD or commercial). There are no conditions attached to them.
Before you start, make a copy of the “blank” application !MyApp to work
on. Put it on a fresh disc or in a new directory.
If you get stuck or come across a problem then please, don't hesitate to
get in touch. Your information could benefit other users.
Most learning is done through experimentation. In most of the tutorials,
you will be invited to fiddle and generally muck about with the code. The
worst that can happen through doing this is your application crashes and is
quitted by the Task Manager.
To help you to understand further how to use DrWimp, some applications are
supplied with the DrWimp system. They have fully commented !RunImage files
so you can study them.
•!Fnc'n'Prc lists summaries of all the functions related to DrWimp. It
demonstrates: panes, interactive help, save windows/saving data.
•!FontRun is a utility to choose whether to boot your fonts or not
whenever you reset your machine. There are two versions of this. One is a
Public Domain utility with the source code mangled, and the one here may
only be distributed with the DrWimp system. It demonstrates: dynamic menus,
drop boxes, saving data, loading data (getting pathnames of font folders).
•!Saver doesn't do anything useful. It just demonstrates a multi-filetype
save window.
•!Bar also doesn't do anything useful. It demonstrates how to use bars.
They can be useful for show the percentage done of an operation, etc.
1. Getting going
Double-click on !MyApp. Nothing should happen. If you now open the task
manager display and look at the list of tasks, you should see “MyApp” at the
bottom.
Load !RunImage into !Edit and take a look at how it works. The !Run file
copies the system variable Obey$Dir into MyApp$Dir. The LIBRARY command can
then be used with the system variable.
The application name is put into a string to make it easier to change
later on. The next line is in case of an error. All it does is call
PROCwimp_error. This wimp function will be looked at in more detail later
on.
The next line is very important and your application can't do anything
until it has been called. It registers your application with the task
manager and it returns a handle for your task. This has been put into task%.
For the moment the second and third parameters are just set to largish
values. When the application is finished you can reduce them. Basically they
are (from left to right) sizes of areas to reserve for window definitions
(including all the icons in the window), and the indirected text (like large
menu entries and long window titles). The first parameter is the text that
appears in the task manager window, and can be anything. Try it and see!
Note: the wimp automatically truncates it if it is too long. The last
parameter is the minimum version number of RISC OS that the application is
allowed to run on multiplied by 100. The default is 200, so MyApp will run
on RISC OS 2.00 or better. Note: the version number returned by the WIMP to
DrWimp isn't always very accurate. For example, if you want to set the
minimum version to RISC OS 3.11, then set the last parameter to 316! This is
not the fault of DrWimp.
The final line calls PROCwimp_poll. This is a continuous loop until your
application quits for some reason, and makes it multitasking.
The rest of the !RunImage file is all the user functions. They are all
empty at the moment and do nothing or return default values.
It doesn't do much at the moment and there is nowhere for the user to get
access to our application. The best thing to do is add an icon to the
iconbar.
After FNwimp_initialise, add the following line:
ibar%=FNwimp_iconbar("!myapp","",1)
The function returns a handle to the window that contains the icon.
“!myapp” is the name of the sprite to use for the icon. Try changing it to
“!draw” and see what happens. The next parameter is the text to place under
the icon (like the floppy drive icon). If it is an empty string then no text
is printed. Try entering some text and reload the application. The final
parameter controls the side of the iconbar that the icon appears on. 0 for
left and 1 for right.
2. Menus
What is needed now is a menu for the iconbar. Menus are created by DrWimp
from a shorthand form which is passed as a string. DrWimp translates it into
the correct layout in a block of memory for the wimp to understand. After
the FNwimp_iconbar, add the following line:
barmenu%=FNwimp_createmenu("MyApp/Info/Quit",0)
This creates a menu and returns a handle for it, which is put into
barmenu%. Each entry or item on the menu is separated by a “/”. The first
item is the menu title, so from the line just added, a menu will be created
with the title “MyApp” and two entries. The top one is “Info” and the bottom
one is “Quit”. The last parameter is the maximum number of items allowed to
be used. It is set to 0, so this means that just allow space for the items
specified.
At the moment DrWimp doesn't know about the menu, all we have done is set
it up in memory. Whenever the Menu button is pressed over a window belonging
to the application, DrWimp calls the user function FNuser_menu. Passed to it
is the window handle (in window%) and the icon number (in icon%). If there
is a menu for that window/icon then we have to return the handle to it,
otherwise return a 0.
Move down to FNuser_menu and change it so it is like:
DEF FNuser_menu(window%,icon%)
CASE window% OF
WHEN ibar% : =barmenu%
ENDCASE
=0
As you can see, whenever the window whose handle is ibar% (the window
containing the iconbar icon) has menu pressed over it, the handle to the
iconbar menu is returned. Try running the application.
As you will see from running it, Quit doesn't do anything. When a menu
item is selected, DrWimp calls another user function:
PROCuser_menuselection. This time nothing has to be returned, you only have
to act on the selection made by the user.
Passed to the function is the handle of the menu that the user chose an
item from (menu%) and the number of the item (item%). The top-most item is
number 1, so for Quit:
menu% = barmenu% and item% = 2.
Add the following to make PROCuser_menuselection look like:
DEF PROCuser_menuselection(menu%,item%)
CASE menu% OF
WHEN barmenu% :
CASE item% OF
WHEN 2 : finished%=TRUE
ENDCASE
ENDCASE
ENDPROC
Recall from Section 1, setting finished% to TRUE quits the application as
soon as possible. Run the application and confirm that it does indeed work.
Try adding some more items to the menu. Don't forget to increase the “2”
in PROCwimp_menuselection accordingly though! Try getting the computer to
make a beep when you select one of the items. VDU7 would be ideal for this.
Note: there is no need to change the last parameter to PROCwimp_createmenu.
3. Windows
What is needed now is an info window that can be accessed from the iconbar
menu. In the tutorials folder you will find the file “Template1”. Copy this
into the MyApp application directory and rename as “Templates”. You can
examine it if you want by loading it into !TemplEd.
Add the following line below FNwimp_iconbar (above FNwimp_createmenu):
info%=FNwimp_loadwindow("<MyApp$Dir>.Templates","info",1)
This function loads in a window from the templates file, whose full
pathname is given in the first parameter. The second parameter is the name
of the window in the templates file, and the last parameter tells DrWimp
where to get the sprites from for the window. A 0 means use a user sprite
area, but we haven't set one up yet, and besides there are no sprites in the
window, only the borders built into RISC OS 3. A 1 means use the wimp sprite
pool (RMA), and this is the most common option.
The function returns a handle to the window which we have put into info%.
Now we need to modify the iconbar menu to take into account the window.
This is very simple to do and it is mostly done automatically. All you have
to do is change the line that calls FNwimp_createmenu to look like:
barmenu%=FNwimp_createmenu("MyApp/Info>info%/Quit",0)
And thats it! Re-load MyApp and you will now see that the Info menu item now
has a submenu which leads to the info window.
Looking more closely at FNwimp_createmenu: the item for the Info entry has
been changed from “/Info/” to “/Info>info%/”. The “>” symbol points to a
submenu for the item. All it does is tell the wimp where it can find the
information to create the submenu. In this case it is a block of memory that
contains the data about the info window (in other words the window handle).
You will see in the info window that the Author and Version fields don't
have the correct information in them. This is very simple to fix, and the
same technique that I am about to describe can be used for any icon that has
text, whether it is a Radio button, a default action button, or just a
comment.
First of all the Author field. This is icon number three. You can find the
icon number by loading the Templates file into !TemplEd, opening the info
window and moving the pointer over the icon. The small window at the top
left will give you the icon number. Add the following line just before
PROCwimp_poll:
PROCwimp_puticontext(info%,3,"© Joe Bloggs 1995")
Replace “Joe Bloggs” with your own name (there is a limit on the length of
the string though. This is fixed by the indirected size and the physical
size of the box. These can easily be changed using !TemplEd.
Now for the Version field. It is common practice to display the version
number and date in the form “X.XX (Dt-Mth-Yr)”, eg:
1.42 (16-Oct-99)
So all you need to do is add the following line just above PROCwimp_poll
(change the date, month and year to today):
PROCwimp_puticontext(info%,4,"1.00 (29-Mar-95)")
The parameters to the function are quite simply. From left to right they
are: the window handle, the icon number, and the text to put into the icon
(in the window).
Check the application works as it is supposed to and then try using the
same method to change the “Purpose” field to something more interesting!
4. Window & icon control
Most applications have a window that appears when the user clicks on the
iconbar icon. This is very easy to do:
Copy “Template2” from the tutorial folder into the MyApp application
directory, and rename as “Templates” thus overwriting the previous one. Add
the following line below FNwimp_loadwindow to load in a second window:
main%=FNwimp_loadwindow("<MyApp$Dir>.Templates","main",1)
Whenever a mouse button is pressed over one of MyApp's windows or icons,
the user function PROCuser_mouseclick is called, passing to it the window
handle, the icon number, and a number relating to the mouse button pressed.
These are in window%, icon% and button% respectively.
Change PROCuser_mouseclick so it looks like:
DEF PROCuser_mouseclick(window%,icon%,button%)
CASE window% OF
WHEN ibar% : PROCwimp_openwindow(main%,1,-1)
ENDCASE
ENDPROC
As you can see, when a mouse button is pressed over the iconbar icon, then
PROCwimp_openwindow is called. The first parameter is the handle of the
window to open. The second means open the window in the centre of the
screen, and the third parameter means open it on top of all other windows.
If the second parameter was 0 then the window would open where you last
left it (ie. before it was closed), or if it was being opened for the first
time then it would open as it was positioned in the templates file.
If the second parameter was -2 then the window would open behind all the
others. If is was a window handle then it would open behind that window.
Run !MyApp and check that it works, then try changing the parameters to
PROCwimp_openwindow and see what happens.
The window is divided up into three sections. I will use each section to
demonstrate one or more aspects of icon control using DrWimp. The icon
number for each icon can be found by loading the templates file into
!TemplEd as described before.
The first section contains a writable icon which can take up to 19
characters. This amount is set by using !TemplEd and changing the indirected
icon size for the writable icon.
Entering text into writable icons is fully automated by the wimp. Click in
the icon and the caret will appear so you can enter some text.
What we want to do is enter some text and when Return is pressed, or 'OK'
is clicked on, the text is read from the icon and copied into the text icon
below.
The wimp function FNwimp_geticontext reads text from icons. ie. it is the
dual of PROCwimp_puticontext. The parameters passed are the window handle
and the icon number. The function returns the text in a string. All that we
need to do then is use PROCwimp_puticontext to put the text into the other
icon.
Alter PROCuser_mouseclick so it looks like:
DEF PROCuser_mouseclick(window%,icon%,button%)
CASE window% OF
WHEN ibar% : PROCwimp_openwindow(main%,1,-1)
WHEN main% :
CASE icon% OF
WHEN 2 :
text$=FNwimp_geticontext(main%,1)
PROCwimp_puticontext(main%,11,text$)
ENDCASE
ENDCASE
ENDPROC
Re-load !MyApp and check that it works. You should be able to see from the
code above that the writable icon is number 1 and the text icon is number
11.
Now we have to get the Return key to perform the same action when it is
pressed and the caret is in the writable icon. Pressing the return key in
this situation should always act the same as clicking on the icon with the
yellow trough/border around it.
FNuser_keypress is called whenever a key is pressed. Passed to it is the
window handle and the icon number to locate the caret. Also passed to it is
the ASCII number of the key, which for Return is 13. If we use the keypress
to do something then we must return a 1. This is to stop the keypress being
passed onto other tasks.
Alter FNuser_keypress so it is like:
DEF FNuser_keypress(window%,icon%,key)
used=0
CASE window% OF
WHEN main% :
CASE icon% OF
WHEN 1 :
IF key=13 THEN
text$=FNwimp_geticontext(main%,1)
PROCwimp_puticontext(main%,11,text$)
used=1
ENDIF
ENDCASE
ENDCASE
=used
There is a lot of code there for what it actually does, but it has be
written so it is easy to add more pieces of code for lots of windows and
icons, with the minimum amount of effort. Also it allows the code to be
executed to be put onto several lines, making easier to read.
There is just one thing missing now. When you click on the 'OK' icon it
presses in briefly. When you press Return it doesn't. It is much more
reassuring for the user to see it press in, because then they know exactly
what has happened, and that they haven't just wipe half their document or
any other unsaved data away.
DrWimp provides a wimp function to invert or select an icon, and un-select
it again, so all we have to do is select the 'OK' icon, copy the text, then
un-select the 'OK' icon.
Alter the part between “IF key=13 THEN” and “ENDIF” so it looks like:
IF key=13 THEN
PROCwimp_iconselect(main%,2,1)
text$=FNwimp_geticontext(main%,1)
PROCwimp_puticontext(main%,11,text$)
used=1
PROCwimp_iconselect(main%,2,0)
ENDIF
Re-run !MyApp and check it works. PROCwimp_iconselect has three
parameters. The first is the window handle and the second is the icon
number. In this case it is 2 for the 'OK' icon. The last parameter controls
the inversion/selection. If it is a 1 then the icon is selected, a 0 makes
it unselected. If you removed the second PROCwimp_iconselect then the 'OK'
button would stay pressed in. Try it and see!
The second section contains two radio buttons and an button labelled
'Swap'. Both the radio buttons have the same ESG group (out of an ESG group,
only one radio button can be selected at once(see !TemplEd)), so clicking on
one de-selects the other. What I want to do is get it so when the user
clicks on 'Swap' the selected and de-selected radio icons swap over, as if
you had clicked on the de-selected one. The button has an icon number of 6.
If you write an application with radio buttons, you have to keep track of
which ones are selected. For MyApp we will use choice% which will be either
1 or 2 depending on which one is selected. When you first load MyApp, Choice
1 is selected (you have to do this when editing the template), so we will
set choice% to 1 at the start. When 'Swap' is clicked on, we look at choice%
to decide which to select and which to de-select.
Just before PROCwimp_poll, add the following line:
choice%=1
After PROCwimp_puticontext(main%,11,text$) in PROCuser_mouseclick, before
the ENDCASE, add the following:
WHEN 6 :
IF choice%=1 THEN
PROCwimp_iconselect(main%,4,0)
PROCwimp_iconselect(main%,5,1)
ENDIF
IF choice%=2 THEN
PROCwimp_iconselect(main%,4,1)
PROCwimp_iconselect(main%,5,0)
ENDIF
choice%=ABS(1-(choice%-2))
WHEN 4 :
choice%=1
WHEN 5 :
choice%=2
It is mostly self explanatory. “choice%=ABS(1-(choice%-2))” toggles
choice% between 1 and 2 to keep track of which one is selected.
There isn't much point in doing this as it is much easier for the user to
simply click on the radio icons instead, but it is a good demonstration in
selecting and de-selecting radio icons.
There is a small problem with radio buttons. Try pressing Adjust over a
selected one. You will find that it becomes un-selected. Having none of the
radio buttons selected may be an undesirable situation. It is quite simple
to solve this.
If you have a look at PROCuser_mouseclick you will see that the third
parameter passed to is is called button%. Basically, if button%=4 then
Select was pressed. If button%=1 then Adjust was pressed. There are also
numbers for combinations of mouse buttons, but we need not concern ourselves
with that at the moment.
Alter the WHEN 4 and WHEN 5 parts so they look like:
WHEN 4 :
IF button%=1 PROCwimp_iconselect(main%,4,1)
choice%=1
WHEN 5 :
IF button%=1 PROCwimp_iconselect(main%,5,1)
choice%=2
Re-load !MyApp and make sure that you always have to have a radio icon
selected.
The last section has an option icon and two buttons. What we want to do
with this section is control the option icon using the buttons, in much the
same way as for the radio icons. There is a difference though, in that at
any one time, one of the buttons will have to be disabled; there is not much
point clicking on 'On' if it is already turned on.
Just before PROCwimp_poll, add the following:
option%=0
PROCwimp_icondisable(main%,10)
option% records the state of the option icon, so if the application ever
needed to act upon its state, it could just look at option%. The function
disables (greys out) the 'Off' button (icon number 10). Its duel
PROCwimp_iconenable enables icons and has the same parameters.
In PROCuser_mouseclick, modify it so it is like:
WHEN 5 :
IF button%=1 PROCwimp_iconselect(main%,5,1)
choice%=2
WHEN 9 :
PROCwimp_icondisable(main%,9)
PROCwimp_iconenable(main%,10)
PROCwimp_iconselect(main%,8,1)
option%=1
WHEN 10 :
PROCwimp_iconenable(main%,9)
PROCwimp_icondisable(main%,10)
PROCwimp_iconselect(main%,8,0)
option%=0
WHEN 8 :
IF option%=0 THEN
PROCwimp_iconenable(main%,10)
PROCwimp_icondisable(main%,9)
ENDIF
IF option%=1 THEN
PROCwimp_icondisable(main%,10)
PROCwimp_iconenable(main%,9)
ENDIF
option%=ABS(1-option%)
You should be able to see how it works, and know exactly what will happen
when you click on the icons. Run it and check!
Using FNwimp_icondisable and FNwimp_iconenable you can grey out and
un-grey out any icon you wish. If the user clicks on a disabled icon, then
the mouse click is ignored, and PROCuser_mouseclick is not called.
You must have noticed that as soon as you have some un-saved data in a
program, the title of the window has an asterisk added to end. Using DrWimp
this is quite easy to achieve, once you know that you have some unsaved
data...
For MyApp we will assume that we have some unsaved data when 'OK' or
Return is pressed. FNwimp_getwindowtitle returns a sting containing the
name. PROCwimp_putwindowtitle changes the title to the supplied string. All
we have to do therefore is read the title, add “ *” to the end and put it
back.
Change the WHEN 2 : section in PROCuser_mouseclick to:
WHEN 2 :
text$=FNwimp_geticontext(main%,1)
PROCwimp_puticontext(main%,11,text$)
r=1
title$=FNwimp_getwindowtitle(main%)
IF RIGHT$(title$,2)=" *" r=0
IF r=1 PROCwimp_putwindowtitle(main%,title$+" *")
The title is put into title$, then the end is checked to see if “ *” has
already been added (we don't want to add “ *” each time 'OK' is pressed!).
If it hasn't then the asterisk is added. You should now be able to alter a
part of FNuser_keypress so the title changes when Return is pressed as well.
Note: In order to change the window title it must be indirected. This is
set up using a template editor like !TemplEd. The indirected size only needs
to be 1.
Just a quick thing for you to try while I am dealing with windows: Quite a
few programs have a window that appears in the centre of the screen when it
loads. It stays there for a bit before closing again. Using banners is a
good way of announcing your program or reminding people to register it.
DrWimp has a function that handles banners for you. While the banner is on
the screen, you can still use the desktop and your application.
This is how you use it: Just before PROCwimp_poll enter the following
line:
PROCwimp_banner(info%,3)
When you load MyApp, the info window will appear for three seconds in the
middle of the screen. The info window isn't really suitable, so I'll leave
it to you to design a window, load it in, and put things like version number
and date, etc in using PROCwimp_puticontext.
5. Advanced menus
So far we have only got a simple two item menu with an info window
(windows off menus are called dialogue boxes). There is a lot more you can
do with menus. This part looks at submenus, ticks, greying out, dotted
lines, changing items' text, and writable menu items.
First of all, lets create a menu for our main window. Below the only
FNwimp_createmenu we have so far, add the following lines:
menu$="MyApp/Info>info%/Item 2/Item 3/Item 4/Save"
mainmenu%=FNWimp_createmenu(menu$,0)
And attach the menu to the main window by altering FNuser_menu so it looks
like:
DEF FNuser_menu(window%,icon%)
CASE window% OF
WHEN ibar% : =barmenu%
WHEN main% : =mainmenu%
ENDCASE
=0
When you press Menu anywhere over the main window, you should get a menu
with 5 items. The first should have a submenu leading to the info window.
Now create another menu by adding the following line ABOVE the menu$=...
you have just entered:
i3menu%=FNwimp_createmenu("Item 3/Help/Tick me!",0)
Now you can see from the title of this menu that it is obviously a submenu
for Item 3 on our main menu. Here is how to add it: instead of entering a
window handle, you simply enter a menu handle. For example, change menu$ to:
menu$="MyApp/Info>info%/Item 2/Item 3>i3menu%/Item 4/Save"
Run MyApp and take a look at the menu. And that is all there is to it! Here
is another example of how easy it is to use:
Before the i3menu%=... line add the following:
tickmenu%=FNwimp_createmenu("Tick me!/Bored/Dull/Waffle",0)
And change the i3menu%=... line to read:
i3menu%=FNwimp_createmenu("Item3/Help/Tick me!>tickmenu%",0)
So you can see that it is quite painless to build up very complex menu
structures.
As you have seen before, if you choose a menu item then
PROCuser_menuselection is called. If you choose the first item from the menu
tickmenu%, then menu%=tickmenu% and item%=1.
When you create a menu it has no ticks by the side of any items, no dotted
lines separating items, and none of the items greyed out. Any that need to
be done when the application loads, have to be set up after the menu has
been created.
PROCwimp_menutick toggles a tick next to the menu item specified. Add the
following line to the end of PROCuser_menuselection and try it out:
IF menu%=tickmenu% AND item%=1 PROCwimp_menutick(menu%,item%)
PROCwimp_menudisable and PROCwimp_menuenable surprisingly enough enable
and disable menu items!
At the end of PROCuser_menuselection, add the following lines and try it
out:
IF menu%=mainmenu% AND item%=2 PROCwimp_menudisable(menu%,3)
IF menu%=mainmenu% AND item%=4 PROCwimp_menuenable(menu%,3)
PROCwimp_menudottedline puts a dotted line on the menu below the item
specified. Try it out by adding the following after i3menu% is created:
PROCwimp_menudottedline(i3menu%,1)
There are a few more functions related to menus:
PROCwimp_menupopup(menu%,bar%,x%,y%)
This brings up the menu menu% at the co-ordinates x%,y% if bar%=0. If
bar%=1 then the menu is positioned for the iconbar icon. This can be useful
for the menu icons (the icons that depict a menu and are usually for to the
right of writable icons, offering the user a choice of strings to enter into
the writable icon). You detect a click with Select or Adjust on the icon,
read the mouse co-ordinates with MOUSE X,Y,B and bring up the menu. You will
need to add some offsets to x% and y% so then menu appears to the side.
The text of a menu item can be read by using FNwimp_getmenutext, passing
the menu handle and the item number. The duel of this is FNwimp_putmenutext.
This allows you to change the text of an item. The text can be up to 78
characters wide, but this would cross the screen, so if you don't know the
length of the string then truncate it.
Delete the PROCwimp_menudisable lines, and put the following line in the
same place:
IF menu%=mainmenu% AND item%=2 THEN
PROCwimp_putmenutext(mainmenu%,3,"ABCDEFGHIJKLMNOPQRS")
ENDIF
Try choosing the second menu item with Adjust. The menu will automatically
adjust its width to accommodate the longest line.
The last major menu function turns an item into a writable one. A block of
memory is reserved to put the text into automatically. After the main menu
has been defined, add the following line:
PROCwimp_menuwrite(mainmenu%,4,20)
The first parameter is the menu handle, the second is the item number. It
doesn't matter if some text is already there. The third parameter is the
maximum length allowed to be entered.
The final handful of menu functions don't really need much description.
For more details see !Fnc'n'Prc or section 3 in this manual.
FNwimp_menusize(menu%) - Returns the number of items in a menu.
PROCwimp_menuclose - Closes any open menu.
FNwimp_getmenutitle(menu%) - Returns the title of the menu.
PROCwimp_putmenutitle(menu%,title$) - Changes the menu title to title$.
6. Panes
Using DrWimp, it is very easy to attach a pane to a window. From the
tutorials folder, copy “Template3” into the MyApp directory and rename as
“Templates”.
Where the other windows are loaded in, load in the window “pane”:
pane%=FNwimp_loadwindow("<MyApp$Dir>.Templates","pane",1)
The pane wants to be attached to the main window. When the main window is
dragged about, it is actually being continually re-opened all the time. This
means that PROCuser_openwindow is also being called continually. All we have
to do is open the pane next to the main window. In PROCuser_openwindow, add
the following lines:
IF window%=main% THEN
xoff%=x%-FNwimp_getwindowsize(pane%,0)
PROCwimp_openwindowat(pane%,xoff%,y%,stack%)
ENDIF
The pane also needs to be closed when the main window is, so in
PROCuser_closewindow add the following line:
IF window%=main% PROCwimp_closewindow(pane%)
There is one last thing to do; add the following line to PROCuser_pane:
IF window%=main% =pane%
Re-load MyApp and check that it is working. And that is all there is to
it! Just a quick explanation of a few things:
PROCwimp_openwindowat opens the specified window so the top left corner is
at the co-ordinates x%,y%. If you want the window to open at the top, then
stack%=-1, or at the bottom, then stack%=-2. If you want the window to open
behind a certain one, then stack%=the handle of the window to open behind.
If you want a window to open with another one but not follow it around,
then in PROCuser_openwindow, use PROCwimp_openwindow. If you set the second
parameter to 1 then it will continually re-centre, so it is best to set it
to 0. Also, just pass stack% straight through.
7. Save windows
Adding and controlling save windows is very easy. Copy the file
“Template3” from the tutorial folder into the MyApp directory and rename to
“Templates”. Now load in the save window, and modify the main menu to gain
access to it:
save%=FNwimp_loadwindow("<MyApp$Dir>.Templates","save",1)
menu$="MyApp/Info>info%/Item 2/Item 3>i3menu%/Item 4/Save>save%"
If you run MyApp now, the save window will behave like any other window
that hasn't got any code to tell it what to do. Everything starts to work
when you add the following line to PROCuser_savefiletype:
IF window%=save% ="FFF"
DrWimp now knows that save% is a save window and that it saves text files.
Don't try to save just yet as you will crash the machine (there is no data
to save).
When the icon is dragged to a destination, PROCuser_savedata is called.
This is where you do the actual saving. path$ is the full pathname of the
file that you are saving to and window% is the handle of the window that the
icon was dragged from.
Don't always assume that the pathname in path$ will be something like
“IDEFS::Andy.$.TextFile”, It could be a system variable that the wimp
expands to a full pathname later on.
So, enter the following into PROCuser_savedata:
IF window%=save% THEN
file%=OPENOUT(path$)
BPUT#file%,"This is a text file,"
BPUT#file%,"from MyApp you know!"
CLOSE#file%
ENDIF
Note: the filetyping is taken care of by DrWimp.
You can now drag the icon to the filer or other applications. The error
messages “You must drag the icon to a filer window to save...” are taken
care of by DrWimp.
It is very easy to add lots more save windows. Simply load them in, add
them to a menu (or provide some way the user can get to them), return their
filetype from PROCuser_savefiletype, and do the saving in PROCuser_savedata!
8. Errors
If you get an error or you are trying to debug a program, error windows
can be very useful. They can tell you information while the program is
running.
Error windows can be altered quite a bit, so there are several parameters
needed to bring one up. There are two wimp functions for error windows:
PROCwimp_error(title$,error$,button%,prefix%)
This one is the most common. title$ is the title of the window. This is
usually the application name. error$ is the error message itself. The text
is wordwrapped automatically. This type of error window can display either
an 'OK' button, or a 'CANCEL' button. This is controlled by button%. If it
is 1 then you get an 'OK' button. If it is a 2 then you get a 'CANCEL'
button. prefix% allows you to tailor the title to suit the error message. If
prefix% is 0 then the title is title$. If it is 1 then the title is prefixed
with “Error from ”. And if it is 2 then the title is prefixed by “Message
from ”.
FNwimp_errorchoice(title$,error$,prefix%)
This is the other function. The parameters act in exactly the same way as
for PROCwimp_error. This function displays an error window with an 'OK'
button and a 'CANCEL' button. If 'OK' is clicked on then the function
returns a TRUE (-1). If 'CANCEL' is clicked on then it returns a FALSE (0).
9. Message files
It is getting increasingly common for applications to have Message files.
These files have most of the text for the application in, so it can be
easily translated by someone who doesn't need to know anything about
programming.
Copy the “Messages” file from the tutorial folder into the MyApp
directory. Load it into !Edit and have a look at it.
Comments start with a hash “#”. Lines which have text on to be used in the
application start with what is called a token. This is just a few letters
that the line can be identified by. The token and the text are separated by
a colon. For example:
LIB:Doctor Wimp
If we wanted to use the line of text “Doctor Wimp” then we would reference
it by using the token “LIB”.
Lines of text can also have strings inserted into them when they are read
into the application. For example:
VER:1.00 (%0-%1-95)
When you read in this line, you supply two strings. These could be “29“
and “Mar” for example. When the line is read in it ends up as “1.00
(29-Mar-95)”.
PROCwimp_initmessages(pathname$) sets up blocks of memory ready to read in
the lines of text. pathname$ is the full pathname to the Messages file.
Somewhere before the PROCwimp_poll, call the function for the Messages
file inside the MyApp directory.
To read a line without substituting any strings you can use
FNwimp_messlook0(token$). This returns the line of text.
To read a line and replace “%0” with a string you can use
FNwimp_messlook1(token$,a$), where “%0” in the messages file is replaced
with a$.
To read and substitute two strings you can use
FNwimp_messlook2(token$,a$,b$).
Add the following lines after PROCwimp_initmessages:
lib$=FNwimp_messlook0("LIB")
PROCwimp_error(appname$,"LIB="+lib$,1,2)
os$=FNwimp_messlook1("OS","3.11")
PROCwimp_error(appname$,"OS="+os$,1,2)
ver$=FNwimp_messlook2("VER","29","Mar")
PROCwimp_error(appname$,"VER="+ver$,1,2)
10. Loading data
This is very simple to do. Whenever a file (or directory or application)
is dropped onto a window belonging to your application, then
PROCuser_loaddata is called. This is where you actually load it in to a
block of memory or an array.
path$ is the full pathname of the file to load from. Don't always assume
that it is something like : “IDEFS::Andy.$.TextFile”.
window% and icon% are the window handle and the icon number that the file
was dropped on to. Most of the time you would only need to check if it was a
window or the iconbar icon, but it can be used for drop-boxes. These are
boxes with text in saying something like: “Drop file to load here”.
ftype$ is the filetype of the file to load. Eg: for text files it is
“FFF”. Files have a three character hexadecimal filetype, but directories
are &1000, and applications are &2000.
If you decide to load in the file after looking at all the parameters,
then you must load it in and return a 1. This is so DrWimp can send a
message to the filer or any other application that the file came from,
saying that it has been loaded.
Here is an example piece of code for loading in a text file in
PROCuser_loaddata
DEF PROCuser_loaddata(path$,window%,icon%,ftype$)
used=0
IF ftype$="FFF" THEN
file%=OPENIN(path$)
L=1
REPEAT
A$(L)=GET$#file%
L+=1
UNTIL EOF#file%
CLOSE#file%
lines%=L-1
used=1
ENDIF
=used
What it does is load in a text file into an array called A$ (which you
will need to create before PROCwimp_poll). At the end, lines%=the number of
lines read in.
Try altering MyApp so it can load in a text file, then using the save box,
allow the user to save the text file to somewhere else. All you have to do
is alter the save code so it saves the array.
11. Interactive help
DrWimp supports interactive help applications like Acorn's !Help. All you
have to do is return the help string for a given window handle and icon
number. FNuser_help is where you do this.
Enter the following line into FNuser_help, reload MyApp, load !Help, and
move the pointer over the info window and the iconbar icon:
DEF FNuser_help(window%,icon%)
h$=""
CASE window% OF
WHEN info% :
CASE icon% OF
WHEN 1 : h$="This application is called 'MyApp' "
WHEN 2 : h$="It tests the DrWimp library"
WHEN 3 : h$="MyApp was written by Joe Bloggs"
WHEN 4 : h$="This is the version number and date"
OTHERWISE : h$="This is the MyApp info window."
ENDCASE
WHEN ibar% : h$="This is the MyApp icon."
ENDCASE
=h$
12. Sprite areas & Mouse pointers
Whenever the pointer moves in and out of one of MyApp's windows, the
functions PROCuser_enteringwindow and PROCuser_leavingwindow are called.
This makes it very easy to change the mouse pointer when it is over one of
your windows. There is a function to change the pointer for you, but first I
will look at sprite areas as it is closely related:
All the sprites in the windows so far are from the wimp sprite pool. An
application can however, create it's own private sprite area that is stored
in the wimpslot, or memory used by the application. This has the advantage
that when the application quits, all the memory is regained.
PROCwimp_loadsprites does all the work for you. Passed to it is a pathname
to a sprite file, and the area is set up and the file is loaded in. The
sprites in that area can then be used in windows (see PROCwimp_loadwindow
for parameters), or for pointers.
PROCwimp_pointer controls the mouse pointer. Pointer number two is always
used for the second one.
Copy the file “Sprites” from the tutorials folder into the MyApp
directory. Enter the following line after FNwimp_initialise:
PROCwimp_loadsprites("<MyApp$Dir>.Sprites")
In PROCuser_enteringwindow, add the following lines:
IF window%=main% THEN
PROCwimp_pointer(1,1,"ptr_hand")
ENDIF
And in PROCuser_leavingwindow, add the following:
IF window%=main% THEN
PROCwimp_pointer(0,0,"")
ENDIF
Run MyApp and you should find that when you move the pointer over the main
window, it turns into a hand. The first parameter tells DrWimp whether to
use the default pointer, or a user defined one. The second parameter should
be 0 for the wimp sprite pool, and 1 for a user sprite area. The default
pointer can be found in the RMA, so it should be a 0 to use it. The last
parameter is the name of the sprite to use for the user defined pointer. If
you are using the default pointer, then you don't need to put anything into
the string.
It is a good idea to change the pointer into one looking like a caret when
it is over a writable icon. For this, you need to have the pointer in the
wimp sprite area (*IconSprites a file with “ptr_write” in), and in the
validation field of the icon enter:
R7;Pptr_write
You can do similar things with other icons like the menu ones. !Impression
is a good example.
13. Redraws, leafnames & versions
If you have some user graphics in a window, that can't be redrawn by the
wimp, then it will ask you to do the redraw. For example, you could be using
the CIRCLE command to draw a circle in a window.
When a redraw is required, PROCuser_redraw is called. The handle of the
window is passed, and the position of the rectangle. The rectangle is like a
graphics window, so you can redraw all the window contents if you like
(although that is a bit slow). Anything outside is clipped.
Sometimes it can be useful to get a leafname from a pathname.
pathname = “IDEFS::Andy.$.Progs.Project1.!Wow.Sprites”
leafname = “Sprites”
DrWimp can do this for you with FNwimp_getleafname(pathname$). It returns
the leafname.
It is very likely that the DrWimp library will have some modifications or
improvements made to it at some point. I very much hope that they will not
affect the way any existing wimp or user functions are called, but just in
case, you can call a function to read the version number of the library. So
if someone decides to replace the library in your application with a newer
version, then your program can read the version number and refuse to work
with it.
FNwimp_libversion returns the version number x 100. So if it is version
1.43 then it will return 143.
14. Changing sprites
If you have an icon which is a sprite (like the text file icon in the save
window) then you can change it to another sprite by using
PROCwimp_puticontext. This will only work however, if the icon is
indirected. That is set up using a template editor.
For example: insert the following line just before PROCwimp_poll:
PROCwimp_puticontext(save%,0,"file_ffd")
Re-load MyApp and the file icon in the save window will now be a Data one.
15. Large menus & rebuilds
Yes, this section is again concerned with menus. In particualar: how to
create very large menus, how to completely change a menu (ie. a re-build),
and add and remove items.
Menus can be created so that they are dynamic. In other words, then can
grow and shrink in accordance with what your application wants.
You should recall from the introduction section that when a menu is
created a block of memory of a fixed size is reserved to put the data that
the wimp needs in. So for example:
menu%=FNwimp_createmenu("MyApp/Info/Quit",0)
will reserve a block of memory just big enough to hold the menu with only
the two items specified.
But what happens if you want to add another item to the menu. This will
create three items, so all the data for one item will be pushed into the
next part of the memory. This could be holding the contents of variables
that you are using, thus corrupting them, or even more likely you will crash
the application, because you are trying to write to some memory addresses
that don't actually exist (address exception errors are the result of this).
What is needed is a way of making sure the block of memory is big enough.
This is where the last parameter to FNwimp_createmenu comes in:
If it is less than or equal to the number of items specified in the
string, then the block of memory will be just big enough to hold the items
given. If it is bigger, then it is the maximum number of items that can be
on that menu.
So if you used:
menu%=FNwimp_createmenu("MyApp/Info/Quit",20)
then you would create a menu the same as before, but you can have up to 20
items added to it later on.
PROCwimp_putmenuitem and PROCwimp_removemenuitem add and remove items from
menus. Note: no check is made to ensure that the menu is not bigger than the
block of memory; you will have to make sure that the block is big enough.
PROCwimp_putmenuitem(menu%,item%,item$)
PROCwimp_removemenuitem(menu%,item%)
The parameters are mainly self explanatory. If item% in
PROCwimp_putmenuitem is greater that the total number of items+1 then it
will just be added onto the end.
As items are added or removed, items below are shuffled down and up
respectively.
If you wanted to re-build or re-create a menu from scratch again, but
still have the same handle as the last one, then you could called
FNwimp_createmenu, which would get another chunk of memory and put the data
needed into it. This means that the block of memory with the original menu
in is still occupied and therefore wasted. If you do this repeatedly then
more and more memory is taken up until your application runs out, crashing
it.
A much better way is to use the wimp function PROCwimp_recreatemenu, which
updates the data in the block of memory containing the old menu.
PROCwimp_recreatemenu(menu%,menu$)
menu% is the handle of the menu to re-create. menu$ is a string to build
the menu from, and is in the usual form, eg:
"MyApp/Info>info%/Quit"
The number of items in the new menu shouldn't be greater than the specified
maximum value when FNwimp_createmenu was called. Eg:
menu%=FNwimp_createmenu("MyApp/Quit",1)
PROCwimp_recreatemenu(menu%,"MyApp/Info/Quit")
Would probably cause the application to crash, because not enough memory has
been allocated for all the items in the larger re-created menu.
When a menu is re-created, all the item attributes like dotted lines,
greying out, and ticks are removed. If you want to change one or two menu
items to reflect something in your application like: “Save selection” or
“Save” depending in this case on whether anything was selected or not, then
use PROCwimp_putmenutext instead as the attributes are retained.
Now we come to the last part in this section: FNwimp_createmenu and
PROCwimp_recreatemenu have a major limitation: very large menus cannot be
built.
If you think about it, the maximum length of a line allowed in BASIC is
something like 255 characters. Now, when you create a menu some of these are
used up with the function name and other parameters, leaving maybe 210
characters left for the string that the menu is created from. So what
happens if you want to create a font menu where the number of fonts could be
in the hundreds?
DrWimp provides a very easy solution to this which requires modified
versions of FNwimp_createmenu and PROCwimp_recreatemenu.
The solution is to put all the menu items into an array, then build the
menu from the array. This lends itself very well to reading in items like
font names, or data from support files for your application.
First of all you need to decide the maximum number of items in the menu.
If you are creating a font menu, then you can use the SWI “Font_ListFonts”
to find out the number of fonts. Anyway, add one onto the total size, and
DIM an array.
The first element of an array (number 0) is the menu title. The last item
must be “END”, so DrWimp knows how much of the array to use. Note: “END”
will not appear as a menu item; the element before it will be the last one.
Here is some example code:
DIM menu$(20)
menu$(0)="MyApp"
menu$(1)="Info>info%"
menu$(2)="Quit"
menu$(3)="END"
barmenu%=FNwimp_createmenuarray(menu$(),20)
As you can see, elements can contain the submenu pointers in the usual
way. FNwimp_createmenuarray is passed the name of the array (with empty
brackets) and the maximum number of items. The last parameter is exactly the
same as for FNwimp_createmenu, so it could just as easily be “0”, which
means that more items can't safely be added, but it makes more sense to set
it as the size of the array.
Menus can be re-built using arrays as well. Instead of using
PROCwimp_recreatemenu, use:
PROCwimp_recreatemenuarray(menu%,array$())
Menus created with a string can be recreated with an array, and
vice-versa. Note: menus created with arrays can be manipulated using the
same functions, such as PROCwimp_putmenuitem, PROCwimp_menuwrite, etc. The
only difference is the way that the data to build the menu initially is
stored (string or array).
16. Multitasking operations
This section is about multitasking raytracing, calculating numbers,
loading data, file finding, etc. No, I am not going to show you how to write
a raytracer, etc. but show you how to make operations like these multitask
easily.
At the moment, if you wanted to do a multitasking operation, then you
would have to set NULL to TRUE so PROCuser_null is called continuously, and
every time it is called, remember where you was up to and do a small bit.
This can make very tangled code. The difficulty lies in storing where you
got up to, and this can require a multitude of variables for just one
operation.
A much easier method is to use PROCwimp_singlepoll. When called, it goes
through the polling loop once. Your operation will already be in some sort
of loop, so all you have to do is call PROCwimp_singlepoll inside it! This
very simple technique makes powerful multitasking operations very easy to
achieve.
Change PROCwimp_menuselection so it has lines like:
CASE menu% OF
WHEN barmenu% :
CASE item% OF
WHEN 1 : PROCchangeauthor
ENDCASE
ENDCASE
And add the following function at the end of !RunImage:
DEF PROCchangeauthor
FOR L=1 TO 200
PROCwimp_singlepoll
a$=""
FOR M=1 TO 6
a$+=CHR$(RND(26)+64)
NEXT M
PROCwimp_puticontext(info%,3,a$)
NEXT L
ENDPROC
Now run !MyApp and choose the first item on the iconbar menu. If you now
look at the info window, the author field should be constantly changing with
random letters. You can still use the desktop, although the loop is simple
so you can't quit !MyApp until it has finished. This can be fixed by using a
REPEAT UNTIL loop and checking for finished%=TRUE.
Note: PROCwimp_singlepoll acts just like PROCwimp_poll, except it doesn't
quit for you. If one of your icons is clicked on, then PROCwimp_mouseclick
is still called, and if your application received messages, then they are
acted on, and so on.
17. “Grubby” tasks
You will sometimes see tasks that load onto the iconbar, but when the icon
is clicked on they leave the desktop and monotask. When the user has
finished, they are returned to the desktop, with the application still
loaded onto the iconbar. Acorn calls these tasks “Grubby tasks”, and they
are very simple to implement.
Alter PROCwimp_mouseclick so it has a line like:
CASE window% OF
WHEN bar% :
PROCwimp_starttask("BASIC -quit <MyApp$Dir>.Mono")
ENDCASE
Create a BASIC file called “Mono” inside the !MyApp directory containing
the following:
MODE12
PRINT "This is monotasking!"
A$=GET$
*DESKTOP
END
Re-load !MyApp and click on the iconbar icon. Press a key to return to the
desktop. Note: change the mode number to one suitable for your monitor.
You will probably want to mangle up the second BASIC file as well as
!RunImage with DrWimp to give you more security. This is possible if you
don't use DrWimp in the second BASIC file. Mangle it up with !MakeApp2 and
!Crunch in the usual way, and then change the PROCwimp_starttask to
something like:
PROCwimp_starttask("Run <MyApp$Dir>.Mono")
18. Bars
When you format a disc a bar increases in size to show the amount of the
disc that has been formatted so far. When you look at the free space on a
floppy or hard drive you have several bars to show you how much space has
been used up, is free, and there is in total. When you open the task display
you are shown lots of bars that depict the amount of memory something is
using up.
Using DrWimp it is simple to control bars like those yourself. They can
make information look much more attractive than numbers.
DrWimp allows the length of the bars to be changed. This means that they
can be changed all the time, or only just before a window containing them is
opened. What you can't do at the moment unfortunately is drag them to
different sizes.
Make a fresh copy of !MyApp. From the Tutorial folder, drag the
“Template5” file into the !MyApp directory, and rename it as “Templates”.
Add the following lines at the start of !RunImage, just above PROCwimp_poll:
main%=FNwimp_loadwindow("<MyApp$Dir>.Templates","main",1)
bar%=FNwimp_iconbar("!MyApp","",1)
barmenu%=FNwimp_createmenu("MyApp/Quit",0)
and in PROCuser_mouseclick:
IF window%=bar% PROCwimp_openwindow(main%,1,-1)
and in FNuser_menu:
IF window%=bar% =barmenu%
and in PROCuser_menuselection:
IF menu%=barmenu% AND item%=1 finished%=TRUE
If you now double-click on !MyApp you should get an icon on the iconbar with
a menu with a 'Quit' item. Clicking on the icon should produce a small
window with a red bar in it. What we are going to do is set the bar to a
random length when it is clicked on.
First we need to know what the maximum length is, so load the templates
into !TemplEd by dropping the file onto !TemplEd's iconbar icon.
Open the main window by double-clicking on it in the window at the top
left. Expand the icon info window at the top right to full size and move the
pointer over the bar.
The icon info window gives the dimensions of 340x36, so the max length is
340. Of course we could extend the icon to whatever size we want using
!TemplEd, and then using that length.
Take a look at all the details of the bar icon by double-clicking on it.
This is how you should set up any icons you want to use as bars. Obviously
you can change the colour and turn the border on, etc.
Returning to !RunImage, add the following line to PROCuser_mouseclick:
IF window%=main% PROCchangelength
Now add the following function to the end of !RunImage:
DEF PROCchangelength
len=RND(340)
PROCwimp_bar(main%,1,len)
ENDPROC
Re-load !MyApp, and click on the bar or frame icon behind it.
It is quite easy to specify the length as a percentage. Alter
PROCchangelength to:
DEF PROCchangelength
len=RND(100)
len=(340/100)*len
PROCwimp_bar(main%,1,len)
ENDPROC
As you can see, len is a percentage chosen at random.
And just to finish off, alter PROCchangelength to:
DEF PROCchangelength
pcent=0
REPEAT
nlen=(340/100)*pcent
PROCwimp_bar(main%,1,nlen)
PROCwimp_singlepoll
pcent+=2
UNTIL pcent>100
ENDPROC
You should be able to see that it is now the basis for a multi-tasking
operation with the percentage done depicted by the bar. Put the operation
inside the loop, and each time round the loop calculate the percentage done
instead of incrementing it as I have done.
You can change the bar to look like however you want it, but I would
advise against adding any text, sprites, or indirected text.
One thing you might like to do is add a border around the bar by clicking
on the “Border” icon in the relevent !TemplEd window. However, if the bar is
going to be changing in size rapidly then the part of the border at the
right edge will flicker a lot as that part of the screen is constantly
redrawn.
Finally, take a look at !Bar in the Examples folder.
*****************************************************************************
Section 3 - Functions
*****************************************************************************
1. Windows
PROCwimp_openwindow(window%,centre%,stack%)
Opens a window on the screen.
window% = handle of window to open.
If centre% = 0 opens window where it was last left on the screen, or if it
hasn’t been opened before, then where it is positioned in the template file.
If centre% = 1 opens the window centred on the screen (mode independent).
stack% = window handle to open behind, or -1 for top of window stack, or -2
for bottom.
PROCwimp_openwindowat(window%,x%,y%,stack%)
Opens a window on the screen so the top left of the window is at
co-ordinates x%,y%. window% = handle of window to open. stack% = window
handle to open behind, or -1 for top of window stack, or -2 for bottom.
Useful for opening panes exactly where you want them.
PROCwimp_closewindow(window%)
Closes a window (removes it from the screen). window% = handle of window to
close.
FNwimp_loadwindow(pathname$,window$,sprite%)
Loads in a window from a templates file and returns a handle for the window.
pathname$ = full pathname to templates file. window$ = name of window in
templates file. sprite% = sprite flag. If = 0 then use sprites from user
sprite area for window. If = 1 then use sprites from the wimp sprite pool
(RMA).
PROCwimp_putwindowtitle(window%,title$)
Changes the window title to title$ window% = handle of window.
FNwimp_getwindowtitle(window%)
Returns a string containing the window title. window% = handle of window.
PROCwimp_banner(window%,delay%)
Opens window in the centre of the screen for specified delay before closing
it. window% = handle of window to open. delay% = number of seconds to keep
window on screen.
FNwimp_getwindowsize(window%,side%)
Returns the dimension required. If side% = 0 returns width. If side% = 1
returns height. Useful for positioning panes along side “parent” windows.
2. Menus
PROCwimp_menupopup(menu%,bar%,x%,y%)
Brings up the menu whose handle is menu% at the co-ordinates x%,y%. If
bar%=1 then the menu will be positioned as for an iconbar menu, otherwise
use 0. Useful for go-right or menu icons. Read the mouse co-ordinates, and
apply offsets to get x% and y%.
FNwimp_createmenu(menu$,size%)
Creates a menu structure from the string menu$. The menu handle is returned.
For more information on menu$ see the tutorial on menus. size% = maximum
number of items allowed. If size% is less than the number of items in menu$,
then it is increased to the number of items.
FNwimp_menusize(menu%)
Returns the number of entries in the menu. menu% = handle of menu.
PROCwimp_menutick(menu%,item%)
If the item doesn’t have a tick next to it then this function places one. If
the item does have a tick then it is removed. menu% = handle of menu. item%
= item number (top item is 1).
PROCwimp_menudisable(menu%,item%)
Greys out the menu item so it is un-selectable. menu% = handle of menu.
item% = item number (top item is 1).
PROCwimp_menuenable(menu%,item%)
Un-greys out the menu item so it is selectable. menu% = handle of menu.
item% = item number (top item is 1).
PROCwimp_menudottedline(menu%,item%)
Adds a dotted line to the menu below the item. menu% = handle of menu. item%
= number of item (top item is 1).
PROCwimp_menuclose
Closes the currently active menu.
FNwimp_getmenutitle(menu%)
Returns a string containing the title of the menu. menu% = handle of menu.
PROCwimp_putmenutitle(menu%,title$)
Changes the title of the menu. If the title>11 characters then it is
truncated. menu% = handle of menu. title$ = new title.
PROCwimp_putmenutext(menu%,item%,text$)
Replaces menu items text with text$. menu% = handle of menu. item% = number
of item (Top item is 1). Can be up to 78 characters long. Automatically
calculates the new width of the menu.
PROCwimp_menuwrite(menu%,item%,length%)
Makes the menu item writable. menu% = handle of menu. item% = number of item
(top item is 1). length% = maximum length of text allowed to be entered.
FNwimp_getmenutext(menu%,item%)
Returns a string containing the text of the menu item. menu% = handle of
menu. item% = number of item (top item is 1).
PROCwimp_putmenuitem(menu%,item%,item$)
If the menu is dynamic then item$ will be put into menu item item%. Any
items below will be shuffled down. If item% is bigger than the current
number of items+1, then it will be added to the bottom. menu% = handle of
menu.
PROCwimp_removemenuitem(menu%,item%)
Removes the item from the menu. Any items below are shuffled up. If there is
only one item on the menu, then it cannot be removed. menu% = handle of
menu. item% = number of item to remove.
PROCwimp_recreatemenu(menu%,menu$)
Rebuilds the menu using the string menu$. More items can be included than
the first time as long as you don’t go over the pre-defined limit. menu% =
handle of menu to rebuild.
FNwimp_createmenuarray(array$(),size%)
Creates a menu from the array supplied. Each item of the menu is in a
seperate element of the array. eg: array$(3)=‘Info>info%’. Note submenus are
included in the usual way. the first element is the menu title, and the last
must be ‘END’. array$() = array to get items from. size% = maximum number of
elements to allocate room for (doesn’t have to be the current number).
Returns a handle to the menu.
PROCwimp_recreatemenuarray(menu%,array$())
Rebuilds the menu using the items in the array. The first array item
(array$(0)) is the menu title, and the last has to be ‘END’. Things like
ticks and dotted lines are reset. Submenus are included with each item in
the usual way, ie. array$(4)=‘Info>info%’. menu% = handle of menu to rebuild
array$() = array to get items from.
3. Icons
FNwimp_iconbar(sprite$,text$,pos%)
Places an icon on the iconbar. Returns a handle to the window containing the
iconbar icon. sprite$ = name of sprite to put on iconbar. text$ = text to
put underneath the icon eg. like the floppy drive icon. If text$ = “” then
no text will be used, and the icon will be positioned correctly. pos% =
controls the position of the icon. If pos% = 1 then the icon will appear on
the right. If pos% = 0 then it will appear on the left.
FNwimp_geticontext(window%,icon%)
Returns a string containing the text from the icon. window% = handle of
window containing icon. icon% = icon number.
PROCwimp_puticontext(window%,icon%,text$)
If the icon is indirected then the text in the icon is replaced with text$.
If the icon is not indirected then an error is caused. Can also be used to
change the sprite in the icon. window% = handle of window containing icon.
icon% = number of icon.
PROCwimp_puticonbartext(text$)
If the iconbar icon has text underneath it then it is replaced by text$.
PROCwimp_iconbarsprite(sprite$)
Changes the sprite used for the iconbar icon to sprite$.
PROCwimp_putcaret(window%,icon%)
Puts the caret in the icon. window% = handle of window containing icon.
icon% = number of icon.
PROCwimp_losecaret
Removes the caret from the icon it is in.
PROCwimp_iconenable(window%,icon%)
Un-greys out icon so it can be selected. window% = handle of window
containing icon. icon% = number of icon.
PROCwimp_icondisable(window%,icon%)
Greys out icon so it cannot be selected. window% = handle of window
containing icon. icon% = number of icon.
PROCwimp_iconselect(window%,icon%,state%)
Selects (inverts) and un-selects icon. window% = handle of window containing
icon. icon% = number of icon. If state% = 0 icon is un-selected. If state% =
1 icon is selected. Useful for making an icon appear to be clicked on when
Return is pressed in a writable icon.
4. Messages
PROCwimp_initmessages(pathname$)
Reserves blocks of memory and sets up Messages file for use. pathname$ =
full pathname of messages file to use.
FNwimp_messlook0(token$)
Returns the string in the messages file for the token token$.
FNwimp_messlook1(token$,a$)
Returns the string in the messages file for the token token$. Any ‘%0’s in
the string are replaced with a$ before returning.
FNwimp_messlook2(token$,a$,b$)
Returns the string in the messages file for the token token$. Any ‘%0’s and
‘%1’s are replaced with a$ and b$ respectively before returning.
5. Misc
FNwimp_initialise(name$,wimpmem%,iconmem%)
This function registers your application with the Task Manager and reserves
some memory. name$ = the name of your application eg. ‘Draw’. wimpmem% =
number of bytes to reserve for icon data or menu entries. iconmem% = number
of bytes to reserve for indirected text. eg. window titles or long menu
entries.
PROCwimp_poll
This function is the main loop of your application When it has finished,
your application has quitted. If something happens to your application eg.
an icon has been clicked on, then the relevant function will be called from
the loop. Set finished% to TRUE to quit.
PROCwimp_error(title$,error$,button%,prefix%)
Reports an error using a standard error box. title$ = title of error window.
error$ = error message. IF button%=1 then will have an ‘OK’ button. IF
button%=2 then will have a ‘CANCEL’ button. prefix% = prefix flag. If = 0
then the title is title$. If = 1 then the title is prefixed by ‘Error from
’. If = 2 then the title is prefixed by ‘Message from ’.
FNwimp_errorchoice(title$,error$,prefix%)
Reports an error using a standard error box. It has both ‘OK’ and ‘CANCEL’
buttons. title$ = title of error window. error$ = error message. IF prefix%
= 0 then the title is title$. If prefix% = 1 then the title is prefixed by
‘Error from ’. If prefix% = 2 then the title is prefixed by ‘Message from ’.
Returns TRUE if ‘OK’ pressed. FALSE if ‘CANCEL’ pressed.
PROCwimp_loadsprites(pathname$)
Creates a user sprite area and loads the sprites into it so they can be used
in windows, etc. pathname$ = full pathname to sprite file.
FNwimp_getleafname(pathname$)
Returns a string containing the leafname from the pathname. pathname$ =
pathname.
PROCwimp_pointer(pointer%,area%,pointer$)
Changes mouse pointer between the default (number 1) and the user defined
pointer (number 2). If pointer% = 0 default pointer is used. If pointer% = 1
user defined pointer is used. If area% = 0 wimp sprite pool is used. If
area% = 1 user sprite area is used. pointer$ = sprite name of pointer.
PROCwimp_starttask(command$)
Sends command$ to the CLI. Omit ‘*’.
FNwimp_libversion
Returns the version number of the library x 100. Eg. if the version of the
library is 1.03 then 103 will be returned.
FNwimp_sysvariable(sysvar$)
Returns a string for the system variable sysvar$. Note ‘<’ and ‘>’ are not
required in sysvar$.
PROCwimp_bar(window%,icon%,length%)
Changes the length of the bar to length%. window% = handle of window
containing bar. icon% = icon number of bar.
6. User
PROCuser_redraw(window%,minx%,miny%,maxx%,maxy%)
When this function is called, the Wimp wants you to update the specified box
on the screen. The box is in the work area of the window whose handle is
window%. minx%,miny% = bottom left co-ordinates of box. maxx%,maxy% = top
right co-ordinates of box.
PROCuser_mouseclick(window%,icon%,button%)
IF an icon has been clicked on in one of your windows then this function is
called. window% = handle of window containing icon. icon% = number of the
icon clicked on. button% = which mouse button was pressed. Eg. 4 for Select,
1 for Adjust.
FNuser_menu(window%,icon%)
IF the specified window (and icon) has a menu which you want to appear when
Menu is pressed over it, then this function should return the handle of the
menu. window% = handle of window. icon% = number of icon.
PROCuser_openwindow(window%,x%,y%,stack%)
IF this function is called, then the window whose handle is window% has been
opened with the top left of the window at x%,y% on the screen. stack% =
window handle to open behind, or -1 for top of window stack, or -2 for
bottom.
PROCuser_closewindow(window%)
IF this function is called, then the window whose handle is window% has just
been closed.
FNuser_keypress(window%,icon%,code%)
IF a key is pressed while one of your windows has the input focus, or a
hotkey is pressed, then this function is called. If you don’t use the key
then return a 0. If you do then return a 1. window% = handle of window with
input focus. icon% = number of icon with caret. code% = key code. For most
keys it is an ASCII number.
Key Alone +Shift +Ctrl +Ctrl Shift
Escape &1B &1B &1B &1B
Print (F0) &180 &190 &1A0 &1B0
F1-F9 &181-189 &191-199 &1A1-1A9 &1B1-1B9
Tab &18A &19A &1AA &1BA
Copy &18B &19B &1AB &1BB
left arrow &18C &19C &1AC &1BC
right arrow &18D &19D &1AD &1BD
down arrow &18E &19E &1AE &1BE
up arrow &18F &19F &1AF &1BF
Page down &19E &18E &1BE &1AE
Page up &19F &18F &1BF &1AF
F10-F12 &1CA-1CC &1DA-1DC &1EA-1EC &1FA-1FC
Insert &1CD &1DD &1ED &1FD
PROCuser_menuselection(menu%,item%)
This function is called when the user has chosen a menu item from one of
your menus. menu% = handle of menu. item% = item number (top item is 1).
PROCuser_savedata(pathname$,window%)
When the user is required to save data, this function is called. pathname$ =
full pathname of file to save data to. window% = handle of save window icon
was dragged from.
FNuser_loaddata(pathname$,window%,icon%,filetype$)
You load data here. pathname$ = full pathname of source file. window% =
handle of window file was dragged on to. icon% = number of icon file was
dragged on to. filetype$ = filetype of file to be loaded. Eg. “FFF”.
FNuser_savefiletype(window%)
You return the filetype for the save windows. eg. =‘FFF’. For windows that
aren’t save windows, return an empty string eg. =‘’. window% = handle of
window%
FNuser_help(window%,icon%)
Return a string to be used for interactive help for the window (and icon).
window% = handle of window (containing icon). icon% = number of icon.
PROCuser_enteringwindow(window%)
This function is called when the pointer enters a window. window% = handle
of window.
PROCuser_leavingwindow(window%)
This function is called when the pointer leaves a window. window% = handle
of window.
FNuser_pane(window%)
IF the window has a pane attached to it, then this function should return
the window handle of the pane. If the window doesn’t have a pane attached,
then it should return a -1. window% = handle of window.
PROCuser_null
This is called continuously. So if you are writing something like a clock,
you would monitor the time here and change any windows as required. IF you
want to use this function then set NULL=TRUE.