---------------------------------------------------------
The Liberty Basic Newsletter - Issue #44 - JUL 99
"Knowledge is a gift we receive from others."
		- Michael T. Rankin
---------------------------------------------------------
In this issue:

Menus - Part 1


In future issues:

Searching Arrays, Part 2 - by Ian Davies
Menus - Part 2 
General Programming Principles
---------------------------------------------------------
Menus - Part 1:

Liberty BASIC MENUS
	Syntax and usage.

Menu API calls:  the basics
	Getting handles to menus and menu items.
	Removing the MenuBar.

Menu API calls:  intermediate
	Change string$
	Enable/disable menu items.
	Check menu items.
	Menu Radio Buttons.
	Check menu items with bitmap.
	Use bitmap as menu item.
__________________________________________________

Liberty BASIC MENUS: Syntax and usage

Menus will appear on a gray bar (the menu bar!) just under 
the titlebar of a window.  You must list menus in your code 
before the OPEN window statement.  The format for a menu is:

menu #w, "Top Title", "First Item", [1.branch],_
                "Second Item", [2.branch]

You may add as many items as you like, but the menu statement 
MUST ALL BE ON ONE LINE! All Liberty Basic commands must be 
on a single line - but it is possible to use multiple lines 
by using the continuation character:

menu #w, "Top Title",  _   ' The underscore is the CONTINUATION symbol 
                  "First Item", [1.branch], _
                  "Second Item", [2.branch]

The "Top Title" is the only part of the menu that will appear 
on the menu bar until the user clicks the mouse there.  Then, 
the entire menu will drop down and the user can choose any of 
the items.  The program will then continue execution at the 
branch label that has been designated for the chosen menu item.

Let us stop here and define terms.  The gray bar that appears 
just below the titlebar of a window is the MENU BAR.  The 
choices that are listed across the MENU BAR are SUBMENUS.  
The small, gray window that appears to drop down when a 
SUBMENU is clicked is a POPUP MENU.  The items that appear 
on the POPUP MENU are MENU ITEMS.  
 
Put an ampersand (&) in front of a character in your SUBMENU 
or in front of a character in your MENU ITEMS and that key 
becomes a hot key.  The user can choose the alt key and the 
hot key to activate the MENU ITEM, instead of doing so with 
the mouse.  

menu #w, "&SubMenu", "&Enabled Menu Item", [1.branch],_
        "&Disabled Menu Item", [2.branch], | , "E&xit", [exit]

In the above example hitting alt-S activates the POPUP MENU.  
Then, while continuing to hold down the alt key, hitting E 
activates the first item and the program will go to [1.branch], 
hitting D activates the second item, or hitting X activates the 
[exit] routine.  Hot keys are case insensitive, so activating 
alt-S is the same as alt-s.  Notice that your ampersand needn't 
be in front of the first character in a word to work - X is the 
second character in the word EXIT.  Notice also that you want 
unique letters in each item for a hot key.  If you designate 
T as a hot key in the first item, don't use T for a hot key in 
any other item.  Although the ampersand appears in your code, 
it will not appear within words in your program.  The character 
immediately following the ampersand in the code will be 
underscored to show the user that it is a hot key.  

You may include as many SUBMENUS as you need in your program.  
If they do not all fit across the top of a window, Windows 
will make the MENU BAR deeper and you will have more than one 
row of SUBMENUS.

You may place a dividing line between MENU ITEMS, so as to 
group them together for a more professional look.  You simply 
place the character ( | ) between commas.  That tells Windows 
to place a MENU BREAK in that position.  In the following 
example, a MENU BREAK will appear before the "Sec&ond Item."  

menu #w, "&Top Title", "&First Item", [1.branch],|,_
              "Sec&ond Item", [2.branch]


DIALOG BOXES

DIALOG BOXES do not have menus, so don't try to put one there!  
You will need to handle user choices in other ways, such as 
buttons or comboboxes if you use a dialog box.


TEXT WINDOWS

If your window is of type-TEXT, Liberty BASIC gives you a 
complete FILE menu, with open, print, etc. and a complete 
EDIT menu, with cut, paste, etc.  You do not need to designate 
these menus.  You cannot remove them either!  The user can access 
the EDIT menu with a right mouse click, making a nice, 
professional application.  You can add as many other menus 
to your TEXT WINDOW as you want.


TEXT EDITOR CONTROL

If you add a text editor control to a window, it will 
automatically add a complete EDIT menu to the menu bar.  
You do not need to designate it yourself, nor can you remove it.  
As with the TEXT WINDOW, you can access the edit menu with a right
mouse click.  You can add as many other menus to the window as you 
want.



___________________________________________________

Menu API calls:  the basics
There are quite a few ways to manipulate Liberty BASIC menus 
via the API.  To use them, you must first obtain handles (ID's) 
to the MENU BAR, SUBMENUS and MENU ITEMS that will be modified.
 
Getting handles to menus and menu items.
For most MENU API calls, you will need to obtain a handle to 
the MENU BAR.  GetMenu is the call that returns the 
MENU BAR HANDLE:

[Menu.Init]                   'Gets handle of menu bar
  CallDll #user, "GetMenu", _
     hMain as word,_      'handle of nongraphics window, or parent
                          'handle of graphics window
     hMenuBar as word   'returns handle of MENU BAR

After you get the handle of the MENU BAR, you may get the 
handles of any of the SUBMENUs that it contains with a call 
to GetSubMenu.  A SUBMENU appears on the menu bar, and when 
clicked, its POPUP MENU drops down.  You need to pass the 
parameter specifying the position of the SUBMENU, so please 
note that the first SUBMENU on the left side of the MENUBAR 
is in Position 0:

[GetSubMenu]
  CallDll #user, "GetSubMenu",   
    hMenuBar as short,_   'handle of MENU BAR
    nPos as short,_       'position of menu:0 is in the first position,
                          '1 is the second, etc.
    hSubMenu as short     'handle of submenu


Once you have the handle of the SUBMENU, you can get the 
handles of all of the MENU ITEMS on its POPUP MENU with a 
call to GetMenuItemID.  You will need the handles of these 
items for many of the menu api calls.  Please note that the 
parameter nPos, which specifies the position of the MENU ITEM 
desired counts positions from 0.  The first MENU ITEM has 
position 0, the second has position 1 and so on.

[GetMenuItemID]
	CallDll #user, "GetMenuItemID", _
	hSubMenu as word, _  ' handle of the submenu
	nPos as short, _     'position of the menu item on the popup menu
	menu.id  as word     'the handle (or ID) of the menu item


Removing the MENU BAR
There is one way to remove the FILE and EDIT menus from a text 
window.  It requires that you remove the entire MENU BAR.  
You need the handle of the window, in order to make the API 
call that removes the MENU BAR.  This is usually obtained with 
LB's HWND function:

hMain = HWND(#main)

If the program window is a graphics window, however, this 
presents a special case.  You must first obtain the handle 
of the graphics window, then use that to make a call to 
GetParent, and use the handle returned by that call in your 
subsequent API calls.  Examples of a graphics window and a 
nongraphics window follow:

[GraphicsWindow]
OPEN "No Menu Here!" for graphics as #main
hMain = HWND(#main)

CallDLL #user, "GetParent", _
    hMain AS word, _      'handle of graphics window
    hParent AS word       'returns parent window handle

[Menu.Destroy]            'Removes entire MenuBar
   calldll #user, "SetMenu",_
    hParent as word,_     'parent handle of graphics window
     0 as word,_             '0 removes the MENU BAR
    results as ushort       'returns nonzero if successful

Note please!  After this, all examples will be done in a plain 
window!  Please make allowances if you are using a graphics 
window, as above!


[NonGraphicsWindow]
OPEN "No Menu Here!" for graphics as #main
hMain = HWND(#main)

[Menu.Destroy]                'Removes entire MenuBar
  calldll #user, "SetMenu",_
     hMain as word,_          'handle of nongraphics window
     0 as word,_              '0 removes the MENU BAR
    results as ushort         'returns nonzero if successful


If you made a call to GetMenu before removing the MENU BAR, 
you can restore it with another call to SetMenu.

[restore.menubar] 
 CallDll #user, "SetMenu",_     'restore the menu bar
     hMain as word,_            'handle of window
     hMenuBar as word,_         'handle of menubar
     results as ushort          'returns nonzero if successful



___________________________________________________
Menu API calls:  intermediate 

It is not difficult to manipulate MENU ITEMS and SUBMENUS.
FOR ALL API CALLS:  If the flag _MF_BYCOMMAND is set, the 
parameter indicates the handle (ID) of the MENU ITEM.  If 
the flag  _MF_BYPOSITIOIN is set, the parameter indicates 
the position of the item, with 0 being the first position, 
1 being the second position and so on.  If neither of these 
flags is set by the programmer, the default _MF_BYCOMMAND, 
is in effect.  Note also that flags are joined together with 
the word "or" and contain an underscore as the first character.

Change string$
To change the string or text of a MENU ITEM, make a call to 
ModifyMenu.  This call can change other attributes as well, 
as you will see later.  This example  changes the string of 
the MENU ITEM to be "I was changed!"

[change.menu.item.string]
    Menu.Name$="I was changed!"
    menu.flags=_MF_STRING or _MF_BYCOMMAND
    calldll #user, "ModifyMenu",_
        hSubMenu as word,_   'handle of SubMenu from GetSubMenu
        menu.id  as word,_      'ID of menu item, from GetMenuItemID
        menu.flags as word,_   '_MF_STRING OR _MF_BYCOMMAND
        menu.id  as word,_      'ID of menu item, from GetMenuItemID
        Menu.Name$ as ptr,_  'new string$ - name of menu item
        result as ushort           'returns nonzero if successful


The same call to ModifyMenu can also be used to change the 
string on a SubMenu - the text that names the menu on the 
Menu Bar.  The first parameter to pass is then the handle 
of the Menu Bar that you got with a call to GetMenu.  Then, 
instead of the Menu Item ID that was used in the previous call, 
pass the handle of the SubMenu.

[change.submenu.string]
    Menu.Name$="I was changed!"
    menu.flags=_MF_STRING or _MF_BYCOMMAND
calldll #user, "ModifyMenu",_
  hMenu as word,_          'handle of Menu Bar
  hSubMenu as word,_    'handle of SubMenu 
  menu.flags as word,_    ' _MF_STRING OR _MF_BYCOMMAND
  hSubMenu as word,_    'handle of SubMenu 
  Menu.Name$ as ptr,_   'new string$ - name of SubMenu
  results as ushort          'returns nonzero if successful

NOTE:
You may also call ChangeMenu, but this function has been replaced 
by the function ModifyMenu.

[change.menu]
change.flags=_MF_CHANGE or _MF_STRING or _MF_BYCOMMAND
NewName$="I was changed!"

calldll #user,  "ChangeMenu", _
  hMenu as word, _         'handle of Menu Bar
  hSubMenu as word, _    'handle of SubMenu to change
  NewName$ as ptr, _      'new string
  hSubMenu as word, _    'handle of SubMenu to change
  change.flags as word, _  'flags needed for the call
  result as word



 
Enable/disable menu items.
EnableMenuItem can be one of the most useful of the menu api 
calls.  You would want to disable a menu item at the start of 
a program, if that routine is not available until other functions 
have been performed.  For instance, if no file is loaded, the 
menu item "Save" could be disabled, to indicate to the user that 
there is nothing yet to save.  A disabled menu item appears in 
gray, rather than black. Once a file is loaded, the "Save" menu 
item could be enabled.

[enable.menuitem]
menu.flag = _MF_DISABLED     ' disables the item
calldll #user, "EnableMenuItem", _
    hSubMenu as word,_   'handle of SubMenu that contains the Menu Item
    menu.id as word,_       'ID of menu item
    menu.flag as word,_     'enabled = _MF_ENABLED
    Menu.enabled.return as word     'returns previous state of menu item



Check menu items.
It is quite easy to place a checkmark beside a menu item to give 
the user information about which program choices are in force.  
Make a call to CheckMenuItem.  If your program was made for 
speakers of English and speakers of German, you might have a 
menu item for each language.  The user could see which language 
was current and could choose a language by clicking on the proper 
menu item.  To make the call, you must have the handle of the 
submenu containing the items to be checked, and the ID of any 
items that might be checked.

[check.menuitem]
'wCheck=0 is value for unchecked
'wCheck=8 is value for checked

calldll #user,"CheckMenuItem",_
    hSubMenu As word,_   'handle of submenu
    menu.id As word,_       'ID of menu item
    wCheck As short,_      'checked=8, unchecked=0
    r as short



 
Menu Radio Buttons.
In the previous example, we discussed using language in a 
program, and checking the language menu items accordingly.  
Actually, there is a better way to handle this condition.  
Since only one language can be used at a time, the language 
menu items can all be part of a radio-group.  This means that 
checking one item automatically UNCHECKS the other items.  
The api call is to CheckMenuRadioItem.  You will need the 
handle of the submenu and the IDs of all menu items to begin.  
You will also need to specify  the ID of the FIRST menu item 
that is part of the radio-group, and the LAST menu item that 
is part of the radio-group.  Then you pass the ID of the menu 
item that is to be checked.


[radio.check.menuitem]
calldll #user,"CheckMenuRadioItem",_
    hSubMenu as word,_
    menu.id.first as word,_   'first item in radio group
    menu.id.last as word,_   'last item in radio group
    menu.id as word,_         'Item to be checked
    8 as short,_                  'always 8 
    r as short




Check menu items with bitmap.
There is another way to check/uncheck menu items.  You may use 
a small bmp for item-checked, item-unchecked, or both.  If you 
will be using bitmaps as checkmarks, you must first make a call 
to SetMenuItemBitmaps to specify the loaded bitmaps that will be 
used as checkmarks.  If either the hUncheckBMP or the hCheckBMP 
parameter is NULL, (null = 0) Windows displays nothing next to 
the menu item for the corresponding attribute. If both parameters 
are NULL, Windows uses the default check mark when the item is 
checked and removes the check mark when the item is unchecked.

Later,  the usual call to CheckMenuItem will check or uncheck the 
item, using the bitmaps you have set up.

Note:  bitmaps used as checkmarks should have a small width 
and height.  Try 12x12.

You may also use bitmaps for Radio Item checks, by calling 
SetMenuItemBitmaps in exactly the same way as the example below.


[set.bitmap.checkmarks]
loadbmp "check","check.bmp"
loadbmp "uncheck","uncheck.bmp"

hCheckBMP = hbmp("check")
hUnCheckBMP = hbmp("uncheck")

calldll #user,"SetMenuItemBitmaps",_
hSubMenu as word,_        'handle of submenu
menu.id as short,_        'ID of item to check/uncheck
_MF_BYCOMMAND as word,_   'use ID, not position
hCheckBMP as word,_       'handle of bmp for checked item
hUnCheckBMP as word,_     'handle of bmp for unchecked item
results as ushort


Use bitmap as menu item.
Yes, you can use a bitmap instead of a text string as a Menu 
Item.  Make a call to ModifyMenu to modify the menu item that 
will be replaced by a bitmap. If one of the flags is _MF_BITMAP 
your menu item will be the bitmap referenced.  It is best to keep 
the bitmaps used for this purpose fairly small, but even large 
ones seem to work okay.

[make.bitmap.menuitem]

loadbmp "picture","picture.bmp"
hPicture = hbmp("picture")

FLAGS = _MF_BYCOMMAND OR _MF_BITMAP
calldll #user, "ModifyMenu",_
  hSubMenu as word,_   'handle of submenu
  menu.id as word,_      'ID of menu item
  FLAGS as word,_       'flags for this call
  menu.id as word,_      'ID of menu item
  hPicture as long,_      'handle of bmp
  results as ushort

---------------------------------------------------------
(c) 1999 
Cliff Bros: brosco@orac.net.au
and
Alyce Watson:  awatson@wctc.net
---------------------------------------------------------
 Newsletter compiled and edited by: Brosco and Alyce.
 Comments, requests or corrections: Hit 'REPLY' now!
            mailto:brosco@orac.net.au
                       or
           mailto:awatson@mail.wctc.net
---------------------------------------------------------