Options Menu API: Using the Options Menu API

Specifying menus in resource files

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 );
}

Initializing menus

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.

Adding menu items

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() );
        }
    }

Removing menu items

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().

Testing the existence of menu items

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 );
            }
        }
    }

Handling command IDs

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:

See also Closing menus.

Context-sensitive 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.

Opening menus

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.

Closing menus

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().

Marquee

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 );

Indicating items

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 );

Items with a check mark

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 );
        }
    }

Radio button groups

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

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 );
    }

Error handling

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 overhead

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.

Limitations of the API

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.

Extensions to the API

None.


Copyright © Nokia Corporation 2001-2008
Back to top