The first step of using menus is to specify them in resource files. The
main descriptor of a menu is the MENU_BAR
resource structure.
The desired menu panes (usually only one) must be listed in the titles field
of it. The txt
fields are ignored, however:
RESOURCE MENU_BAR r_myapp_menu_bar { titles= { MENU_TITLE { txt="System"; menu_pane=r_system_menu; }, MENU_TITLE { txt="App"; menu_pane=r_app_menu; }, MENU_TITLE { txt="Context"; menu_pane=r_context_menu; } }; }
The menu panes are collection of menu items. The items are listed in the items field. An item may open a cascading submenu. Cascading submenus are also menu pane resources:
RESOURCE MENU_PANE r_system_menu { items= { MENU_ITEM { command=EMyappSystemFile; txt="File"; cascade=r_system_file; }, MENU_ITEM { command=EAknCmdExit; txt="Exit"; } }; } RESOURCE MENU_PANE r_system_file { items = { MENU_ITEM { command=EMyappFileOpen; txt=”Open”; }, MENU_ITEM { command=EMyappFileSave; txt=”Save”; }, }; }
The menu bar structure then can be linked to the EIK_APP_INFO
resource,
or to an AVKON_VIEW
resource, if the application uses views:
RESOURCE EIK_APP_INFO { menubar=r_myapp_menu_bar; cba=R_AVKON_SOFTKEYS_OPTIONS_EXIT; } RESOURCE AVKON_VIEW r_browser_content_view { menubar=r_myapp_menu_bar; cba=R_AVKON_SOFTKEYS_OPTIONS_EXIT; }
A menu bar can also be referenced in AVKON_SETTING_PAGE
resource
structure:
RESOURCE AVKON_SETTING_PAGE r_slider_setting_page { label = "Slider Page label"; hint_text = "This is a long hint text message"; menubar= r_slider_page_menubar; softkey_resource = R_AVKON_SOFTKEYS_OPTIONS_BACK; type = EAknCtSlider; editor_resource_id = r_setting_app_slider; }
A menu bar resource structure can directly be passed to CAknDialog
’s ConstructL()
.
In the following example CFileOpenDialog
is derived from CAknDialog
:
TInt CFileOpenDialog::ExecuteLD() { CleanupStack::PushL( this ); ConstructL( R_FILE_OPEN_MENUBAR ); CleanupStack::Pop( this ); … return CAknDialog::ExecuteLD( R_FILE_OPEN_DIALOG ); }
In order for applications to modify the contents of the menu pane at run
time, DynInitMenuPaneL()
is called on the menu bar observer
(typically the application UI) to change the options. This function is called
every time just before a menu pane is launched, with the menu pane resource
as the function parameter.
The following example illustrates adding one item to the menu pane:
void CMyappView::DynInitMenuPaneL( TInt aResourceId, CEikMenuPane* aMenuPane ) { if ( aResourceId == R_COMMON_MENU ) { CEikMenuPaneItem::SData menuFindNext; menuFindNext.iCommandId = EMyappFindNext; menuFindNext.iCascadeId = 0; menuFindNext.iFlags = 0; menuFindNext.iText = KMyappFindNext; aMenuPane->AddMenuItemL( menuFindNext ); } }
There is the possibility to add more than one item. The resource ID parameter
of AddMenuItemsL()
must refer to a valid MENU_PANE
resource:
void CMyappAppUi::DynInitMenuPaneL( TInt aResourceId, CEikMenuPane* aMenuPane ) { if ( aResourceId == R_AVKON_FORM_MENUPANE ) { aMenuPane->AddMenuItemsL( R_GENERAL_STATUS_MENU_PANE ); } }
A new menu item can be inserted to a given position. The following example inserts a new item at the last position:
void CMyappView::DynInitMenuPaneL( TInt aResourceId, CEikMenuPane* aMenuPane ) { if ( aResourceId == R_COMMON_MENU ) { CEikMenuPaneItem::SData menuFindNext; menuFindNext.iCommandId = EMyappFindNext; menuFindNext.iCascadeId = 0; menuFindNext.iFlags = 0; menuFindNext.iText = KMyappFindNext; aMenuPane->InsertMenuItemL( menuFindNext, aMenuPane->NumberOfItemsInPane() ); } }
The following example illustrates deleting one item from the menu pane:
void CMyappAppUi::DynInitMenuPaneL( TInt aResourceId, CEikMenuPane* aMenuPane ) { if ( aResourceId == R_COMMON_MENU ) { if ( IsLastOccurrence() ) aMenuPane-> DeleteMenuItem( EMyappFindNext ); if ( IsFirstOccurrence() ) aMenuPane-> DeleteMenuItem( EMyappFindPrevious ); } }
There is the possibility to delete more than one item between the specified indexes. The example deletes all items from the menu pane:
aMenuPane->DeleteBetweenMenuItems( 0, aMenuPane->NumberOfItemsInPane() - 1 );
When a menu pane is dismissed and opened again, items not desired have to be deleted again!
In S60, dimming a menu item simply removes the item from the menu pane. The item will not be visible at all!
void CMyappView::DynInitMenuPaneL( TInt aResourceId, CEikMenuPane* aMenuPane ) { if ( aResourceId == R_COMMON_MENU ) { aMenuPane->SetItemDimmed( EMyappFindNext, IsLastOccurrence() ); aMenuPane->SetItemDimmed( EMyappFindPrevious, IsFirstOccurrence() ); } }
In S60, menu items not wanted are usually removed with SetItemDimmed()
.
The following example tests the existence of a given menu item:
void CMyappView::DynInitMenuPaneL( TInt aResourceId, CEikMenuPane* aMenuPane ) { if ( aResourceId == R_COMMON_MENU ) { TInt pos( 0 ); if ( aMenuPane->MenuItemExists( EMyappFindNext, pos ) && IsLastOccurrence() ) { aMenuPane->SetItemDimmed( EMyappFindNext, ETrue ); } } }
When an option is activated, the observer of the menu pane is fired to
handle the activated menu command ID. It is given to CAknAppUi::HandleCommandL
in
the application UI or CAknView::HandleCommandL
, if the application
view handles the commands.
Example:
void CMyAppUi::HandleCommandL( TInt aCommand ) { switch ( aCommand ) { case EEikCmdExit: { Exit(); break; } case EAknSoftkeyExit: case EAknCmdExit: { CAknEnv::RunAppShutter(); break; } case EMyappCmdDoSomething: { … break; } default: { CAknAppUi::HandleCommandL( aCommand ); break; } } }
Common command IDs can be found in files:
eikon.hrh
uikon.hrh
avkon.hrh
See also Closing menus.
Since each section of the menu pane is defined as a separate menu pane resource, application developers may combine menu panes to give the desired menu options for each application state. Each of the unique menu sections should be defined once as a menu pane resource, after which a menu bar resource may be defined for each application state that is required.
The current menu can be changed at any time by calling
iEikonEnv->AppUiFactory()->MenuBar()->SetMenuTitleResourceId();
with the new menu bar resource ID, or an existing menu can be altered by simply adding new items to it or removing existing items from it.
Menu and the application UI framework give some more support to implement
context sensitive menus. The client code can specify context menu with CEikMenuBar
’s SetContextMenuTitleResourceId()
, and then call TryDisplayContextMenuBarL()
when the menu
must be opened. The application UI base class CAknAppUi
supports
opening the context menu, if the client application forwards the command EAknSoftkeyContextOptions
to CAknAppUi::ProcessCommandL()
.
Some S60 application opens a context-sensitive, simplified menu when the
OK key is pressed. It can be achieved by opening the menu in OfferKeyEventL()
when EKeyOK
is
received.
The menu bar is shown when the user presses the Options softkey.
When a UI component implements its own menu, the menu bar can be displayed (opened) with the following code:
iMenuBar->TryDisplayMenuBarL();
This method constructs the correct menu bar and displays it.
CAknAppUi
-, CAknViewAppUi
-, CAknView
-
and CAknSettingPage
-derived classes can open the menu by
calling the base class’ ProcessCommandL()
with EAknSoftkeyOptions
.
The same stands for context menus set by SetContextMenuTitleResourceId()
,
but with the exception that they must use EAknSoftkeyContextOptions
as
parameter.
CAknDialog
-derived classes can open the menu by calling OkToExitL()
with EAknSoftkeyOptions
.
The menu bar is closed when an option is selected or is canceled by the user pressing the Cancel softkey.
When a UI component implements its own menu, the menu bar can be hidden (closed) with the following code:
iMenuBar->StopDisplayingMenuBar();
Note that in non-AppUi
or view classes, a menu calls ProcessCommandL()
of
the menu observers that implement MEikMenuObserver
. In this
case, it is the responsibility of the code handling the command to dismiss
the menu with StopDisplayingMenuBar()
.
The ProcessCommandL()
method of CAknDialog
and CAknSettingPage
stops
displaying the menu bar, thus CAknDialog
-derived classes
are advised to call the base class’ ProcessCommandL()
in
their own ProcessCommandL()
.
It is possible to enable horizontal scrolling (the so called marquee) of
long menu items that do not fit into the available width. By default, marquee
is disabled. To enable marquee, EnableMarqueeL()
must be
called with parameter ETrue
in DynInitMenuPaneL()
:
aMenuPane->EnableMarqueeL( ETrue );
There are two indication types supported:
A menu can contain indicated items in it with the following constraints:
Notice that menu pane doesn't keep a track on the status of these items
and when menu is displayed again the status will be set to the one which was
specified in the resource structure unless SetItemButtonState()
was
called. So an application is responsible for setting the right status for
those items in DynInitMenuPaneL()
using the method:
void SetItemButtonState( TInt aCommandId, TInt aButtonState );
An item with a check mark can be created by using EEikMenuItemCheckBox
flag
for the menu item. To set the item to be marked on initialization, the EEikMenuItemSymbolOn
flag
should be specified.
Here is an example for the resource structure:
… MENU_ITEM { command = ESomeCmdId; txt = qtn_some_text; flags = EEikMenuItemCheckBox | EEikMenuItemSymbolOn; } …
Here is an example on how to set the status of an item having a check mark:
void CMyAppUi::DynInitMenuPaneL( TInt aResourceId, CEikMenuPane* aMenuPane ) { if ( aResourceId == R_MYAPP_CASCADE_WEATHER ) { aMenuPane->SetItemButtonState( EMyappCmdSunny, iIsWeatherSunny? EEikMenuItemSymbolOn: EEikMenuItemSymbolIndeterminate ); } }
For the radio button group creation, the flags EEikMenuItemRadioStart
and EEikMenuItemRadioEnd
should
be used:
MENU_ITEM { command = ESomeCmdId1; txt = qtn_some_text_1; flags = EEikMenuItemRadioStart; }, MENU_ITEM { command = ESomeCmdId2; txt = qtn_some_text_2; flags = EEikMenuItemSymbolOn; }, … MENU_ITEM { command = ESomeCmdIdN; txt = qtn_some_text_n; flags = EEikMenuItemRadioEnd; }
If none of the items has EEikMenuItemSymbolOn
flag set,
then the first item in the radio button group will have indication on. If
several items in the group have this flag on, then the last one will be indicated
Here is an example of how to set the status of items in a radio button group:
void CMyAppUi::DynInitMenuPaneL( TInt aResourceId, CEikMenuPane* aMenuPane ) { if ( aResourceId == R_MYAPP_CASCADE_ORDER_DRINK ) { if ( iSelectedDrink == EMyappWater ) aMenuPane->SetItemButtonState( EMyappCmdWater, EEikMenuItemSymbolOn ); else if ( iSelectedDrink == EMyappJuice ) aMenuPane->SetItemButtonState( EMyappCmdJuice, EEikMenuItemSymbolOn ); else if ( iSelectedDrink == EMyappBeer ) aMenuPane->SetItemButtonState( EMyappCmdBeer, EEikMenuItemSymbolOn ); } }
Application-level hotkeys are not strongly connected to the Options Menu API, but one reason for mention them here is that they omit command IDs like menus.
The application UI framework enables the definition of hotkeys. A hotkey
generates a command that is handed over to the application UI’s HandleCommandL()
method.
First of all, a hotkey resource of the type HOTKEYS
must
be defined. The following example defines two hotkeys. When the user presses
Ctrl-e, it generates the command EAknCmdExit
, and when Ctrl-t,
then it generates EMyappCmdTest
. Note that these keys work
when the Ctrl is also pressed down. This is why they are listed under the
‘control’ field of HOTKEYS
.
RESOURCE HOTKEYS r_myapp_hotkeys { control = { HOTKEY { command=EAknCmdExit; key='e'; }, HOTKEY { command=EMyappCmdTest; key='t'; } }; }
Even if hotkeys are defined in EIK_APP_INFO
resource structure
of the application, they are not handled. In order the hotkeys to be handled
by the application, the derived application UI class’ ConstructL()
must
call the base class’ CreateHotKeyControlL()
method with the
ID of the HOTKEYS
resource defined in the application’s resource
file:
void CMyAppUi::ConstructL() { BaseConstructL(); … CreateHotKeyControlL( R_MYAPP_HOTKEYS ); }
Options Menu API uses standard Symbian OS error reporting mechanism. Leaves and system wide error codes as function return values are used if the error is recoverable. A client application can handle these errors similarly as a normal Symbian platform application.
Memory consumption of the Options Menu API is directly proportional to the number of menus and the number of items in each menu defined by the client.
Menu bar titles are not displayed - as stated before, menu pane resources of a menu bar are read on construction and joined to form a single menu pane. The title texts and icons are not displayed at all.
Menu pane item icons are not supported. Even if the relevant methods of CEikMenuPaneItem
are
called, icons are not displayed.
Menu item text has no size limit, but at most only the first ENominalTextLength
characters
will be displayed.
Separators are not supported.
Menu item accelerator hotkeys are not supported: CEikMenuPaneItem
’s iHotKeyCode
is
ignored. Note that this hotkey differs from the one that is defined on application-level
by the resource structure HOTKEYS
.
None.