PrevNextUpHome SophiaFramework UNIVERSE 5.3

3.9. User-Defined Event

Event(SFXEvent) consists of an event type and 2 parameters(P16 parameter and P32 parameter).

There are three types of events as follows:

  1. BREW-defined event in BREW SDK
  2. Responder-defined event in SophiaFramework UNIVERSE
  3. User-defined event, which you can define and use as your own event.

User-defined event is an event in the range from SFEVT_USER_CLASS_BEGIN(0x8000) to SFEVT_USER_CLASS_END(0xFFFE), which you can define and use as your own event.

In this section, how to use the user-defined event will be described.

Reference: Event | SFCEventEnum

3.9.1. How to Use the User-Defined Event

Let's apply color scheme selected by the text menu to the SoftKey control, the tab control, and the frame of the window.

Color scheme of the responder can be changed by distributing the user-defined event with color scheme information to the responder.

Figure 3.49. How to use the user-defined event: distribute color scheme information

How to use the user-defined event: distribute color scheme information

First, let's define the user-defined event(hereafter called the SFEVT_USER_COLOR event) to distribute the custom color structure.

Concretely, we will define the SFEVT_USER_COLOR event value and the SFEVT_USER_COLOR event handler macros.

Example 3.72. Define the SFEVT_USER_COLOR event value

// SFEVT_USER: starting value of user-defined event
#define SFEVT_USER_COLOR    (SFEVT_USER + 0x0001)
#define SFP16_USER_COLOR    0

Example 3.73. Define the SFEVT_USER_COLOR event handler macros

// declaration macro
#define     XANDLER_DECLARE_VOIDUSERCOLOR(FUNCTION) \
static Bool XANDLER_FUNCTION(FUNCTION)(SFYResponderPtr invoker, SFXEventConstRef event, VoidPtr reference); \
Void FUNCTION(SFYResponderPtr invoker, UInt16 reason, UserColorPtr color);

// implementation macro
// * pointer to the UserColor structure passed as the P32 parameter
#define     XANDLER_IMPLEMENT_VOIDUSERCOLOR(TYPE, FUNCTION, INVOKER, REASON, COLOR) \
Bool XANDLER_FUNCTION(TYPE::FUNCTION)(SFYResponderPtr invoker, SFXEventConstRef event, VoidPtr reference) \
{ \
    static_cast<TYPE*>(reference)->FUNCTION(invoker, event.GetP16(), reinterpret_cast<UserColorPtr>(event.GetP32())); \
    return true; \
} \
\
Void TYPE::FUNCTION(SFYResponderPtr INVOKER, UInt16 REASON, UserColorPtr COLOR)

This handler is declared, registered, and implemented similarly to the responder-defined event as follows:

// declare the  handler for the SFEVT_USER_COLOR event
XANDLER_DECLARE_VOIDUSERCOLOR(OnColor)
// register handler for the SFEVT_USER_COLOR event 
RegisterHandler(
    SFXEventRange(SFEVT_USER_COLOR, SFEVT_USER_COLOR, SFP16_USER_COLOR, SFP16_USER_COLOR),
    XANDLER_INTERNAL(OnColor)
);
// implement handler for the SFEVT_USER_COLOR event 
XANDLER_IMPLEMENT_VOIDUSERCOLOR(helloworld, OnColor, invoker, reason, color)
{
    // ... 
    return;
}

However, the SFEVT_USER_COLOR event will not be distributed to target responders as it is.

We have to register its dispatching rule into the tracer of the distributer(SFYDistributer).

Registration of the dispatching rule into the distributer will be done in the constructor of the application class(in this case, the helloworld application class) as follows:

Example 3.74. Register the dispatching rule into the tracer of the distributer

// constructor
helloworld::helloworld(Void) static_throws
{
    if (static_try()) {

        // *** added code segments are in bold

        SFYDistributerPtr distributer;
        if ((distributer = GetDistributer()) != null) {

            // register the dispatching rule on user-defined event into the tracer of the distributer
            // * distribute to all visible responders from background to foreground with the overloading condition flag as "true"
            static_throw(distributer->RegisterTracer(
                SFXEventRange(SFEVT_USER_COLOR, SFEVT_USER_COLOR, SFP16_USER_COLOR, SFP16_USER_COLOR),
                SFYTracer::ORDER_BACKWARD, SFYTracer::STATE_VISIBLE, true
            ));

            if (static_try()) {

                //...(omitted)...

            }
        }
        else {
            static_throw(SFERR_FAILED);
        }
    }
}

Next, let's update the result handler of the text menu to distribute the SFEVT_USER_COLOR event to responders actually.

Example 3.75. Distribute the SFEVT_USER_COLOR event

// result handler of the text menu
XANDLER_IMPLEMENT_VOIDRESULT(helloworld, OnMenuResult, invoker, reason, result)
{

    // ...(omitted)...

    switch (reason) {
        case SFP16_RESULT_OK:
            TRACE("'%S' is selected", _textMenu->GetItemText(static_cast<SInt16>(result)).GetCString());
            switch (result) {
                case 0:
                case 1:
                case 2:
                case 3: {
                    SetMenuColors((color[result]));
                    MakeColorDialog(_textMenu->GetItemText(result), (color[result]));

                    // *** added code segments are in bold

                    // get the root
                    SFYResponderSmp root;
                    if ((root = GetRoot()) != null) {

                        // distribute the color scheme event at the root
                        // * give the pointer to the UserColor class as the P32 parameter
                        error = root->Distribute(
                            SFXEvent(SFEVT_USER_COLOR, SFP16_USER_COLOR, reinterpret_cast<UInt32>(&color[result]))
                        );

                    }
                    break;
                }

            }
            break;

        // ...(omitted)...
    }
    return;
}
[Note] Distribute function

To distribute an event to child responders , use Type 1 of the SFYResponder::Distribute function. In this case, it is necessary to register its dispatching rule into the tracer.

The SFYResponder::InvokeBackward / SFYResponder::InvokeForward function is used to send an event to a specific responder in the callback type. In this case, the event will not be distributed to child responders.

Reference: Handler | Handler List | Callback Type | Distribute Type | Distributer | Tracer Event | SFYResponder::InvokeForward | SFYResponder::InvokeBackward | SFYResponder::Distribute

In the end, the SFEVT_USER_COLOR event will be received by responders such as the SoftKey control, the frame of the window, or the tab control by registering its handlers into those responders.

Example 3.76. Register color scheme handlers

// define the helloworld class
SFMTYPEDEFCLASS(helloworld)  //  macro to generate the useful types
class helloworld : public SFYApplication {

    SFMSEALCOPY(helloworld)  //  macro to prohibit the developer from copying this instance
private:
    MyWindowSmp _myWindow;
    ItsWindowSmp _itsWindow;
    SFZTextMenuSmp _textMenu;
    TabWindowSmp _tabWindow;
    SFZSoftKeyControlSmp _softkey;
    SFZTitlePlainFrameSmp _windowFrame;
    SFZTitleBevelFrameSmp _dialogFrame;
public:
    static SFCInvokerPtr Factory(Void);
private:

    // ...(omitted)...

    // *** added code segments are in bold

    // color scheme handler of the SoftKey control
    XANDLER_DECLARE_VOIDUSERCOLOR(OnSoftColor)

    // color scheme handler of the window frame
    XANDLER_DECLARE_VOIDUSERCOLOR(OnWindowFrameColor)
};

// define the TabWindow class 
SFMTYPEDEFRESPONDER(TabWindow)  //  macro to generate the useful types
class TabWindow : public SFZWindow {

    SFMSEALRESPONDER(TabWindow)  //  macro to prohibit the developer from copying this instance

    // macro to specify the inheritance relation from SFYResponder to this class
    SFMRESPONDERINSTANTIATEFOUR(TabWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
public:
    enum CodeEnum {
        CODE_TYPE = four_char_code('T', 'A', 'B', 'W')
    };
    SFMTYPEDEFTYPE(CodeEnum)

private:

    SFZTabControlSmp _tab;
public:

    static TabWindowSmp NewInstance(SFCErrorPtr exception = null);
    SFCError Make();
protected:

    explicit TabWindow(Void) static_throws;
    virtual ~TabWindow(Void);
private:

    XANDLER_DECLARE_BOOLEVENT(OnKey)        // declare the key handler 

    // color scheme handler of tab control
    XANDLER_DECLARE_VOIDUSERCOLOR(OnTabColor)
};

// constructor
helloworld::helloworld(Void) static_throws
{
    if (static_try()) {

        SFYDistributerPtr distributer;
        if ((distributer = GetDistributer()) != null) {

            // set the dispatching rule of the user-defined event into the distributer's tracer
            // * distribute this event to the visible responders from background to foreground (overloading condition: true)
            static_throw(distributer->RegisterTracer(
                SFXEventRange(SFEVT_USER_COLOR, SFEVT_USER_COLOR, SFP16_USER_COLOR, SFP16_USER_COLOR),
                SFYTracer::ORDER_BACKWARD, SFYTracer::STATE_VISIBLE, true
            ));

            if (static_try()) {

                // ...(omitted)...

                if ((_softkey = SFZSoftKeyControl::NewInstance()) != null) {
                        static_throw(_softkey->SetParent(GetThis()));
                        if (static_try()) {

                            // register the color scheme handler into the SoftKey control
                            static_throw(_softkey->RegisterHandler(
                                SFXEventRange(SFEVT_USER_COLOR, SFEVT_USER_COLOR, SFP16_USER_COLOR, SFP16_USER_COLOR),
                                XANDLER_INTERNAL(OnSoftColor)
                            ));

                            if (static_try()) {

                                // ...(omitted)...

                            }
                        }
                    }
                }
                else {
                    static_throw(SFERR_NO_MEMORY);
                }
            }
        }
        else {
            static_throw(SFERR_FAILED);
        }
    }
}

// make the window frame
SFCError helloworld::MakeWindowFrame(SFXWideStringConstRef title)
{
    SFCError error(SFERR_NO_ERROR);

    if ((_windowFrame = SFZTitlePlainFrame::NewInstance(&error)) != null) {

        // register the color scheme handler into the window frame
        error = _windowFrame->RegisterHandler(
            SFXEventRange(SFEVT_USER_COLOR, SFEVT_USER_COLOR, SFP16_USER_COLOR, SFP16_USER_COLOR),
            XANDLER_INTERNAL(OnWindowFrameColor)
        );

        if (error == SFERR_NO_ERROR) {

            // ...(omitted)...

        }
    }
    return error;
}

// make the child responder(tab control) of TabWindow
SFCError TabWindow::Make()
{
    MyWindowSmp myWindow;
    CustomContainerSmp customContainer;
    SFCError error(SFERR_NO_ERROR);

    if ((_tab = SFZTabControl::NewInstance(&error)) != null) {
        error = _tab->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {

            // register the color scheme handler into the tab control
            error = _tab->RegisterHandler(
                SFXEventRange(SFEVT_USER_COLOR, SFEVT_USER_COLOR, SFP16_USER_COLOR, SFP16_USER_COLOR),
                XANDLER_INTERNAL(OnTabColor)
            );

            if (error == SFERR_NO_ERROR) {

                // ...(omitted)...

            }
        }
    }
    return error;
}

At last, let's implement the color scheme handler to update the color scheme of dialog frame.

Example 3.77. Implement the color scheme handler

// color scheme handler of the SoftKey control
XANDLER_IMPLEMENT_VOIDUSERCOLOR(helloworld, OnSoftColor, invoker, reason, color)
{
    unused(invoker);
    unused(reason);

    // set the SoftKey control's background color
    _softkey->SetBackgroundColor(color->itemBack);

    // set the SoftKey control's label color
    // * if nothing specified, SoftKey menu refers to the color of the "0" key
    // * since the color key of the SoftKey menu is not changed
    // * all SoftKey menus refer to the color of the "0" key
    _softkey->RegisterFrameColor(0, color->dark);
    _softkey->RegisterBackColor(0, color->titleBack);
    _softkey->RegisterForeColor(0, color->titleFore);

    return;
}

// color scheme handler of the window frame
XANDLER_IMPLEMENT_VOIDUSERCOLOR(helloworld, OnWindowFrameColor, invoker, reason, color)
{
    unused(invoker);
    unused(reason);

    //  set the color for the frame header
    _windowFrame->SetHeaderColor(color->titleBack);

    //  set the color for the frame title
    _windowFrame->SetTextColor(color->titleFore);

    return;
}

// color scheme handler of the tab control
XANDLER_IMPLEMENT_VOIDUSERCOLOR(TabWindow, OnTabColor, invoker, reason, color)
{
    unused(invoker);
    unused(reason);

    // set the tab control's background color
    _tab->SetBackgroundColor(color->base);

    // set the color for the tab control's hint bevel
    _tab->SetHintBevelColor(SFXBevelColor(color->light, color->base, color->dark));

    // set the color for the tab control's bevel
    _tab->SetTabBevelColor(SFXBevelColor(color->light, color->base, color->dark));

    // get all tab pages and set their tab page's titlestring color
    for (SInt16 i = 0; i < _tab->GetPageCount(); ++i) {
        SFZTabPageSmp page = _tab->GetPage(i);
        page->SetTextColor(color->selFore);
    }

    return;
}

// make the dialog
SFCError helloworld::MakeColorDialog(SFXWideStringConstRef title, UserColorConstRef color)
{
    SFZMessageDialogSmp dlg;
    SFCError error(SFERR_NO_ERROR);

    if ((error = MakeDialogFrame(title)) == SFERR_NO_ERROR) {
        if ((dlg = SFZMessageDialog::NewInstance(&error)) != null) {
            error = dlg->SetParent(GetThis());
            if (error == SFERR_NO_ERROR) {
                error = dlg->SetFrame(_dialogFrame);
                if (error == SFERR_NO_ERROR) {
                    error = dlg->RegisterHandler(
                        SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
                        XANDLER_INTERNAL(OnDialogResult)
                    );
                    if (error == SFERR_NO_ERROR) {
                        error = dlg->SetMessageText("Color Changed.");
                        if (error == SFERR_NO_ERROR) {
                            error = dlg->SetButtonText("OK");
                            if (error == SFERR_NO_ERROR) {

                                // *** added code segments are in bold

                                // set the bevel color of the frame header 
                                _dialogFrame->SetHeaderColor(SFXBevelColor(color.light, color.titleBack, color.dark));

                                // set the color of the frame title
                                _dialogFrame->SetTextColor(color.titleFore);

                                dlg->SetBackgroundColor(color.selBack);

                                // ...(omitted)...

                            }
                        }
                    }
                }
            }
        }
    }
    return error;
}
[Caution] Caution

The handler of the dialog and its frame does not set the color scheme.

This is because an event of the distribute type will not be distributed to responders created newly in the same event loop.

That is all about implementation of this sample.

The following is execution result on BREW simulator.

Figure 3.50. Color scheme: Dialog's frame and SoftKey control

Color scheme: Dialog's frame and SoftKey control

Figure 3.51. Color scheme: Window's frame and tab control

Color scheme: Window's frame and tab control

The sample code in this chapter is available at this site.