Back to Contents        Previous        Next








4. Window & icon control **

Most applications have a main window that appears when the user clicks on the iconbar icon. This is easy to implement with Dr Wimp.

Pressing the <select> or <adjust> button
Copy “Template2” from the Tutorials folder (Tutor1 sub-directory) 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”,0)


Whenever the <select> or <adjust> mouse button is pressed over one of !MyApp’s icons, the user-function PROCuser_mouseclick is automatically called, passing to it the window handle, the icon number, a number relating to the mouse button pressed and the work area coordinates the pointer was at. These are in window%, icon%, button%, workx% and worky% respectively. (It is useful to remember that PROCuser_mouseclick is used to respond to <select> or <adjust>, whereas FNuser_menu is used for <menu> presses)

Therefore, in !RunImage, change PROCuser_mouseclick so that it looks like:

DEF PROCuser_mouseclick(window%,icon%,button%,workx%,worky%)
CASE window% OF
         WHEN iconbar% :
PROCwimp_openwindow(main%,1,-1)
ENDCASE
ENDPROC

As you can see, when a mouse button is pressed over the iconbar icon (i.e. in the window whose handle is iconbar%) then PROCwimp_openwindow is called , which here is used to open the window whose handle is main%.

The first parameter of PROCwimp_openwindow 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 centred on the mouse pointer. (Useful if you want to open save windows below the pointer so the user doesn't have to move the pointer very much to start dragging the file icon.)

If the third parameter was -2 then the window would open behind all the others. If the third parameter was -3 then the window would at the current stack position. If this third parameter was another window handle then the opening window would open behind that window - very useful when panes are involved (see Section 2.6). Finally, if the third parameter was -4 the window would open ‘behind the backdrop’ i.e. the window would be open but hidden - a rather special usage which need not concern us here.

Run !MyApp and check that it works, then try changing the values of parameters of PROCwimp_openwindow and see what happens.

Note: PROCuser_mouseclick will also respond to mouse-clicks over a window's background, if the latter is given a ‘button type’ of ‘Click’ in a template editor - see !WinEd. In such cases, the icon number passed in PROCuser_mouseclick will be -1.



Our new window main% is divided up into three sections. We will now 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 !WinEd as described before.

The first section contains a writable icon (icon number 1) which can take up to 19 characters (+1 terminator character, making a total of 20 - the value set here). This value is set by using !WinEd and changing the ’Max text length’ for this writable icon.


Reading icon text and writable icons
Entering text into writable icons is fully automated by the Wimp. Click in the writable icon and the caret will appear so you can enter some text. Note also that this action automatically gives the window the ‘input focus’ (if it hasn’t already got it) - signified by the title bar changing to a cream colour. There is more on this a little later.

What we want to do is enter some text from the keyboard into the writable icon (Icon 1) and when ‘OK’ is clicked on (icon number 2), the text is read from the icon and copied into the icon below (icon number 11). As an alternative action, we want to achieve the same copying result by pressing <return> when the caret is in the writable icon.


The wimp-function FNwimp_geticontext reads text from icons i.e. it is the complement 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.

So, alter PROCuser_mouseclick to look like:

DEF PROCuser_mouseclick(window%,icon%,button%,workx%,worky%)
CASE window% OF
WHEN iconbar% : 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 this first step works. Read this part of the above routine as “When the window is main% and the clicked icon is 2, read the text in icon number 1 and write it into icon number 11”. The OK button (icon number 2) has the yellow trough/border around it and is called the Default Action icon.

‘Indirected’ icons
Note that, although you can read text from any icon, you can only put new text into icons if they are what is called “indirected”. You can make an icon indirected by turning that option on when editing the icon in a template editor. At the same time, you need to decide the maximum number of characters you want to use - then add 1 to it (because the Wimp always automatically adds a string ‘terminator’). This is value is entered in the appropriate place in the template editor.

So, making an icon indirected with a maximum value of 11 allows a user to put up to 10 text characters into the icon.

If you have an icon whose text you are never going to change during the program run (e.g. a label) then you can make it non-indirected to save memory - but note that the maximum size of non-indirected text is 12 (11 characters plus terminator).


Keyboard keys
The above deals with clicking the OK button, and now we are going to make the action of pressing the keyboard’s <return> key (when the caret is in the writable icon) do the same as clicking on the OK button.

The <return> key is just one of the keys on the keyboard, so before looking at our immediate issue we need to divert for a moment to look more generally at what happens when any keyboard key is pressed whilst the caret is in a writable icon.


The detailed result(s) of a keypress are programmer-definable via the ‘validation string’ (see Section 2.28 later) which is set in the definition of the writable icon.

Briefly, the validation string can, among other things, control which characters (typed at the keyboard rather than entered by PROCwimp_puticontext) are allowed to appear in the writable icon, how the caret moves between writable icons (when there are more than one in a window) and which keypresses will be notified to our task by the Wimp if/when they occur. These issues can be controlled separately by the validation string but there are sensible default arrangements if you opt to ‘do nothing’.

The main points to note for this stage of our tutorial are that, by default (and with only one writable icon in the window), all printable characters entered at the keyboard will be displayed in the writable icon but only the pressing of the <return> key will be notified to our task by the Wimp (so that we can respond to that, if we wish).


Whenever a keypress is notified to a Dr Wimp task, FNuser_keypress is automatically called -and passed to it is the window handle and the icon number holding the caret. Also passed to it is the ASCII number of the letter/number/symbol pressed, which for <return> is 13 (&0D).

In its’empty’ state FNuser_keypress returns 0. If we use the keypress to do something (other than simply appearing in a writable icon) then we must return a 1. This is to stop the keypress being notified to other tasks by the Wimp.

So alter FNuser_keypress to:

DEF
FNuser_keypress(window%,icon%,key%)
return%=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$)
return%=1
ENDIF
ENDCASE
ENDCASE
=return%

Note that the writable icon is icon number 1, which is the location of the caret when <return> is pressed.

This added code is very similar to what we added in the mouse-click case - which is what you might expect as we want the same action.

It may look to be a lot of code for what it actually does, but it has been written so that it is easy to add more pieces of code for lots of windows/icons (or many different key press codes) with the minimum amount of effort and minimum risk of problems. Also it encourages putting the code onto several lines, making easier to read.


Selecting/De-selecting icons
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 the OK button ‘press in’ in both cases, because then they know exactly what has happened. ‘Pressing in’ is simply a behind-the-scenes trick whereby one icon is used for the ‘deselected’ state and another for the ‘selected’ state.


DrWimp provides a wimp-function, PROCwimp_iconselect, to select/deselect an icon. So, to achieve our required effect all we have to do is select the OK icon, copy the text, then deselect the OK icon.

In DEF FNuser_keypress(), alter the part between IF key%=13 THEN and ENDIF so that it looks like:

IF key%=13 THEN
         PROCwimp_iconselect(main%,2,1):REM** Selects the icon. **
         text$=FNwimp_geticontext(main%,1)
         PROCwimp_puticontext(main%,11,text$)
         return%=1
         PROCwimp_iconselect(main%,2,0):REM** De-selects the icon. **
ENDIF

Re-run !MyApp and check it works.


PROCwimp_iconselect uses a format which is common to several wimp-functions in DrWimp. It has three parameters window%, icon% and state%. The first is the window handle, the second is the icon number and the third chooses the desired action: here, the selection state (0 to deselect: 1 to select and 2 to toggle from one to the other). In this case, icon% is 2 for the ‘OK’ icon.

If you removed the PROCwimp_iconselect(main%,2,0) call then the ‘OK’ button would stay pressed in. Try it and see.


On fast machines this simulated short press in may be too quick and just produce a flicker. You may therefore like to add the following line, maybe temporarily, just above PROCwimp_iconselect(main%,2,0):

PROCwimp_pause(1)

This wimp-function is described in Section 3. The above call will introduce a pause of 1 second into the <return> action.



Keypress character codes
Although we don’t need any more detail about keypresses for the tutorial, this is a useful point to delve a little further into the general handling of keyboard presses.

As seen above, the default arrangements for a writable icon i.e. assuming that no validation string is added by the programmer, is that all key presses will appear in the writable icon (if they are printable) but only a press of the <return> key is specifically notified to our task by the Wimp - via FNuser_keypress(window%,icon%,key%).

If we want to be notified of more keypresses than this then the validation string - and, in particular, its K-command - needs to be used.

The most important K-command in this respect is the Kn command. If this is entered into the validation string of a writable icon then all keyboard presses will be notified via FNuser_keypress(), with the value of its parameter key% being set to the appropriate keycode used by the Wimp - which is the normal ASCII code for alphanumeric keys and the codes as shown in the table below for the non-alphanumeric keys.

If using Kn it is then a matter of coding the contents of FNuser_keypress() carefully to respond to whichever key presses you wish and to signal these uses (and only these uses) with the correct return value of 1 for the user-function. If you are not responding to some keypresses - and that will be the normal case - it is important that ‘unused’ keypresses return the value 0 from the user-function.

As an important example, if you examine the following table you will see that the key F12 is a perfectly valid keypress and it will appear as the value &1FC in the parameter key% (if Kn is used). In virtually all cases it will be important that your application does nothing in response to this key - because it traditionally gives access to the Command Line. And there are other keys with common special uses.

The safest type of coding when using Kn is to try to give priority to ‘filtering’ the key% value before anything else. For instance, using the CASE structure with key% first:

DEF FNuser_keypress(window%,icon%,key%)
return%=0
CASE key% OF
WHEN <wanted codes>
CASE window% OF
WHEN <wanted window handles>
CASE icon% OF
WHEN <wanted icon handles>

<action>
return%=1

ENDCASE
ENDCASE
ENDCASE
=return%


Non-alphanumeric key press codes

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        

Radio icons
Returning now to our Tutorial, in our main% window, the second section contains two radio buttons labelled ‘Choice1’ and ‘Choice2’ and a button labelled ‘Swap’. Both the radio buttons have the same ESG group. In one ESG group, only one radio button can be selected at any one time, so clicking <select> on one radio icon within the group de-selects any others in the same ESG group.

Thus, here, when the user clicks <select> on Choice1 it becomes selected and Choice2 becomes deselected, and vice versa. Also, here, if you press ‘Swap’ the selected and de-selected radio icons swap over, as if you had clicked on the de-selected one. The ‘Swap’ button has an icon number of 6.

If you write an application with radio buttons, you may have to keep track of which ones are selected. For !MyApp we will use the integer variable choice% - which will be set to either 1 or 2 depending on which radio button is selected. When you first load !MyApp we will have it so Choice 1 is selected, so we will set choice% to 1 at the start.

Although you can set the radio icon to select when editing the templates it is always best to do this in your program so there is no chance of problems if a user fiddles with the templates file. In fact, this is good practice for all initial settings.

Then, when ‘Swap’ is clicked, we look at choice% to decide which to select and which to de-select.

So, just before ENDPROC in PROCuser_initialise, add the following lines to make the initial settings:

choice%=1
PROCwimp_iconselect(main%,4,1)
PROCwimp_iconselect(main%,5,0)

Then, 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%+=1
IF choice%>2 THEN choice%=1
WHEN 4 :
choice%=1
WHEN 5 :
choice%=2

It is mostly self-explanatory. The sequence choice%+=1:IF choice%>2 THEN choice%=1 toggles choice% between 1 and 2 to keep track of which one is selected.

This middle section of the main% window is a bit over-the-top (and the above coding is not elegant) but it is a clear demonstration of 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 deselected. 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 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.

So 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 now always have a radio icon selected.

Note: the act of clicking on a radio icon with any mouse button will automatically deselect the others in the same ESG group, so that’s why we only set the icon clicked on with <adjust> and not deselect the other here. However, note also from the above examples that using PROCwimp_iconselect() to select a radio icon does not, in itself, de-select others in the same ESG and you would need to carry out deselection separately - with further calls to the same wimp-function for the other icons with the same ESG.

Enabling/Disabling icons
The last section of the main% window 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, we will want to disable (‘grey out’) one of the buttons - because, for instance, if ‘On’ is already chosen there is not much point in clicking on ‘On’ . If the user clicks on a disabled icon, then the mouse click is ignored, and PROCuser_mouseclick is not called.

The function PROCwimp_iconenable(window%,icon%,state%) follows the common DrWimp practice: it allows you to ‘enable’ an icon, or disable (’grey out’) it - or to change its current state from one to the other.

For example, in our tutorial program, just before ENDPROC in PROCuser_initialise, add the following to make the initial setting of the ‘Off’ button:

option%=0
PROCwimp_iconenable(main%,10,option%)

option% is going to be used to record the state of the ‘Off’ button option icon - which is icon number 10. So, placing option% (now 0) in the third parameter in the above call ‘disables’ the ‘Off’ button. If we had used 1 the icon would be enabled - and if we had used 2 the state of the icon would be changed i.e. if it was enabled it would be disabled - and vice versa i.e. ‘toggled’ between the two states.

Now modify PROCuser_mouseclick to:

WHEN 5 :
IF button%=1 THEN PROCwimp_iconselect(main%,5,1)
choice%=2
WHEN 9 :
PROCwimp_iconenable(main%,9,0):REM** Disables icon. **
PROCwimp_iconenable(main%,10,1):REM** Enables icon. **
PROCwimp_iconselect(main%,8,1)
option%=1
WHEN 10 :
PROCwimp_iconenable(main%,9,1)
PROCwimp_iconenable(main%,10,0)
PROCwimp_iconselect(main%,8,0)
option%=0
WHEN 8 :
IF option%=0 THEN
         PROCwimp_iconenable(main%,10,1)
         PROCwimp_iconenable(main%,9,0)
ENDIF
IF option%=1 THEN
         PROCwimp_iconenable(main%,10,0)
         PROCwimp_iconenable(main%,9,1)
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.

(If you want to check if an icon is currently enabled/disabled, then FNwimp_geticonenable() returns 0 if the icon is disabled and 1 if the icon is enabled.)

As you can see, PROCuser_mouseclick is probably one of the most important user­functions and will often contain most of the code to control your application.



Changing the window title
You must have noticed in many applications (eg. !Edit, !Draw) that as soon as you have some unsaved data, the title of the window has an asterisk added to its end. Using DrWimp this is quite easy to achieve, once you know that you have some unsaved data..........

¸ Note: In order to change the window title it must be ‘indirected
. This is set up using a template editor like !WinEd, similar to setting up indirected text for icons.

For !MyApp we will assume that we have some unsaved data when, in the main% window, ‘OK’ or <return> is pressed.

FNwimp_getwindowtitle returns a string containing the window title and its complement is PROCwimp_putwindowtitle which 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.

So change the WHEN 2 section in PROCuser_mouseclick to become:

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 existing title is read into title$ and 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.

If your program has a save feature (details on how to do that coming up later) then when the data has been saved you can remove the asterisk from the title.

Don’t forget to allow for the extra ‘space-plus-asterisk’ (two characters) when setting the maximum allowable length of the indirected title text!


Banners
Just a quick thing for you to try while we are dealing with windows: quite a few programs have a temporary window that appears in the centre of the screen when it loads. It stays there for a bit before closing again. This is called a ‘banner’.

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 ENDPROC in PROCuser_initialise 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 you can design your own window, load it in, and put things like version number and date, etc in using PROCwimp_puticontext.



The caret and ‘input focus’
As has been demonstrated, if you click on a writable icon it gains the caret, and the window it is in gets the ‘input focus’ - signified by the title bar changing to a cream colour.

But there will be many occasions when you want, automatically, to give the input focus to a window you have just opened and place the caret in a specific writable icon. This is done by using PROCwimp_putcaret(window%,icon%,index%) to specify the window and icon in which the caret should be placed.

If you wish to place the caret in the icon text more precisely then the third parameter, index%, can be set to the number of characters from the start (left) of the text to the required caret position. That is, a value of 0 will place the caret in front of the text; the value 1 will place it between the first and second character from the lrft; and so on. The special value of -1 will place the caret after the last (right-most) character - and this will also happen if the index% value is longer than the text string.
It may be obvious, but it is worth noting that the window needs to be open before this particular wimp-function can be used.

There may also be occasions when one of your windows will not have a writable icon but you want to give the window the input focus anyway. This is effected by calling PROCwimp_putcaret using the appropriate window handle but with the icon parameter set to -1. This gives the window the input focus without placing the caret. (index% also needs to be given a value in this case, even though it will be ignored.)

[Your !RunImage listing should now look like listing RI_02 in Tutor1 (apart from the REM lines, perhaps). Do not destroy it as the following sections continue the tutorial from this stage.]






Top of page        Back to Contents        Previous        Next