Older Version Newer Version

swetterlin swetterlin Jan 25, 2010

 'Demo for Hiding/Showing Submenus and Command Items 

'This example illustrates how to hide submenus and reshow them when desired. The menus are created in the normal way,
'and we keep track of handles, IDs and positions to refer to later.
'Terminology: Menus are basically lists of menu items. The menu bar at the top of the window is the top-level menu.
'Its menu items are normally themselves menus and are called submenus. The menu items listed in a submenu, such as
'the File menu, normally trigger some action, such as Save File, and are called command items. However, the File
'menu could contain a submenu that opens another list. Everything is a menu item. Each menu item is either itself a menu,
'or it is a command item. Every menu except the menu bar is also a submenu. We don't deal here with hiding
'the menu bar, so everything we hide/show will either be a submenu or a command item. The distinction is important
'mainly because submenus are referred to by their handles (and normally have IDs of -1) and command items are
'referred to by their IDs (and have NULL handles).
'
'We create a File and Options menu, and two additional menus to trigger the hiding/showing of the entire Options
'menu, or the Save menu item in the File menu. Hiding/showing the Options menu illustrates how to deal with submenus.
'Hiding/showing the Save menu item illustrates how to deal with command items.

'declare major variables
global hWindow 'Windows handle to the window
global hMenuBar 'Windows handle to menu bar in window

global hFileMenu, hOptionsMenu 'Windows handles to menus we want to mess with
global menuSaveID 'ID of Save menu item
global menuFilePosition, menuSavePosition, menuOptionsPosition 'Positions of these menu items in their menus, with first menu=0
global showOptions, showSave 'Flags to indicate whether Options menu and Save menu item should be made visible
global optionsIsShowing, saveIsShowing 'Keeps track of what is actually showing now
nomainwin

[CreateWindow]
WindowWidth = 300
WindowHeight = 300
UpperLeftX = 200
UpperLeftY = 200
'Create File, Save and Options menus
menu #handle, "File", "Open", [Open], "Save", [Save]
menu #handle, "Options", "Calibrate", [Calibrate], "Reset", [Reset]
'Create menu to hide/show entire Options menu with its command items
menu #handle, "Options_Mode", "With Options",[WithOptions], "Without Options", [WithoutOptions]
'Create menu to hide/show just the Save command item in the File menu
menu #handle, "File_Mode", "With Save", [WithSave], "Without Save", [WithoutSave]

open "Test Window" for window as #handle 'Open the actual window with all menus showing

'Keep track of the position of the things that need to be modified. Note that if we were possibly
'hiding more than one menu in the menu bar, the position of our target menu might change based on
'what else we had hidden, so we would have to keep track of that.
menuOptionsPosition=1 'Options menu is second in menu bar, which is position 1 when indexed from zero
menuFilePosition=0 'File menu is first in menu bar, which is position 1 when indexed from zero
menuSavePosition=1 'Save menu item is second in File menu, which is position 1 when indexed from zero

hWindow=hwnd(#handle) 'get window handle
'Get handle to the menu bar. We could put this in a subroutine, but it will only be used once.
calldll #user32, "GetMenu",_
hWindow as ulong,_ 'window handle
hMenuBar as ulong 'returns handle of menubar

'Save handle to Options menu for later reference. Because it is a submenu (i.e. it opens another
'menu of choices) it is referred to by its handle)
hOptionsMenu=uSubMenuHandle(hMenuBar, menuOptionsPosition)
hFileMenu=uSubMenuHandle(hMenuBar, menuFilePosition)
'Save ID of Save menu item. Because it is a command item (i.e. it triggers a command, rather than
'opening another menu), it is referred to by an ID number)
menuSaveID=uMenuItemID(hFileMenu, menuSavePosition)

optionsIsShowing=1 : saveIsShowing=1 'Everything is showing at the moment
showSave=1 : showOptions=0 'Tells ConformMenusToMode to show Save and hide Options

call ConformMenusToMode 'Hide/show whatever is indicated by showSave and showOptions
print #handle, "trapclose [quit]" 'goto [quit] if window is closed

wait 'Wait for user action

[quit]
close #handle
end

'These are the actions for the File and Options menus. Here we just wait.
[Open]
wait
[Save]
wait
[Calibrate]
wait
[Reset]
wait

'The following respond to clicks in the Options Mode and Save Mode menus.
[WithOptions]
showOptions=1 : call ConformMenusToMode
wait
[WithoutOptions]
showOptions=0 : call ConformMenusToMode
wait
[WithSave]
showSave=1 : call ConformMenusToMode
wait
[WithoutSave]
showSave=0 : call ConformMenusToMode
wait

'ConformMenusToMode shows/hides whatever is indicated by showOptions and showSave
'showOptions and showSave could be made arguments here instead of global variables.
sub ConformMenusToMode
'Here we hide everything that might ever need to be hidden, and then show what we want. In this
'simple example, we could first check to see that what is now shown is supposed to be shown, but
'for a more involved case it is better to first hide everything that might need to be hidden.

'We created two different subroutines for hiding. One is for command items like Save, which
'actually trigger action and are referred to by an ID. One is for submenus like Options, which simply
'open another list of choices.
if saveIsShowing then menuOK=uHideCommandItem(hFileMenu,menuSaveID) 'Hide Save menu item, identified by the handle of
'the menu it is in and its own ID

'Hide Options menu item, identified by the handle of menu it is in and its relative postion.
'This hides the word "Options" in the menu bar and also the Calibrate and Reset command items
'that are listed ini the Options menu. Because uHideSubMenu uses the DLL RemoveMenu, rather than DeleteMenu,
'the full Options menu structure will continue to exist in memory so we can show it later.
if optionsIsShowing then menuOK=uHideSubMenu(hMenuBar, menuOptionsPosition)

'Now both Options and Save are hidden. If we want to show one, we do it here.
'For variety, we take a different approach here. For hiding, we created separate subroutines
'for command items and menus. Here, we use a single subroutine, with two different arguments, one for
'the ID and one for the handle. When showing a command item, we use the ID and dummy handle. When showing
'a submenu, we use the handle and a dummy ID.
if showSave then
menuOK=uShowMenuItem(hFileMenu, _ 'Handle to the menu that contains the Save menu item
menuSaveID, _ 'ID of the Save menu item. We use this because Save is a command item
NULL, _ 'Dummy handle for Save menu item. We use this because command items don't have handles.
"Save", _ 'Caption to use for inserted menu item. We aren't changing the caption.
menuSavePosition) 'Position in File menu to insert Save menu item.
saveIsShowing=1
else
saveIsShowing=0
end if

if showOptions then
menuOK=uShowMenuItem(hMenuBar, _ 'Handle to the menu that contains the Save menu item
-1, _ 'Dummy ID of Options menu. IDs are for command items, which this is not.
hOptionsMenu, _ 'handle to Options menu, which still exists in memory
"Options", _ 'Caption to use for inserted menu. We aren't changing the caption.
menuOptionsPosition) 'Position in menu bar to insert Options menu
optionsIsShowing=1
else
optionsIsShowing=0
end if

'The above only affected memory structures. We need to actually draw the new menu.
'This has to be done even if the window is not currently visible.
'We specify the handle of the window whose menu bar is to be redrawn.
call uDrawMenu hWindow
end sub

'-------------------------------------------------------------------------------------------
'-----The remaining subroutines are wrappers for calling Windows API functions.-------------
'-------------------------------------------------------------------------------------------
function uHideCommandItem(hParent, itemID)
'Delete the specified command item. It can later be re-inserted
'hParent is the submenu containing the item. "Parent" may not be Windows terminology.
'itemID is the ID of the item to hide by removing it
calldll #user32, "RemoveMenu",_
hParent as ulong,_ 'handle of submenu
itemID as ulong,_ 'menu item ID
_MF_BYCOMMAND as long,_ 'says we are specifying the target item by its ID, not its position
result as boolean 'nonzero=success We return this, but it probably won't be used.
uHideCommandItem=result
end function

function uHideSubMenu(hParent, position)
'Delete the specified submenu. It can later be re-inserted
'hParent is the submenu containing the item. "Parent" may not be Windows terminology.
'postion is the position of the item to hide by removing it
calldll #user32, "RemoveMenu",_
hParent as ulong,_ 'handle of menu listing the one we want to hide
position as ulong,_ 'position of menu we want to hide
_MF_BYPOSITION as long,_ 'Says we are specifying the target menu by its position
result as boolean 'nonzero=success We return this, but it probably won't be used.
uHideSubMenu=result
end function

function uShowMenuItem(hParent, itemID, hMenu, caption$, precedeNum)
'Insert a menu item that was previously deleted
'hParent is the submenu in which it will be inserted
'itemID is the item ID of the item to insert, if it is a command item; otherwise -1
'hMenu is the handle of the submenu to insert, if the item is a submenu; otherwise NULL
'caption$ is the name of the item being inserted;
'The item will be inserted prior to the item in position precedeNum (0...)--That is,
'once it is inserted it will occupy position precedeNum.
'the number of existing items.
'An alternative subroutine could be written to locate the insertion
'point by the ID of the item to be preceded, rather than by position.

'The DLL uses the following structure to contain info about the item to be shown
struct MENUITEMINFO,cbSize as ulong,fMask as ulong, _
fType as ulong,fState as ulong,wID as ulong, _
hSubMenu as ulong,hbmpChecked as ulong,hbmpUnchecked as ulong, _
dwItemData as ulong,dwTypeData$ as ptr,cch as ulong 'Note dwTypeData$ is ptr because we have text caption
MENUITEMINFO.cbSize.struct = len(MENUITEMINFO.struct) 'length of this structure
MENUITEMINFO.fMask.struct = _MIIM_ID or _MIIM_SUBMENU or _MIIM_TYPE 'Says to process ID, submenu handle and type
MENUITEMINFO.wID.struct = itemID 'ID of command item, or any value for submenu
MENUITEMINFO.fType.struct = _MFT_STRING 'type of caption is text
MENUITEMINFO.hSubMenu.struct =hMenu 'handle to submenu being inserted, or NULL if not a submenu
MENUITEMINFO.dwTypeData$.struct = caption$ 'caption for menu. This is represented in the struct as a pointer to the text
MENUITEMINFO.cch.struct = len(caption$) 'length of new caption
'we don't mess here with the struct members fState, hbmChecked, hbmpUnchecked or dwItemData.

'Actual DLL call
calldll #user32, "InsertMenuItemA",_
hParent as ulong,_ 'handle of menu into which we are inserting. "Parent" may not be Windows terminology.
precedeNum as ulong,_ 'pos of item that new item is to precede
_MF_BYPOSITION as long,_ 'Says to find locate the insertion point by position
MENUITEMINFO as struct,_ 'struct with item info
result as boolean 'nonzero=success We return this, but it probably won't be used.
uShowMenuItem=result
end function

sub uDrawMenu hWind 'Redraw menu after making modifications
calldll #user32, "DrawMenuBar",_
hWind as ulong,_ 'window handle
result as boolean 'nonzero=success We don't bother to return this
end sub

function uSubMenuHandle(hParent, subPosition) 'Return handle of submenu in specified position
'hParent is handle of the menu bar, or whatever menu contains the submenu
'subPosition is position (0...) of the desired submenu
calldll #user32, "GetSubMenu",_
hParent as ulong,_ 'menu handle
subPosition as long,_ '0-indexed pos of submenu whose handle is sought
hSub as ulong 'returns submenu handle
uSubMenuHandle=hSub
end function

function uMenuItemID(hSub, itemPosition) 'Return ID of item in submenu in menubar
'This returns -1 if the specified menu item is not a command item, so
'it is pointless to use it for submenus.
calldll #user32, "GetMenuItemID", _
hSub as ulong, _ 'handle of the submenu
itemPosition as long, _ 'position of the menu item
menuID as ulong 'the handle (or ID) of the menu item
uMenuItemID=menuID
end function