SophiaFramework UNIVERSE 5.3 |
Let's make the flex list box control(SFZFlexListBoxControl) in the previous custom container as the figure below.
Flex list box control | |
---|---|
Flex list box control(SFZFlexListBoxControl) is the control designed to select an item among the item list. It has more advanced function such as handling the image than SFZListBoxControl. For more details, see SFZFlexListBoxControl. |
The following is the code to make the flex list box control in "CustomContainer".
Example 3.54. Make the flex list box control
// define the CustomContainer class SFMTYPEDEFRESPONDER(CustomContainer) // macro to generate the useful types class CustomContainer : public SFYContainer { SFMSEALRESPONDER(CustomContainer) // macro to prohibit the developer from copying this instance // macro to specify the inheritance relation from SFYResponder to this class SFMRESPONDERINSTANTIATETHREE(CustomContainer, SFYContainer, SFYWidget, SFYResponder) public: // since 4-character type of small alphabet and symbol is reserved // define ('C', 'C', 'T', 'N') of capital alphabets for CustomContainer type enum CodeEnum { CODE_TYPE = four_char_code('C', 'C', 'T', 'N') }; SFMTYPEDEFTYPE(CodeEnum) public: static CustomContainerSmp NewInstance(SFCErrorPtr exception = null); // *** added code segments are in bold // make flex list box control SFCError Make(Void); protected: explicit CustomContainer(Void) static_throws; virtual ~CustomContainer(Void); // drawing handler virtual Void HandleRenderRequest(SFXGraphicsPtr graphics) const; private: // result handler of the flex list box control XANDLER_DECLARE_VOIDRESULT(OnListResult) }; // make flex list box control SFCError CustomContainer::Make(Void) { SFZFlexListBoxControlSmp list; SFZFlexListBoxControl::ItemRec item; SFBShellSmp shell(SFBShell::GetInstance()); SFBImageSmp normal(shell->LoadResImage("helloworld.bar", IDI_OBJECT_5001)); SFBImageSmp select(shell->LoadResImage("helloworld.bar", IDI_OBJECT_5002)); SFCError error(SFERR_NO_ERROR); // create the flex list box control if ((list = SFZFlexListBoxControl::NewInstance(&error)) != null) { // set the flex list box control's parent responder to the container if ((error = list->SetParent(GetThis())) == SFERR_NO_ERROR) { // register the result handler into flex list box control error = list->RegisterHandler( SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END), XANDLER_INTERNAL(OnListResult) ); if (error == SFERR_NO_ERROR) { // set the background color of even numbered items list->SetEvenListColor(SFXRGBColor(0xFF, 0xFF, 0xCC, 0x00)); // set the background color of odd numbered items list->SetOddListColor(SFXRGBColor(0xFF, 0xCC, 0xFF, 0x00)); // set the default horizontal alignment to "center-aligned" list->SetHorizontalAlign(SFZFlexListBoxControl::NORMAL, SFZFlexListBoxControl::HORIZONTAL_CENTER); // set repeat-scroll flag to "false" list->SetScrollRepeat(false); // set the scroll bar's width to 5 list->SetScrollBarWidth(5); // set that multiple string is displayed when selected list->SetToggle(SFZFlexListBoxControl::TOGGLE_MULTIPLE_BODY_TEXT); // set the flex list box control's move-item-up key to LEFT key list->SetScrollUpKey(AVK_LEFT); // set the flex list box control's move-item-down key to RIGHT key list->SetScrollDownKey(AVK_RIGHT); // set the enable flag of access key to "true" (enabled) list->SetAccessKeyEnable(true); // append an item with the item structure // though only string can be appended, // with the item structure is recommended to append an image // set the enable flag of the item structure to "true" item.property.enable = true; // set the access key and the command ID of the item structure // (ID is not used in this case) item.property.key = 0; item.property.id = SFZFlexListBoxControl::INVALID_COMMAND_ID; // set the image of the item structure item.normal.body.icon = normal; item.select.body.icon = select; // append 10 items for (SInt32 i = 0; i < 10; ++i) { // set the text of the item structure item.normal.header.text.Set(SFXWideString::Format("%02d", i)); item.normal.body.text.Set(SFXWideString::Format("List item %02d", i)); item.select.body.text.Set(SFXWideString::Format("The item %02d is selected.", i)); // set the access key of the item structure item.property.key = AVK_0 + i; // insert the item at the tail if ((error = list->InsertLast(item)) != SFERR_NO_ERROR) { break; } } if (error == SFERR_NO_ERROR) { // set the flex list box control's real region list->SetRealBound(list->GetSuitableBound(GetLocalBound().Deflate(10, 10)).SnapCenter(GetLocalBound().GetCenter())); // set the flex list box control's state to "visible" + "active" + "enable" + "focus" together list->SetState(true, true, true, true); list->SetCurrentValue(1); // (*) // set the current value after setting the enable flag to "true" // } } } } return error; }
In default settings of SFZFlexListBoxControl, the SFEVT_KEY event of the CLEAR key will be handled by SFZFlexListBoxControl and the result event of [SFXEvent(SFEVT_RESPONDER_RESULT, SFP16_RESULT_ESCAPE, 0)] will be received when the CLEAR key is pressed.
As a result, the SFEVT_KEY event of the CLEAR key will be handled before distributed to ItsWindow. And the window will not be terminated in the current key handler of ItsWindow.
Therefore, we have to implement the result handler of SFZFlexListBoxControl to send the SFEVT_KEY event of the CLEAR key to the parent responder(ItsWindow).
Example 3.55. Implement the result handler
// result handler of the flex list box control XANDLER_IMPLEMENT_VOIDRESULT(CustomContainer, OnListResult, invoker, reason, result) { SFYResponderSmp parent; unused(invoker); unused(result); switch (reason) { // the result event will be received when the CLEAR key is pressed case SFP16_RESULT_ESCAPE: if ((parent = GetParent()) != null) { // send the CLEAR key event to the container's parent responder(ItsWindow) // * key handler of the container's parent responder(ItsWindow) will be booted up from foreground to background(in the reverse order of registration) parent->InvokeForward(SFXEvent(SFEVT_KEY, AVK_CLR, 0), false); } break; } return; }
SFYResponder::InvokeBackward / SFYResponder::InvokeForward function | |
---|---|
To send an event to the specific responder in the callback type, use the SFYResponder::InvokeBackward / SFYResponder::InvokeForward function. Different from the key event, this event will not be distributred to child responders of target responder. To distribute an event to the child responders of the target responder, use the SFYResponder::Distribute function. In this case, it is necessary to register the dispatching rule into the tracer. |
In the code below, after the custom container "CustomContainer" is made, the flex list box control will be created and placed there.
Example 3.56. Update the ItsWindow class
// update so that ItsWindow calls container's Make function SFCError ItsWindow::Make(Void) { CustomContainerSmp container; SFZContainerScrollBarControlSmp bar; SFCError error(SFERR_NO_ERROR); // create the custom container if ((container = CustomContainer::NewInstance(&error)) != null) { // set the custom container's parent responder to ItsWindow if ((error = container->SetParent(GetThis())) == SFERR_NO_ERROR) { // ...(omitted)... // set the custom container's state to "visible" + "active" + "enable" + "focus" together container->SetState(true, true, true, true); // make the flex list box control in the custom container container->Make(); } } if (error == SFERR_NO_ERROR) { // create the scroll bar control only for the container if ((bar = SFZContainerScrollBarControl::NewInstance(&error)) != null) { // ...(omitted)... } } return error; }
Let's make the tab control(SFZTabControl) and tab pages(SFZTabPage) as the figure below.
Tab control and tab page | |
---|---|
Tab control[SFZTabControl] is the control designed to manage and display the tab page(container for the tab control), its child responder, in the tabbed form. The tab part of the tab control, called "tab label", and the corresponding tab page(SFZTabPage) will behave or be drawn differently depending on the state of the tab page. For more details, see SFYTabControl. SFZTabPage is the container responder with a title image/string and a hint string, and has almost the same functionality with the general purpose container(SFZContainer). * In general, though the control does not have the container as the child responder, the tab control has the container as the tab page exceptionally. |
In the code below, the responders, MyWindow and CustomContainer, are used as tab pages by inheriting from SFZTabPage.
The following is the code to change the parent class of MyWindow and CustomContainer for SFZTabPage.
Example 3.57. Change the parent class of MyWindow and CustomContainer for SFZTabPage
// *** updated code segments are in bold // define the MyWindow class SFMTYPEDEFRESPONDER(MyWindow) // macro to generate the useful types class MyWindow : public SFZTabPage { SFMSEALRESPONDER(MyWindow) // macro to prohibit the developer from copying this instance // macro to specify the inheritance relation from SFYResponder to this class SFMRESPONDERINSTANTIATEFOUR(MyWindow, SFZTabPage, SFYContainer, SFYWidget, SFYResponder) // ... (omitted) ... }; // define the CustomContainer calss SFMTYPEDEFRESPONDER(CustomContainer) // macro to generate the useful types class CustomContainer : public SFZTabPage { SFMSEALRESPONDER(CustomContainer) // macro to prohibit the developer from copying this instance // macro to specify the inheritance relation from SFYResponder to this class SFMRESPONDERINSTANTIATEFOUR(CustomContainer, SFZTabPage, SFYContainer, SFYWidget, SFYResponder) // ... (omitted) ... };
Next, let's implement the window(TabWindow) to make the tab control.
Example 3.58. Implement TabWindow
// define TabWindow class SFMTYPEDEFRESPONDER(TabWindow) 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: // since 4-character type of small alphabet and symbol is reserved // define ('T', 'A', 'B', 'W') of capital alphabets for TabWindow type enum CodeEnum { CODE_TYPE = four_char_code('T', 'A', 'B', 'W') }; SFMTYPEDEFTYPE(CodeEnum) private: // declare the tab control SFZTabControlSmp _tab; public: static TabWindowSmp NewInstance(SFCErrorPtr exception = null); // make the tab control and the tab page SFCError Make(); protected: explicit TabWindow(Void) static_throws; virtual ~TabWindow(Void); private: // key handler XANDLER_DECLARE_BOOLEVENT(OnKey) }; // constructor TabWindow::TabWindow(Void) static_throws { if (static_try()) { // set the responder type SetType(CODE_TYPE); // register the key handler in TabWindow static_throw(RegisterHandler( SFXEventRange(SFEVT_KEY, SFEVT_KEY, SFP16_BEGIN, SFP16_END), XANDLER_INTERNAL(OnKey) )); } } // destructor TabWindow::~TabWindow(Void) { } // create TabWindow TabWindowSmp TabWindow::NewInstance(SFCErrorPtr exception) { return static_pointer_cast<TabWindow>(Factory(:: new TabWindow, exception)); } #define COLOR_TAB COLOR_WHITE // tab control's background color // make tab control and tab page on TabWindow SFCError TabWindow::Make() { MyWindowSmp myWindow; CustomContainerSmp customContainer; SFCError error(SFERR_NO_ERROR); // create the tab control if ((_tab = SFZTabControl::NewInstance(&error)) != null) { // set the tab control's parent responder to TabWindow error = _tab->SetParent(GetThis()); if (error == SFERR_NO_ERROR) { // set the tab control's real region _tab->SetRealBound(GetLocalBound()); // set the colors of the various tab control's parts _tab->SetBackgroundColor(COLOR_TAB); // draw the tab control's border line _tab->SetDrawBorder(true); // undisplay the tab control's scroll bar _tab->SetScrollBarWidth(0); _tab->SetScrollBarControl(SFYScrollBarControlSmp::EmptyInstance()); // set the maximum tabs displayed in the tab control to 2 page _tab->SetFieldValue(2); // set the tab control's state to "visible" + "active" + "enable" + "focus" together _tab->SetState(true, true, true, true); // make MyWindow(MyWindow's inheriting from parent responder is changed into SFZTabPage) if ((myWindow = MyWindow::NewInstance(&error)) != null) { // set the MyWindow's parent responder to the tab control // MyWindow's real region is automatically set to the region obtained by excluding tab label and hint region from tab control region error = myWindow->SetParent(_tab); if (error == SFERR_NO_ERROR) { // set the title text of MyWindow as tab page (this text will be dispalyed in the tab region) myWindow->SetTitle("Controls"); // set the hint text of MyWindow as tab page myWindow->SetHint("This is MyWindow"); // set the MyWindow's state to "visible" + "active" + "enable" + "unfocus" together // * this statement can be omitted since it is default setting myWindow->SetState(true, true, true, false); // make responders in MyWindow myWindow->Make(); // make CustomContainer(CustomContainer's inheriting from the parent responder has been changed into SFZTabPage) if ((customContainer = CustomContainer::NewInstance(&error)) != null) { error = customContainer->SetParent(_tab); if (error == SFERR_NO_ERROR) { // set the title text of CustomContainer as tab page (this text will be displayed in tab region) customContainer->SetTitle("Container"); // set the hint text of CustomContainer as tab page customContainer->SetHint("This is CustomContainer"); // set CustomContainer's state to "visible" + "active" + "enable" + "unfocus" together // * this statement can be omitted since it is default setting customContainer->SetState(true, true, true, false); // make responders in CustomContainer customContainer->Make(); // calculate the suitable virtual region on all tab pages automatically _tab->AdjustPages(); // select the 2nd tab page(CustomContainer) _tab->FocusPage(1); } } } } } } return error; } // key handler XANDLER_IMPLEMENT_BOOLEVENT(TabWindow, OnKey, invoker, event) { Bool result(false); unused(invoker); switch (event.GetP16()) { case AVK_CLR: // when the CLEAR key is pressed // terminate TabWindow Terminate(); result = true; break; } return result; }
The order to boot up the key handlers | |
---|---|
If more than one key handler are registered into the same responder, the key handlers will be booted up in the reverse order of registration. Reference: Key Event[from SFEVT_KEY to SFEVT_KEY_HOOK_RELEASE] |
Settings of the real region of the tab page | |
---|---|
In the tab page, when the parent responder is set to the tab control, its real region is automatically calculated and set at the same time. Therefore, there is no need to set the real region of the tab page. In the above example, by executing the _myWindow->SetParent(_tab); statement, the parent responder of _myWindow is set to _tab and the _myWindow's real region is set to the region obtained by excluding the tab region from the _tab's real region. |
Setting of the state of the tab page | |
---|---|
Immediately after creating the tab page(SFZTabPage instance), its state is automatically set to "visible" + "active" + "enable" + "unfocus" together as an initial value. In almost all cases, since this setting is enough, you don't have to set the tab page's state. |
The following is the code to display TabWindow when the "4" key is pressed in the initial screen of the helloworld applet.
Example 3.59. Update the helloworld application class
// 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; // *** added and updated code segments are in bold // TabWindow's smart pointer TabWindowSmp _tabWindow; public: static SFCInvokerPtr Factory(Void); private: explicit helloworld(Void) static_throws; virtual ~helloworld(Void); SFCError MakeMy(Void); SFCError MakeMenu(Void); SFCError MakeIts(Void); // make TabWindow SFCError MakeTab(Void); // ...(omitted)... }; // make TabWindow SFCError helloworld::MakeTab(Void) { SFCError error(SFERR_NO_ERROR); // create TabWindow if ((_tabWindow = TabWindow::NewInstance(&error)) != null) { // error = _tabWindow->SetParent(GetThis()); if (error == SFERR_NO_ERROR) { // set TabWindow's real region to device screen region _tabWindow->SetRealBound(GetLocalBound()); // set TabWindow's state to "visible" + "active" + "enable" + "focus" together _tabWindow->SetState(true, true, true, true); // make tab control, tab page, etc. _tabWindow->Make(); // move TabWindow foremost _tabWindow->ToFront(); } } return error; } // drawing handler XANDLER_IMPLEMENT_VOIDRENDER(helloworld, OnRenderRequest, invoker, reason, graphics) { unused(invoker); // responder's background is filled in the color set with SFYWidget::SetBackgroundColor()[default: white] // draw text graphics->DrawSingleText("Key 1 - Controls", SFXGrid(20, 20), GetLocalBound(), COLOR_BLACK); graphics->DrawSingleText("Key 2 - TextMenu", SFXGrid(20, 40), GetLocalBound(), COLOR_BLACK); graphics->DrawSingleText("Key 3 - Container", SFXGrid(20, 60), GetLocalBound(), COLOR_BLACK); graphics->DrawSingleText("Key 4 - TabControl", SFXGrid(20, 80), GetLocalBound(), COLOR_BLACK); return; } // key handler XANDLER_IMPLEMENT_BOOLEVENT(helloworld, OnKey, invoker, event) { Bool result(false); unused(invoker); // handle the key events when the application class has no visible child responder if (this->GetChildFront(true, false, false, false) == null) { switch (event.GetP16()) { case AVK_SELECT: Terminate(); result = true; break; case AVK_1: TRACE("key 1"); if (MakeMy() == SFERR_NO_ERROR) { result = true; } break; case AVK_2: TRACE("key 2"); if (MakeMenu() == SFERR_NO_ERROR) { result = true; } break; case AVK_3: TRACE("key 3"); if (MakeIts() == SFERR_NO_ERROR) { result = true; } break; // when the "4" key is pressed case AVK_4: TRACE("key 4"); // make TabWindow to place the tab control if (MakeTab() == SFERR_NO_ERROR) { result = true; } break; } } return result; }
Since the move-item key of the flex list box control in the above code are set to the RIGHT key and the LEFT key and the move-focus key of the tab control are also set to them by default, collision of the key settings occurs.
Therefore, let's set the move-item key of the flex list box control to the UP key and the DOWN key(default settings), if the parent responder of CustomContainer that contains the flex list box control is the tab control.
Example 3.60. Change the move-item key for the flex list box control
// make flex list box control SFCError CustomContainer::Make(Void) { SFZFlexListBoxControlSmp list; SFZFlexListBoxControl::ItemRec item; SFBShellSmp shell(SFBShell::GetInstance()); SFBImageSmp normal(shell->LoadResImage("helloworld.bar", IDI_OBJECT_5001)); SFBImageSmp select(shell->LoadResImage("helloworld.bar", IDI_OBJECT_5002)); SFCError error(SFERR_NO_ERROR); // create the flex list box control if ((list = SFZFlexListBoxControl::NewInstance(&error)) != null) { // set the flex list box control's parent responder to CustomContainer if ((error = list->SetParent(GetThis())) == SFERR_NO_ERROR) { // register the result handler into flex list box control error = list->RegisterHandler( SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END), XANDLER_INTERNAL(OnListResult) ); if (error == SFERR_NO_ERROR) { // ...(omitted)... SFYResponderSmp parent; if ((parent = GetParent()) != null) { // change the LEFT/RIGHT key settings if CustomContainer's parent is not the tab control // if it is tab control, default settings(UP key and DOWN key) are applied if (parent->GetType() != SFZTabControl::CODE_TYPE) { // set the flex list box control's move-item-up key to the LEFT key list->SetScrollUpKey(AVK_LEFT); // set the flex list box control's move-item-down key to the RIGHT key list->SetScrollDownKey(AVK_RIGHT); } } // ...(omitted)... } } } return error; }
The key handler of the MyWindow tab page will delete it from the tab control and terminate itself when the CLEAR key is pressed.
For the CustomContainer tab page, the result handler of the flex list box control will delete and terminate it from the tab control when the CLEAR key is pressed.
Example 3.61. Terminate the tab page from the tab control
// MyWindow's key handler XANDLER_IMPLEMENT_BOOLEVENT(MyWindow, OnKey, invoker, event) { Bool result(false); unused(invoker); switch (event.GetP16()) { case AVK_CLR: // delete and terminate MyWindow from the tab control Terminate(); result= true; break; } return result; } // result handler of the flex list box control XANDLER_IMPLEMENT_VOIDRESULT(CustomContainer, OnListResult, invoker, reason, result) { SFYResponderSmp parent; unused(invoker); unused(result); switch (reason) { case SFP16_RESULT_ESCAPE: if ((parent = GetParent()) != null) { if (parent->GetType() == SFZTabControl::CODE_TYPE) { // if CustomContainer's parent is tab control: // delete and terminate CustomContainer from the tab control Terminate(); } else { // if CustomContainer's parent is ItsWindow: // send the CLEAR key event to ItsWindow parent->InvokeForward(SFXEvent(SFEVT_KEY, AVK_CLR, 0), false); } } break; } return; }
The following is execution result on BREW simulator.
Reference: Tab Control and Tab Page[SFZTabControl]
Let's make the SoftKey control(SFZSoftKeyControl) in the helloworld application class(i.e., root), which will be bound with the helloworld application class(i.e., root), MyWindow, the text menu, the dialog.
SoftKey control | |
---|---|
SoftKey control(SFZSoftKeyControl) is the control designed to receive the key event[SFEVT_KEY] from SoftKey and send it as the SoftKey event[SFEVT_RESPONDER_SOFTKEY]. The SoftKey event[SFEVT_RESPONDER_SOFTKEY] will be sent only to the "active" responder, which is placed foremost among focused responders bound with the SoftKey control. When the SoftKey control is used, the key event from SoftKey will not be sent to any responder other than the SoftKey control. |
Now, let's make the SoftKey control in the helloworld application class(i.e., root), register the SoftKey handler, and bind them.
Example 3.62. Create and place the SoftKey control
// 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; // *** added code segments are in bold // smart pointer to SFZSoftKeyControl SFZSoftKeyControlSmp _softkey; public: static SFCInvokerPtr Factory(Void); private: explicit helloworld(Void) static_throws; virtual ~helloworld(Void); SFCError MakeMy(Void); SFCError MakeMenu(Void); SFCError MakeIts(Void); SFCError MakeTab(Void); SFCError MakeColorDialog(UserColorConstRef color); Void SetMenuColors(UserColorConstRef color); // register the label texts for the SoftKey menu SFCError RegisterText(Void); // make the SoftKey menu SFCError MakeSoftMenu(UInt32 key); // get the device screen region excluding the SoftKey control region SFXRectangle GetContentBound(Void) const; XANDLER_DECLARE_VOIDRENDER(OnRenderRequest) // declare the drawing handler XANDLER_DECLARE_BOOLEVENT(OnKey) // declare the key handler XANDLER_DECLARE_VOIDRESULT(OnMenuResult) // declare the result handler // SoftKey handler of the helloworld application class XANDLER_DECLARE_VOIDEVENT(OnSoftKey) // SoftKey handler of the text menu XANDLER_DECLARE_VOIDEVENT(OnMenuSoftKey) // SoftKey handler of MyWindow XANDLER_DECLARE_VOIDEVENT(OnMyWindowSoftKey) }; enum { // allocate the identifier to the SoftKey menu KEY_MENU_TOP = 1, KEY_MENU_WINDOW, KEY_MENU_TEXTMENU, KEY_MENU_DIALOG }; // constructor helloworld::helloworld(Void) static_throws { if (static_try()) { static_throw(RegisterHandler( SFXEventRange(SFEVT_RESPONDER_RENDER, SFEVT_RESPONDER_RENDER, SFP16_RENDER_REQUEST, SFP16_RENDER_REQUEST), XANDLER_INTERNAL(OnRenderRequest) )); if (static_try()) { static_throw(RegisterHandler( SFXEventRange(SFEVT_KEY, SFEVT_KEY, SFP16_BEGIN, SFP16_END), XANDLER_INTERNAL(OnKey) )); if (static_try()) { // register the SoftKey handler static_throw(RegisterHandler( SFXEventRange(SFEVT_RESPONDER_SOFTKEY, SFEVT_RESPONDER_SOFTKEY, SFP16_BEGIN, SFP16_END), XANDLER_INTERNAL(OnSoftKey) )); // create the SoftKey control if ((_softkey = SFZSoftKeyControl::NewInstance()) != null) { // set the SoftKey control's parent responder to the application class(root) static_throw(_softkey->SetParent(GetThis())); if (static_try()) { // set the SoftKey control's real region to suitable region // (to be set at the bottom in the device screen) // *** CAUTION on specification of GetSuitableBound() only for SFZSoftKeyControl: // *** 1. A rectangular region will be ignored if specified in the argument and // *** the suitable size will be calculated from the full screen region of the mobile phone gotten by calling SFXDevice::GetScreenSize(). // *** In general, the argument is not specified since it has no meaning. // *** 2. This function will return not only the suitable rectangle size but also the suitable origin position. // *** Therefore, there is no need to set the position of the real region after calling this function. _softkey->SetRealBound(_softkey->GetSuitableBound()); // set the SoftKey control's state to "visible" + "active" + "disable" + "unfocus" _softkey->SetState(true, true, false, false); // register the label texts necessary for the SoftKey control static_throw(RegisterSoftText()); if (static_try()) { // create the SoftKey menu for the helloworld(initial screen) static_throw(MakeSoftMenu(KEY_MENU_TOP)); if (static_try()) { // bind the application class(root) with the SoftKey menu of the SoftKey control static_throw(_softkey->Bind(GetThis(), KEY_MENU_TOP)); } } } } else { static_throw(SFERR_NO_MEMORY); } } } } }
CAUTION | |
---|---|
In the SFYResponder::GetSuitableBound function of the SoftKey control, the rectangular region will be ignored if specified in the argument. The suitable rectangular region will be calculated from the full screen of the mobile phone gotten by calling the SFXDevice::GetScreenSize function. The normal SFYResponder::GetSuitableBound function will return only the size of the suitable rectangular region as a result of calculation. However, in case of the SFYResponder::GetSuitableBound function of the SoftKey control, it will return not only the size but also the origin position of the suitable rectangular region. Therefore, there is no need to set the origin position of the real region after calling the SFYResponder::GetSuitableBound function. |
All label texts for the SoftKey menu such as "Exit", "Select", "Config", or "Back" are registered into the SoftKey control with the SFZSoftKeyControl::RegisterText function.
Example 3.63. Register label texts for the SoftKey menu
enum { // allocate the identifier to each label text for the SoftKey menu KEY_TEXT_EXIT = 1, KEY_TEXT_SELECT, KEY_TEXT_CONFIG, KEY_TEXT_BACK }; // register the label texts into the SoftKey control SFCError helloworld::RegisterSoftText(Void) { SFCError error(SFERR_NO_ERROR); // register the label texts into the SoftKey control one by one // * method to register them together from the resource file is also available if ((error = _softkey->RegisterText(KEY_TEXT_EXIT, "Exit")) == SFERR_NO_ERROR) { if ((error = _softkey->RegisterText(KEY_TEXT_SELECT, "Select")) == SFERR_NO_ERROR) { if ((error = _softkey->RegisterText(KEY_TEXT_CONFIG, "Config")) == SFERR_NO_ERROR) { error = _softkey->RegisterText(KEY_TEXT_BACK, "Back"); } } } return error; }
The SoftKey menus are made by the MakeSoftMenu function below.
Though only the SoftKey menu for the helloworld(initial screen) is used at present, other SoftKey menus are implemented together in this function as follows:
Example 3.64. Make the SoftKey menu
// make the SoftKey menus SFCError helloworld::MakeSoftMenu(UInt32 key) { SFCError error(SFERR_NO_ERROR); // confirm whether or not the SoftKey menu for menu key has been already made if (!_softkey->ContainsMenuKey(key)) { // create the SoftKey menu for the menu key if ((error = _softkey->CreateMenu(key)) == SFERR_NO_ERROR) { // set the label text to the SoftKey menu switch (key) { // SoftKey menu for the helloworld(initial screen) case KEY_MENU_TOP: // set the SoftKey-1's label to "Exit" _softkey->SetTextKey(key, SFZSoftKeyControl::SOFTKEY_1, KEY_TEXT_EXIT); // set the SoftKey-2's label to "Config" _softkey->SetTextKey(key, SFZSoftKeyControl::SOFTKEY_2, KEY_TEXT_CONFIG); // set SELECT key's label to "false" [nothing will be displayed] _softkey->SetEnable(key, SFZSoftKeyControl::SELECT, false); break; // SoftKey menu for the window such as MyWindow case KEY_MENU_WINDOW: // set the SoftKey-1's label to "Back" _softkey->SetTextKey(key, SFZSoftKeyControl::SOFTKEY_1, KEY_TEXT_BACK); // set the SoftKey-2's label to "Config" _softkey->SetTextKey(key, SFZSoftKeyControl::SOFTKEY_2, KEY_TEXT_CONFIG); // set the SELECT key's label to "Select" _softkey->SetTextKey(key, SFZSoftKeyControl::SELECT, KEY_TEXT_SELECT); break; // SoftKey menu for text menu case KEY_MENU_TEXTMENU: // set the SoftKey-1's label to "Exit" _softkey->SetTextKey(key, SFZSoftKeyControl::SOFTKEY_1, KEY_TEXT_EXIT); // set the SoftKey-2's label to "false" [nothing will be displayed] _softkey->SetEnable(key, SFZSoftKeyControl::SOFTKEY_2, false); // set the SELECT key's label to "Select" _softkey->SetTextKey(key, SFZSoftKeyControl::SELECT, KEY_TEXT_SELECT); break; // SoftKey menu for the dialog case KEY_MENU_DIALOG: // set the SoftKey-1's label to "false" [nothing will be displayed] _softkey->SetEnable(key, SFZSoftKeyControl::SOFTKEY_1, false); // set the SoftKey-2's label to "false" [nothing will be displayed] _softkey->SetEnable(key, SFZSoftKeyControl::SOFTKEY_2, false); // set the SELECT key's label to "Select" _softkey->SetTextKey(key, SFZSoftKeyControl::SELECT, KEY_TEXT_SELECT); break; default: error = SFERR_FAILED; // cancel to make the SoftKey menu _softkey->DestroyMenu(key); break; } } } return error; }
Since the region to be displayed is reduced by the SoftKey control's region, the real region of window(MyWindow) or the text menu(_textMenu) needs to be adjusted.
The following is the code to implement the GetContentBound function which gets the region of the device screen excluding that of the SoftKey control.
Example 3.65. Get the region of the device screen excluding that of the SoftKey control
// get the device screen region excluding the SoftKey control's region
SFXRectangle helloworld::GetContentBound(Void) const
{
SFXRectangle result;
result.Set(GetLocalBound());
result.SetBottom(_softkey->GetRealBound().GetTop());
return result;
}
For each of the other respondes(MyWindow, ItsWindow, TabWindow, text menu, dialog), processing is the same with the helloworld application class as below.
Each real region of responders other than dialog will be changed by placing the SoftKey control. Therefore, we have to set it to the suitable size by using the helloworld::GetContentBound function as the code below.
Example 3.66. Make the other responders
// MyWindow make SFCError helloworld::MakeMy(Void) { SFCError error(SFERR_NO_ERROR); if ((_myWindow = MyWindow::NewInstance(&error)) != null) { error = _myWindow->SetParent(GetThis()); if (error == SFERR_NO_ERROR) { // register the SoftKey handler error = _myWindow->RegisterHandler( SFXEventRange(SFEVT_RESPONDER_SOFTKEY, SFEVT_RESPONDER_SOFTKEY, SFP16_BEGIN, SFP16_END), XANDLER_INTERNAL(OnWindowSoftKey) ); if (error == SFERR_NO_ERROR) { // set the MyWindow's real region to the region obtained by deflating the content region(device screen region excluding the SoftKey control) by (10, 10) _myWindow->SetRealBound(GetContentBound().Deflate(10, 10)); // set the MyWindow's state to "visible" + "active" + "enable" + "focus" together _myWindow->SetState(true, true, true, true); // create SoftKey menu if ((error = MakeSoftMenu(KEY_MENU_WINDOW)) == SFERR_NO_ERROR) { // bind MyWindow with the SoftKey menu of the SoftKey control error = _softkey->Bind(_myWindow, KEY_MENU_WINDOW); if (error == SFERR_NO_ERROR) { _myWindow->ToFront(); _myWindow->Make(); } } } } } return error; } // ItsWindow make SFCError helloworld::MakeIts(Void) { // ...(omitted)... } // TabWindow make SFCError helloworld::MakeTab(Void) { // ...(omitted)... } // make the text menu SFCError helloworld::MakeMenu(Void) { SFCError error(SFERR_NO_ERROR); if ((_textMenu = SFZTextMenu::NewInstance(&error)) != null) { error = _textMenu->SetParent(GetThis()); if (error == SFERR_NO_ERROR) { error = _textMenu->RegisterHandler( SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END), XANDLER_INTERNAL(OnMenuResult) ); if (error == SFERR_NO_ERROR) { // register the SoftKey handler into the text menu error = _textMenu->RegisterHandler( SFXEventRange(SFEVT_RESPONDER_SOFTKEY, SFEVT_RESPONDER_SOFTKEY, SFP16_BEGIN, SFP16_END), XANDLER_INTERNAL(OnMenuSoftKey) ); if (error == SFERR_NO_ERROR) { // ...(omitted)... // set the text menu's real region to the content region _textMenu->SetRealBound(GetContentBound()); // set the text menu's state to "visible" + "active" + "enable" + "focus" together _textMenu->SetState(true, true, true, true); // make SoftKey men if ((error = MakeSoftMenu(KEY_MENU_TEXTMENU)) == SFERR_NO_ERROR) { // bind the text menu with the SoftKey menu of the SoftKey control error = _softkey->Bind(_textMenu, KEY_MENU_TEXTMENU); if (error == SFERR_NO_ERROR) { _textMenu->ToFront(); } } } } } } return error; } // make the dialog SFCError helloworld::MakeColorDialog(UserColorConstRef color) { SFZMessageDialogSmp dlg; SFCError error(SFERR_NO_ERROR); if ((dlg = SFZMessageDialog::NewInstance(&error)) != null) { error = dlg->SetParent(GetThis()); if (error == SFERR_NO_ERROR) { // don't register handler since this dialog does not handle the SoftKey // ...(omitted)... // set the dialog's state to "visible" + "active" + "enable" + "focus" together dlg->SetState(true, true, true, true); // make the SoftKey menu for the dialog if ((error = MakeSoftMenu(KEY_MENU_DIALOG)) == SFERR_NO_ERROR) { // bind dialog with the SoftKey menu of the SoftKey control error = _softkey->Bind(dlg, KEY_MENU_DIALOG); if (error == SFERR_NO_ERROR) { dlg->ToFront(); dlg->ScheduleTimer(500); } } } } return error; }
Next, let's implement the SoftKey handler of each responder according to the following specifications.
Active responder | |
---|---|
The responder placed foremost among focused responders bound with the SoftKey control is called as the active responder. The SoftKey event will be sent only to the active responder. |
Example 3.67. Implement the SoftKey handler
// SoftKey handler of the helloworld application class XANDLER_IMPLEMENT_VOIDEVENT(helloworld, OnSoftKey, invoker, event) { unused(invoker); switch (event.GetP16()) { case AVK_SOFT1: // terminate the helloworld applet Terminate(); break; case AVK_SOFT2: // make the text menu MakeMenu(); break; } return; } // SoftKey handler of the window XANDLER_IMPLEMENT_VOIDEVENT(helloworld, OnWindowSoftKey, invoker, event) { switch (event.GetP16()) { case AVK_SOFT1: // terminate the window invoker->Terminate(); break; case AVK_SOFT2: // make the text menu MakeMenu(); break; } return; } // SoftKey handler of the text menu XANDLER_IMPLEMENT_VOIDEVENT(helloworld, OnMenuSoftKey, invoker, event) { switch (event.GetP16()) { case AVK_SOFT1: // terminate the text menu invoker->Terminate(); break; } return; }
Now, since there is no need to terminate the helloworld applet by pushing the SELECT key in the initial screen, the key handler of the helloworld application class is updated as follows:
Example 3.68. Update the key handler of the helloworld application class
// key handler XANDLER_IMPLEMENT_BOOLEVENT(helloworld, OnKey, invoker, event) { SFYResponderSmp child; Bool result(false); unused(invoker); // handle the key event only if application class has no visible child responder // * search from 2nd foremost responder since SoftKey control is always placed foremost if ((child = GetChildForward(1, true, false, false, false)) == null) { switch (event.GetP16()) { // due to the code below, the SELECT key will not be handled #if 0 case AVK_SELECT: Terminate(); result = true; break; #endif // ...(omitted)... } } return result; }
The following is execution result on BREW simulator.
Copyright(c) 2002 - 2024 Sophia Cradle Incorporated All Rights Reserved. |