PrevNextUpHome SophiaFramework UNIVERSE 5.3

9.16. Menu(Basic)

Menu is the responder designed to be placed in the root[SFZRoot].

All menus inherit from SFYMenu which provides functions to register the timer processing callback(for more details, see SFYMenu::ScheduleTimer) and handle some key events by default.

The concrete menu is the part class which can be used as it is in the applet development. On the other hand, the abstract menu is the base class to define and implement the user-defined menu.

Table 9.17. Type of concrete menu

Class name Description
SFZTextMenu Concrete class which represents a text menu.
SFZGridMenu Concrete class which represents a grid menu.
SFZFlexListMenu Concrete class which represents a flex list menu.
[Important] IMPORTANT

In the concrete menu, the SFYResponder::SetParent, SFYResponder::SetState, and SFYResponder::SetRealBound functions must be always called.

Other functions are optionally called.

* When a frame is attached to a menu with the SFYResponder::SetFrame function, calling the SFYResponder::SetRealBound function of the menu can be omitted by setting the real region of the frame with the SFYResponder::SetRealBound function since that of the menu will be internally set to the region obtained by deflating it by the frame margin.

Table 9.18. Type of abstract menu

Class name Description
SFYMenu Abstract class which represents a menu.

9.16.1. Text Menu [SFZTextMenu]

Figure 9.45. Execution Result

Execution Result

SFZTextMenu is a class to create, control, update, and destroy a menu(text menu) in text format.

There are 2 types of text menus: Page style(default) and Scroll style.

The design of a text menu can be customized using its various APIs.

A text, an icon character, or an image can be set to a text menu item.

To insert an item, use the SFZTextMenu::Insert / SFZTextMenu::InsertFirst / SFZTextMenu::InsertLast function. To remove an item, use the SFZTextMenu::Remove / SFZTextMenu::RemoveFirst / SFZTextMenu::RemoveLast function. If the SFZTextMenu::Clear function is called, all items are removed.

The selection key is set with the SFYMenu::SetSelectUpKey / SFYMenu::SetSelectDownKey / SFYMenu::SetSelectRightKey / SFYMenu::SetSelectLeftKey functions. By default, selection keys are set to the UP key, the DOWN key, the RIGHT key, the LEFT key respectively.

In the default implementation, the text menu[SFZTextMenu] will receive the following result events[SFEVT_RESPONDER_RESULT].

The developer can register handlers for these events.

If no handler is registered, the default handler will be booted up when one of the above result events is received. The default handler only closes the menu.

The operation key of the menu is set with the SFYMenu::SetOperateKey function. By default, the operation key is set to the SELECT key.

The access key is set with the SFZTextMenu::SetItemAccessKey function.

The ESCAPE key is set with the SFYMenu::SetEscapeKey function. By default, the ESCAPE key is set to the CLEAR key.

[Caution] Caution
The result event will not occur when the enable flag of selected item is set to "false" with the SFZTextMenu::SetItemEnable function.
[Note] Note
The timer processing callback scheduled with the SFYMenu::ScheduleTimer function will be canceled automatically when the operation key of the menu or the ESCAPE key is pressed.

Reference: Result Event[SFEVT_RESPONDER_RESULT] | SFZTextMenu::HandleOperateKey | SFZTextMenu::HandleEscapeKey | SFZTextMenu::HandleSelectUpKey | SFZTextMenu::HandleSelectDownKey | SFZTextMenu::HandleSelectRightKey | SFZTextMenu::HandleSelectLeftKey

Example 9.76. Declaration

SFMTYPEDEFCLASS(USRApplication)
class USRApplication: public SFYApplication {
    SFMSEALCOPY(USRApplication)
private:
    SFZTextMenuSmp _menu;

    ...
private:
    SFCError Make(Void);

    // result handler which means that text menu item is selected
    XANDLER_DECLARE_VOIDRESULT(OnResult)
};

Example 9.77. Implementation

SFCError USRApplication::Make(Void)
{
    SFXRectangle rectangle;
    SInt16 i;
    SFCError error(SFERR_NO_ERROR);

    // create the text menu
    if ((_menu = SFZTextMenu::NewInstance(&error)) != null) {
        error = _menu->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {

            // register the result handler to be booted up when an item of the text menu is selected
            error = _menu->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
                XANDLER_INTERNAL(OnResult)
            );
            if (error == SFERR_NO_ERROR) {

                // set the text menu title
                // * SFXWideString text can be set from the resource file
                error = _menu->SetTitle("Text Menu");
                if (error == SFERR_NO_ERROR) {
                    for (i = 0; i < 3; ++i) {

                        // append the specified item onto the text menu
                        // * SFXWideString text can be set from the resource file
                        error = _menu->InsertLast(SFXWideString::Format("Menu item %d", i));

                        if (error != SFERR_NO_ERROR) break;
                    }
                    if (error == SFERR_NO_ERROR) {

                        // place the text menu at the center of the screen

                        // calculate the suitable text menu region size
                        rectangle.Set(_menu->GetSuitableBound(GetLocalBound().Deflate(10, 0)));
                        rectangle.SetHeight(_menu->GetTitleHeight() + 3 * _menu->GetItemHeight());

                        // place the text menu at the center of the screen
                        rectangle.SnapCenterMiddle(GetLocalBound().GetCenterMiddle());

                        // set the text menu's real region
                        _menu->SetRealBound(rectangle);

                        // Calculate the suitable width of the menu region within the hint region obtained by deflating the screen device region by (10, 10)
                        // and set the height of the menu to "header height + 3 * item height", which will be aligned at the center and the middle of the hint region.
                        // Set the menu's real region to it.
                        _menu->SetRealBound(_menu->GetSuitableBound(GetLocalBound().Deflate(10, 10).SetHeight(_menu->GetTitleHeight() + 3 * _menu->GetItemHeight()), 
                                               SFYResponder::HORIZONTAL_CENTER, 
                                               SFYResponder::VERTICAL_MIDDLE));

                        // set the text menu's state to "visible" + "active" + "enable" + "focus" together
                        _menu->SetState(true, true, true, true);

                        // move the text menu foremost
                        _menu->ToFront();
                    }
                }
            }
        }
    }

    return error;
}

// result handler to be booted up when an item of the text menu is selected
XANDLER_IMPLEMENT_VOIDRESULT(USRApplication, OnResult, invoker, reason, result)
{
    SFXWideString text;

    // menu will be passed via the invoker argument
    // the P16 value of the result event will be passed via the reason argument

    switch (reason) {

        case SFP16_RESULT_OK:  // when the operation key is pressed[item needs to be enabled with SetItemEnable()]

            // the index of the selected item will be passed via the result argument

            // get the text of the selected item
            text = _menu->GetItemText(result);
            // display it on BREW Output Window
            TRACE("%S", text.GetCString());
            break;

        case SFP16_RESULT_ESCAPE:  // when the ESCAPE key is pressed or the time scheduled with ScheduleTimer() elapses

            // 0 will be passed via the result argument

            // close the menu
            invoker->Terminate();  
            // or "_menu->Terminate();"

            break;
    }

    return;
}

9.16.2. Grid Menu [SFZGridMenu]

Figure 9.46. Execution Result

Execution Result

SFZGridMenu is a class to create, control, update, and destroy a menu(grid menu) in matrix format.

Each cell of grid menu has the same size, which is automatically set based on the size of real region and the number of rows and colums.

The design of a grid menu can be customized with its various APIs.

A text or an image can be set to a grid menu item.

To insert an item, use the SFZGridMenu::Insert / SFZGridMenu::InsertFirst / SFZGridMenu::InsertLast function. To remove an item, use the SFZGridMenu::Remove / SFZGridMenu::RemoveFirst / SFZGridMenu::RemoveLast function. If the SFZGridMenu::Clear function is called, all items are removed.

The selection key is set with the SFYMenu::SetSelectUpKey / SFYMenu::SetSelectDownKey / SFYMenu::SetSelectRightKey / SFYMenu::SetSelectLeftKey functions. By default, selection keys are set to the UP key, the DOWN key, the RIGHT key, the LEFT key respectively.

In the default implementation, the grid menu[SFZGridMenu] will receive the following result events[SFEVT_RESPONDER_RESULT].

The developer can register handlers for these events.

If no handler is registered, the default handler will be booted up when one of the above result events is received. The default handler only closes the menu.

The operation key of the menu is set with the SFYMenu::SetOperateKey function. By default, the operation key is set to the SELECT key.

The access key is set with the SFZGridMenu::SetItemAccessKey function.

The ESCAPE key is set with the SFYMenu::SetEscapeKey function. By default, the ESCAPE key is set to the CLEAR key.

[Note] Note
The timer processing callback scheduled with the SFYMenu::ScheduleTimer function will be canceled automatically when the operation key of the menu or the ESCAPE key is pressed.

Reference: Result Event[SFEVT_RESPONDER_RESULT] | SFZGridMenu::HandleOperateKey | SFZGridMenu::HandleSelectUpKey | SFZGridMenu::HandleSelectDownKey | SFZGridMenu::HandleSelectRightKey | SFZGridMenu::HandleSelectLeftKey

Example 9.78. Declaration

SFMTYPEDEFCLASS(USRApplication)
class USRApplication: public SFYApplication {
    SFMSEALCOPY(USRApplication)
private:
    SFZGridMenuSmp _menu;

    ...
private:
    SFCError Make(Void);

    // result handler which means that grid menu is selected
    XANDLER_DECLARE_VOIDRESULT(OnResult)
};

Example 9.79. Implementation

SFCError USRApplication::Make(Void)
{
    SFBShellSmp shell;
    SFBImageSmp image;
    SFBImageSmp selectedImage;
    SInt16 i;
    SFCError error(SFERR_NO_ERROR);

    // create grid menu
    if ((_menu = SFZGridMenu::NewInstance(&error)) != null) {
        error = _menu->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {

            // register the result handler which means that grid menu item is selected
            error = _menu->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
                XANDLER_INTERNAL(OnResult)
            );
            if (error == SFERR_NO_ERROR) {

                // set grid menu title
                // * SFXWideString text can be set from the resource file
                error = _menu->SetTitle("Text Menu");
                if (error == SFERR_NO_ERROR) {

                    // set the text color of grid menu title to white color
                    _menu->SetTitleForeColor(SFXRGBColor(0xFF, 0xFF, 0xFF, 0x00));

                    // set background color of grid menu title to blue color
                    _menu->SetTitleBackColor(SFXRGBColor(0x00, 0xBF, 0xF3, 0x00));

                    // set numbers of rows and colums of grid menu
                    _menu->SetRowCol(4, 3);

                    // get SFBShell instance
                    shell = SFBShell::GetInstance();
                    if (shell != null) {
                        for (i = 0; i < 12; ++i) {

                            // get image for unselected grid menu item from the resource file and ID
                            image = shell->LoadResImage(NEWWORLD_RES_FILE, IDI_OBJECT_5001 + i);

                            // get image for selected grid menu item
                            selectedImage = shell->LoadResImage(MENU_RES_FILE, IDI_OBJECT_5001 + i);

                            // append grid menu item
                            // * SFXWideString text can be set from the resource file
                            error = _menu->InsertLast(SFXWideString::Format("%d", i), image, selectedImage);

                            if (error != SFERR_NO_ERROR) break;
                        }

                        if (error == SFERR_NO_ERROR) {

                            // display grid menu item's name
                            _menu->SetDrawItemText(true);

                            // set grid menu's real region to device screen
                            _menu->SetRealBound(GetLocalBound());

                            // set grid menu's state to "visible" + "active" + "enable" + "focus" together
                            _menu->SetState(true, true, true, true);

                            // move grid menu foremost
                            _menu->ToFront();
                        }
                    }
                }
            }
        }
    }

    return error;
}

// result handler which means that grid menu item is selected
XANDLER_IMPLEMENT_VOIDRESULT(USRApplication, OnResult, invoker, reason, result)
{
    // menu will be passed via the invoker argument
    // the P16 value of the result event will be passed via the reason argument

    switch (reason) {

        case SFP16_RESULT_OK:  // when the operation key is pressed

            // the index of the selected item will be passed via the result argument

            // display index of selected item on BREW Output Window
            TRACE("%d", result);
            break;

        case SFP16_RESULT_ESCAPE:  // when the ESCAPE key is pressed or the time scheduled with ScheduleTimer() elapses

            // 0 will be passed via the result argument

            // close the menu
            invoker->Terminate();  
            // or "_menu->Terminate();"

            break;
    }

    return;
}

9.16.3. Abstract Class that Represents a Menu [SFYMenu]

SFYMenu is the abstract base class for all menus.

For instance, a menu such as SFZTextMenu, SFZGridMenu or SFZFlexListMenu is implemented by inheriting from SFYMenu.

In SFYMenu, there are functions to close itself after the specified period, implement some default handlers(virtual functions), and handle key events of menu operation, ESCAPE, and scroll keys.

The selection key is set with the SFYMenu::SetSelectUpKey / SFYMenu::SetSelectDownKey / SFYMenu::SetSelectRightKey / SFYMenu::SetSelectLeftKey functions. By default, selection keys are set to the UP key, the DOWN key, the RIGHT key, the LEFT key respectively.

In the default implementation, the abstract menu[SFYMenu] will receive the following result events[SFEVT_RESPONDER_RESULT].

The developer can register handlers for these events.

If no handler is registered, the default handler will be booted up when one of the above result events is received. The default handler only closes the menu.

The operation key of the menu is set with the SFYMenu::SetOperateKey function. By default, the operation key is set to the SELECT key.

The ESCAPE key is set with the SFYMenu::SetEscapeKey function. By default, the ESCAPE key is set to the CLEAR key.

[Note] Note
The timer processing callback scheduled with the SFYMenu::ScheduleTimer function will be canceled automatically when the operation key of the menu or the ESCAPE key is pressed.

Reference: Result Event[SFEVT_RESPONDER_RESULT] | SFYMenu::HandleOperateKey | SFYMenu::HandleEscapeKey | SFYMenu::HandleSelectUpKey | SFYMenu::HandleSelectDownKey | SFYMenu::HandleSelectRightKey | SFYMenu::HandleSelectLeftKey

The handlers(virtual functions) below for key events on the menu operation, ESCAPE, and selection keys, region event[SFEVT_RESPONDER_BOUND], drawing event[SFEVT_RESPONDER_RENDER] are registered into SFYMenu.

In a menu inheriting from SFYMenu, the following handlers(virtual functions) will be booted up first when the event is received.

Table 9.19. Events and their Handlers

Event Handler(Virtual function) Default behaviour Override
SFEVT_KEY event of the operation key set with SFYMenu::SetOperateKey SFYMenu::HandleOperateKey Send the result event *1 Optional
SFEVT_KEY event of the ESCAPE key set with SFYMenu::SetEscapeKey SFYMenu::HandleEscapeKey Send the result event *2 Optional
SFEVT_KEY event of the UP key set with SFYMenu::SetSelectUpKey SFYMenu::HandleSelectUpKey - Optional
SFEVT_KEY event of the DOWN key set with SFYMenu::SetSelectDownKey SFYMenu::HandleSelectDownKey - Optional
SFEVT_KEY event of the RIGHT key set with SFYMenu::SetSelectRightKey SFYMenu::HandleSelectRightKey - Optional
SFEVT_KEY event of the LEFT key set with SFYMenu::SetSelectLeftKey SFYMenu::HandleSelectLeftKey - Optional
(SFEVT_RESPONDER_BOUND, SFP16_BOUND_REQUEST) event SFYWidget::HandleBoundRequest - Recommended
(SFEVT_RESPONDER_BOUND, SFP16_BOUND_OPTIMIZE) event SFYWidget::HandleBoundOptimize - Recommended
(SFEVT_RESPONDER_BOUND, SFP16_BOUND_REAL) event SFYMenu::HandleBoundReal Adjust virtual region *3 Optional
(SFEVT_RESPONDER_BOUND, SFP16_BOUND_VIRTUAL) event SFYWidget::HandleBoundVirtual - Optional
(SFEVT_RESPONDER_BOUND, SFP16_BOUND_GLOBAL) event SFYWidget::HandleBoundGlobal - Optional
(SFEVT_RESPONDER_RENDER, SFP16_RENDER_REQUEST) event SFYWidget::HandleRenderRequest - Optional

* "-" in the default behaviour column represents that nothing is implemented.

[Note] NOTE

*1. Execute SFYResponder::InvokeForward(SFXEvent(SFEVT_RESPONDER_RESULT, SFP16_RESULT_CANCEL, 0), false). Just before the SFYMenu::HandleOperateKey function is called, the timer processing callback scheduled with the SFYMenu::ScheduleTimer function will be canceled internally.

*2. Execute SFYResponder::InvokeForward(SFXEvent(SFEVT_RESPONDER_RESULT, SFP16_RESULT_ESCAPE, 0), false). Just before the SFYMenu::HandleEscapeKey function is called, the timer processing callback scheduled with the SFYMenu::ScheduleTimer function will be canceled internally.

*3. Execute SFYResponder::SetVirtualBound(SFXRectangle(SFXGrid::ZeroInstance(), GetRealBound().GetSize())).

The following is the code necessary to make the user-defined menu.

Example 9.80. Declaration

SFMTYPEDEFRESPONDER(USRMenu)
class USRMenu: public SFYMenu {
    SFMSEALRESPONDER(USRMenu)
    SFMRESPONDERINSTANTIATETHREE(USRMenu, SFYMenu, SFYWidget, SFYResponder)
public:

    // define responder type
    // small alphabet and symbol must not be used since they are reserved for SophiaFramework UNIVERSE
    enum CodeEnum {
        CODE_TYPE = four_char_code('U', 'M', 'N', 'U')
    };
    SFMTYPEDEFTYPE(CodeEnum)

public:
    static USRMenuSmp NewInstance(SFCErrorPtr exception = null);
protected:
    explicit USRMenu(Void) static_throws;
    virtual ~USRMenu(Void);

    // virtual functions defined in the parent class and recommended to be implemented
    virtual Void HandleOperateKey(Void);
    virtual Void HandleSelectUpKey(Void);
    virtual Void HandleSelectDownKey(Void);
    virtual Void HandleBoundRequest(SFXRectanglePtr rectangle) const;
    virtual Void HandleBoundOptimize(SFXRectanglePtr rectangle) const;
    virtual Void HandleBoundReal(Void);
    virtual Void HandleBoundVirtual(Void);
    virtual Void HandleRenderRequest(SFXGraphicsPtr graphics) const;
};

Example 9.81. Implementation

USRMenu::USRMenu(Void) static_throws
{
    if (static_try()) {

        // set the responder type
        SetType(CODE_TYPE);

        // here describe the initialization
    }
}

USRMenu::~USRMenu(Void)
{
    // here describe the finalization
}

USRMenuSmp USRMenu::NewInstance(SFCErrorPtr exception)
{
    return static_pointer_cast<USRMenu>(Factory(::new USRMenu, exception));
}

Void USRMenu::HandleOperateKey(Void)
{
    // here describe processing necessary when the operation key is pressed
    // in general, send event as below
    // "_select" variable represents number of selected item
    InvokeForward(SFXEvent(SFEVT_RESPONDER_RESULT, SFP16_RESULT_OK, _select), false);

    return;
}

Void USRMenu::HandleSelectUpKey(Void)
{
    // here describe processing necessary when UP key is pressed
    // example: move selected item up by one

    return;
}

Void USRMenu::HandleSelectDownKey(Void)
{
    // here describe processing necessary when DOWN key is pressed
    // example: move selected item down by one

    return;
}

Void USRMenu::HandleBoundRequest(SFXRectanglePtr rectangle) const
{
    // calculate the suitable menu size
    // set the rectangle argument to the calculated suitable menu size
    // for the rectangle argument, it is recommended to set only its size and not to change its origin in this function

    return;
}

Void USRMenu::HandleBoundOptimize(SFXRectanglePtr rectangle) const
{
    // calculate the suitable menu size within rectangular region given by the rectangle argument
    // set the rectangle argument to the calculated suitable menu size
    // for the rectangle argument, it is recommended to set only its size and not to change its origin in this function

    return;
}

Void USRMenu::HandleBoundReal(Void)
{
    // here describe the size recalculation if necessary when the real region is changed

    return;
}

Void USRMenu::HandleBoundVirtual(Void)
{
    // here describe the size recalculation if necessary when the virtual region is changed

    return;
}

Void USRMenu::HandleRenderRequest(SFXGraphicsPtr graphics) const
{
    // draw menu

    return;
}