Back to Contents        Previous        Next








18. Large menus, rebuilds and Font menus

This section is again concerned with menus - including how to create very large menus, how to completely change a menu (ie. a re-build), and add and remove items. Also, how to create menus of the fonts loaded in your machine.

Please note that Dr Wimp creates all the title and item text in menus as indirected - and therefore you do not need to worry about the maximum text length. These should be transparent features but it may help if/when you examine the coding in the DrWimp library.

Allowing for extra menu items
Menus can be created so that they 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 (handle/start address assigned to menu%) 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 would 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 18 further items added to it later on.

The created maximum number of menu items is stored with each menu’s definition and can be read using FNwimp_menumaxsize().



Adding/deleting menu items
PROCwimp_putmenuitem and PROCwimp_removemenuitem add and remove items from menus. Note: a non-fatal warning is given if the menu is already at its maximum size (as defined at its creation) and therefore cannot accept extra menu items.

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 existing items+1 then it will just be added onto the end. If item% is less than or equal to the number of existing items, the new item is inserted at item% and those below it are shuffled down. Removing items works similarly, with remaining items being shuffled up.



Re-creating the whole menu
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 call 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/..../..../Quit”

The number of items in the new (re-created) menu must not be greater than the specified maximum value when FNwimp_createmenu was called - and a warning will be given is this is being attempted.

When a menu is re-created, all the item attributes like dotted lines, greying out, and ticks are removed and therefore need to be subsequently re-applied if still wanted. (And don’t forget that the item number for Quit might well change - the tip given earlier is very useful here.)

If you want to change only the text of menu items then use PROCwimp_putmenutext instead, as all the attributes are then retained.



Handling very large menus

However, FNwimp_createmenu and PROCwimp_recreatemenu have a major limitation: very large menus cannot be built - simply because the ‘slash-separated’ menu text is a single string, which is limited to 255 characters.

DrWimp provides two solutions to this - using arrays or message files. These are examined in turn below.

Menus from string arrays
The first 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 of data from support files for your application.
For this method, you firstly need to decide the maximum number of items in the menu. Add one to the total size, and DIM a string array.

Then fill the array elements with the required item text - array element 1 for menu item 1, element 2 for menu item 2, etc. The first element of the array (element 0) is for the menu title. The last item must be the string “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:

maxitems%=20
DIM menu$(maxitems%+1):REM** array large enough for 20 menu items. **
menu$(0)=“MyApp”:REM** Menu title string. **
menu$(1)=“Info” :REM** First menu item. **
menu$(2)=“Options” :REM** Second menu item. **
menu$(3)=“Quit” :REM** Third (and last, here) menu item. **
menu$(4)=“END”
iconbarmenu%=FNwimp_createmenuarray(menu$(),20)
PROCwimp_attachsubmenu(iconbarmenu%,1,info%)


which will create a three-item menu with the title “MyApp” and items “Info”, “Options” and “Quit”.

As you can see, 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 be made 0 if the size is not going to change subsequently. Here it is set to maxitems%. (Note that “END” always needs to be put in the array element after the current last item. If re-creation causes the number of items to increase then “END” needs to be moved accordingly.)


Menus can be re-built using arrays as well. Instead of using PROCwimp_recreatemenu, use:

PROCwimp_recreatemenuarray(menu%,array$())




Menus from Message files
It is also possible to create menus automatically from a message file - and you may need to refer back to Section 2.9 to recap on the message file structure in the following.

The big advantage of using this method is that the size of the menu is not restricted in any way.



The following is an example of the necessary message file structure and - as with all message files - the first step is to initialise the message file (with FNwimp_initmessages()) to obtain its handle. We will assume that this has been done and that the handle is messagefilehandle%:

BMenuT:Iconbar menu
BMenu1:Info
BMenu2:Quit


Then, by using:

iconbarmenu%=FNwimp_createmessagemenu(messagefilehandle%, "BMenu","",0)

a menu will be created with the title “Iconbar menu”, and two items, the first being “Info” and the second being “Quit”. The first parameter of the above wimp-function is the messages file handle. The second is the token string (see Section 2.9) and is used to find the individual items of the menu in the messages file. token+“T” is the title, token+“1” is item one, token+“2” is item 2 and so on.

The third parameter is the menu title. In this case it’s an empty string, so the one in the messages file is used. If, instead, we had put:

iconbarmenu%=FNwimp_createmessagemenu(messagefilehandle%, "Bmenu",appname$,0)

then the menu title would be the string appname$, overriding the title in the messages file. In fact if you specify a menu title, then the token in the messages file for the title doesn't have to be included, and you can just specify the items.

The final parameter is the maximum size of the menu. It is exactly the same as the last parameter of FNwimp_createmenu.






It is vital to note that the Wimp demands very strict discipline of the message file structure. For instance:

BMenuT:Iconbar menu
BMenu2:Quit

BMenu1:Info

would fail, simply because the entries must be in the same file position as their number sequence.
Further, Dr Wimp also imposes a small format requirement concerning the title item. As has already been stated, there is no need to include a title item - but it is essential not to include the title token element with a null string entry e.g.:

BMenuT:
BMenu1:Info
BMenu2:Quit

will fail (and you will find that an extra blank menu item occurs as a result).



From Dr Wimp 3.61 onwards (as already mentioned in Section2.9) there is also:

PROCwimp_recreatemessagemenu(menu%,messagefilehandle%,token$,
title$)

whose use should now be self-explanatory, and:

FNwimp_getnumberofmessages(messagefilehandle%,token$)

which reads a messages file and returns the number of messages in it having the given token.


Flexibility

A menu that has initially been created with any one of the three ‘wimp_createmenu....’ functions can be recreated with any one of the three ‘wimp_recreatemenu...’ functions.





Dynamic sub-menu manipulation
Finally in this section, we come to PROCuser_overmenuarrow. This user-function is called whenever the mouse pointer passes over one of those little arrow-heads to the right of a menu item when it has a sub-menu (or window) attached to it. Its format is:

PROCuser_overmenuarrow(rootmenu%,rootmenuitem%,RETURN nextsubmenu%,nextsubmenunumber%,parentmenuitem%,x%,y%)

The parameter rootmenu% holds the handle of the root menu and rootmenuitem% holds the currently selected menu item in that root menu. (The root menu is the first menu of the particular menu ‘tree’ in use.)
The handle of the sub-menu/window about to be opened is given in nextsubmenu% (note this is a RETURN parameter, see later) and its position in the current ‘tree’ in nextsubmenunumber% i.e. if the sub-menu about to be opened is the first submenu of the tree then nextsubmenunumber% will be 1, and if it is the second sub-menu it will be 2, etc.
The menu item number of the item whose arrow-head the pointer is over will be contained in parentmenuitem% and the x/y values (in screen OS units) of the pointer position when moving over the arrow head will be in x%, y%.

This user-function provides considerable flexibility for handling menu trees - including the means to alter/rebuild etc. the about-to-be-opened sub-menu dynamically if you so wish - or even to display a totally different sub-menu/window.

For example, assuming the standard main menu with ‘Info’ as its first item and the sub-menu (a window, here) handle of info% attached to it, you could make PROCuser_overmenuarrow look like:

DEF PROCuser_overmenuarrow(rootmenu%,rootmenuitem%,RETURN nextsubmenu%,nextsubmenunumber%,parentmenuitem%,x%,y%)
CASE nextsubmenu% OF
         WHEN info%
         CASE parentmenuitem% OF
                  WHEN 1: PROCwimp_puticontext(nextsubmenu%,0,TIME$)
         ENDCASE
ENDCASE
ENDPROC
which would put the current time into icon number 1 of the info window each time you open it.

Another practical example might be:

CASE nextsubmenu% OF
         WHEN submenu1%
         CASE parentmenuitem% OF
                  WHEN 2
                  IF condition%=TRUE THEN
                           PROCwimp_menuenable(nextsubmenu%,3,1)
                  ELSE
                           PROCwimp_menuenable(nextsubmenu%,3,0)
                  ENDIF
         ENDCASE
ENDCASE


which would ‘grey out’ Item 3 of the up-coming submenu if the current state of condition% is FALSE or enable the same item if condition% is TRUE - with condition% only being tested at the time the pointer goes over the arrowhead.

This user-function is particularly useful for large menu trees e.g. if you have a fourth sub-menu about to be opened from a third sub-menu then PROCuser_overmenuarrow will be called with the fourth submenu handle in nextsubmenu%, the value 4 in nextsubmenunumber% and the third sub-menu’s currently selected item number in parentmenuitem%. (And, of course, the root menu handle and selected item will always be contained in rootmenu% and rootmenuitem%.)

Note that the x/y values made available in this user-function can often conveniently be passed directly through to other wimp-function calls that you might make here, for example to open a window at a certain place relative to the x/y values.

Finally, the purpose of the RETURN with the first parameter of this user-function. With this you can, if you so wish, completely change the sub-menu/window handle at this same ‘over arrow-head’ point e.g. so that the user is presneted with one sub-menu/window in one set of circumstances and another in another set.

This is effected simply by reassigning the variable nextsubmenu% within the user-function. For example:

DEF PROCuser_overmenuarrow(rootmenu%,rootmenuitem%,RETURN nextsubmenu%,nextsubmenunumber%,parentmenuitem%,x%,y%)
CASE nextsubmenu% OF
         WHEN info%
         IF registered%=FALSE THEN nextsubmenu%=unreginfo%
ENDCASE
ENDPROC

This would substitute the window unreginfo% for info% if the flag registered% is FALSE. (The window unreginfo% would, of course, need to be already loaded.)

As you can see, PROCuser_overmenuarrow really does allow you to manage your menus comprehensively.



Font menus
In some applications the user needs to select the font he/she requires for display or printing. This is invariably done by providing the user with the means to display a menu of the available fonts - which are those which have been loaded into your machine’s !Fonts application, or otherwise made active by a font manager utility. (A quick look at Style.Font name from the main menu in a !Draw document will refresh your memory on what a font menu looks like.)

To produce menus of current fonts in your own applications, two wimp-functions are available: namely FNwimp_createfontmenu, which has no parameters, and FNwimp_recreatefontmenu(), which has one parameter.

FNwimp_createfontmenu creates a font menu definition - comprising the full menu/sub-menu ‘tree’ of all the fonts currently active on the user’s machine - and returns the corresponding menu handle.

Should you wish to re-create an existing font menu definition, then FNwimp_recreatefontmenu(fontmenu%) is used - where fontmenu% is the existing font menu’s handle.

If you want a font menu to appear as a sub-menu then the font menu handle can be attached to a normal menu/sub-menu in the usual way - using PROCwimp_attachsubmenu().


Bearing in mind that the fonts available on any machine might well change during the run of your Dr Wimp application, it is usual to make an initial creation of a font menu at application start-up i.e. within PROCuser_initialise, and then re-create the font menu immediately prior to each opening of that font menu.

You can also create multiple font menu definitons, each with its own handle - for applications where you need to provide more than one independent font menu actions e.g. for changing the font independently in two icons in the same window.

As will be explained in more detail later, selection from a font menu is made in the usual way and the selected full font name (’period separated’) is automatically passed to the third parameter in:

PROCuser_menuselection(menu%,item%,font$)

In addition (and this is different from the practice with normal menus) the font menu handle is passed in menu%.

With normal menus/sub-menus, where the programmer always knows all the menu and sub-menu handles, menu% will hold the handle of the menu or sub-menu from where the selection was actually made. However, with font menus, the programmer only knows (and only needs) the handle of the complete font menu definition and does not know the many font sub-menu handles. So it is the overalll font menu handle which is passed in font menu cases, irrespective of where, in the font menu tree, the font selection is made.

The programmer can thus use the menu% and font$ information as he/she wishes, in the usual Dr Wimp way.


With the above we can now look at some practical usage.

To create a font menu, all that is necessary is to use a line such as:

FontMenu1%=FNwimp_createfontmenu

and that’s all there is to it. Here, the handle of the font menu has been assigned to the variable FontMenu1% which can then be used in the same way as any other menu handle.

However - because of the point made earlier about catering for changes in the active fonts made during the run of an application - it would be sensible to place the above ‘creation’ call in PROCuser_initialise and then arrange to re-create the font menu afresh each time it is to be displayed.

Thus, for example, after making the above call, if you wanted to display the up-to-date font menu when <menu> is pressed over a particular window, then you might code of FNuser_menu() as follows:

DEF FNuser_menu(window%,icon%,screenx%,screeny%)
return%=0
CASE window% OF
         WHEN main%
FontMenu1%=FNwimp_recreatefontmenu(FontMenu1%)
return%=FontMenu1%
ENDCASE
=return%

This would ensure that you always see the up-to-date font list.

Similarly, if you wanted the menu to appear by using PROCwimp_menupopup() then you would use PROCuser_mouseclick() and, again, display the menu just after a ‘re-creation’ call.


As already stated, if you want the font menu tree to open as a submenu off an item in another (already defined!) menu, then you simply use PROCwimp_attachsubmenu() in the normal way. This will automatically attach the complete font menu tree (i.e. with all its font sub-menus) as a sub-menu structure.

Thus, if you also wanted the same font menu to appear as a sub-menu from Item 2 of an iconbar menu you would simply add:

PROCwimp_attachsubmenu(Iconbarmenu%,2,FontMenu1%)

to PROCuser_initialise after the initial creation of FontMenu1% - and then make DEF FNuser_menu() look like this:

DEF FNuser_menu(window%,icon%,screenx%,screeny%)
return%=0
CASE window% OF
WHEN Iconbarmenu%
         FontMenu1%=FNwimp_recreatefontmenu(FontMenu1%)
         return%=FontMenu1%
WHEN main%
FontMenu1%=FNwimp_recreatefontmenu(FontMenu1%)
return%=FontMenu1%
ENDCASE
=return%




Further, if you needed the actions resulting from the main% and Iconbarmenu% font selections to be completely independent then it would simply be a matter of creating a second font menu as FontMenu2% in PROCuser_initiliase and substituting that in one of the above cases e.g.:

DEF FNuser_menu(window%,icon%,screenx%,screeny%)
return%=0
CASE window% OF
WHEN Iconbarmenu%
         FontMenu1%=FNwimp_recreatefontmenu(FontMenu1%)
         return%=FontMenu1%
WHEN main%
FontMenu2%=FNwimp_createfontmenu(FontMenu2%)
return%=FontMenu2%
ENDCASE
=return%



For even more flexibilty with a font menu as a sub-menu, you could also use PROCuser_overmenuarrow(). For example:

DEF PROCuser_overmenuarrow(rootmenu%,rootmenuitem%,RETURN nextsubmenu%,nextsubmenunumber%,parentmenuitem%,x%,y%)
CASE nextsubmenu% OF
         WHEN FontMenu1%
         REM** FontMenu1% is previously-created font menu handle and previously attached as a sub-menu to a menu. **
         FontMenu1%=FNwimp_recreatefontmenu(FontMenu1%)
         nextsubmenu%=FontMenu1%
ENDCASE
ENDPROC

This method relies on the RETURN in the third parameter to change the sub-menu handle (in nextsubmenu%) to the one just newly re-created - and this occurs each time the pointer moves across the menu arrow.


Font menu selection
Having got the font menu displayed we need to look at PROCuser_menuselection() to see how to retrieve and use the font selection. The user-function is:

DEF PROCuser_menuselection(menu%,item%,font$)

As usual, when a selection is made from any menu, this user-function is called automatically by Dr Wimp with the parameters set to the ‘live’ values ready for your use. With font menus the only differences are that:

- for a selection from a normal menu: menu% and item% are used as normal, but font$ is always set automatically to a null string; and
- for a selection from a font menu: item% is always automatically set to 0; menu% is set to the font menu handle and font$ carries the complete ‘period separated’ font name. (To be absolutely clear: if you have created a font menu with the handle FontMenu1% and made a font selection from it, then menu% will always hold the value FontMenu1% - whether you made the selection from the ‘root’ of the font menu or one of its sub-menus.)

So, a typical general coding might include:

DEF PROCuser_menuselection(menu%,item%,font$)
....
....
IF font$<>”” THEN
CASE menu% OF
WHEN FontMenu1%
         selectedfonthandle1%=FNwimp_getfont(font$,12,12)
         <etc.>

WHEN FontMenu2%
selectedfonthandle2%=FNwimp_getfont(font$,16,16)
         <etc.>
ENDCASE
ENDIF
....
....
ENDPROC




To help take advantage of the font menu facilities the wimp-function:

PROCwimp_puticonfont(window%,icon%,fonthandle%)

allows the font used for text in an icon to be changed.

The usage should be self-explanatory, but you do have to ensure that the icon definition specifies that an outline font is used - otherwise a non-fatal error occurs and no change is made.

The Example application !FontMen demonstrates these font menu facilities.

Finally, it needs to be noted that the detailed contents of font menus cannot be changed in the same way as other menus - and, in fact, you would not normally wish to do so. For example, you cannot add/remove items with PROCwimp_putmenuitem/PROCwimp_removemenuitem, nor can you colour an item with PROCwimp_menuitemcolour, etc. etc.

So, all of the ‘menu contents changing’ wimp-functions (although still usable with ordinary menus) will give a non-fatal error if you try to apply them to a font menu. However, FNwimp_menusize can still be used.






Top of page        Back to Contents        Previous        Next