Home > Products > SophiaFramework UNIVERSE > GUI Framework of SophiaFramework 2.2

GUI Framework of SophiaFramework 2.2

  1. Outline
  2. Creating an Applet
  3. Initialization
  4. From Applet Boot to Termination
  5. Event
  6. Using Window
  7. Responder
    1. UI Components
    2. Glossary
    3. Management of Components
    4. Event Handling
    5. Rendering
    6. Component Destruction
  8. Application
    1. Starting an Applet
    2. Event Handling
    3. Closing an Applet
  9. Window
    1. Constructing a Window
    2. Event Handling
    3. Destroying a Window
    4. Types of Windows
  10. Dialog
    1. Creating a Dialog
    2. Event Handling
    3. Types of Dialog
  11. Menu
    1. Creating a Menu
    2. Event Handling
    3. Types of Menu
  12. Control
    1. Creating a Control
    2. Event Handling
    3. Types of Control

1. Outline

The GUI framework corresponds to the Application layer of SophiaFramework, and enables developers to program their applets easily and speedily.

In the standard BREW development, it is necessary to build an BREW applet by hand from scratch, first defining the AEEMod_Load function, then event handling, rendering, etc. Developers can leave all complex programming like event handling or rendering to the GUI framework of SophiaFramework.

As developers have only to program the logic specific to their BREW applets, the development efficiency can increase drastically.

The GUI framework of SophiaFramework offers a Responder class (SFRResponder) that performs all GUI-related core processes like handling and rendering. Responder corresponds to what is called a Window in Microsoft Windows programming. all GUI components such as Window, Dialog, Button, etc. are abstracted into the Responder class ( SFRResponder ).

By default SophiaFramework offers the standard GUI-related classes, such as Button ( SFRButtonControl ), Menu ( SFRTextMenu), etc. so that developers can make GUI components only by instantiating these classes and also create their specific custom UI Components by inheriting from the Responder class( SFRResponder ).


In the following chapters, you will learn how to use the GUI framework and build a BREW applet using SophiaFramework with simple examples.

Creating an Applet : Building a very simple applet that displays "Hello Brew world".

Initialization : How to initiate an applet using SophiaFramework is explained. In order to use SophiaFramework efficiently, you should understand this part first of all.

From Applet Boot to Termination : The flow of execution from applet initiation to its termination is explained with simple examples.

Types of Events and Details : Types of event used frequently in SophiaFramework are explained.

Using Windows : How to use Window and Control is explained with a simple applet that displays "Hello Brew world".


In the following chapters, you will learn each component in the Application ( GUI ) layer.

Responder : In the SophiaFramework, UI component such as Window, Button, Dialog, etc. is called as Responder. Responder offers the functions of Event Handler and Renderer, and is designed so that the codes for one Reponder can be easily reused in the implementation of another Responder.

Application : Application is a type of Responder, which is at the topmost position in the Responder ownership hierarchy and has the so-called Standard Tracer by default.

Window : Window is a type of Responder, which offers user interface like a window in the personal computer.

Dialog : Dialog is a type of Responder, which offers user interface like a dialog in the personal computer.

Menu : Menu is a type of Responder, which offers user interface like a menu in the personal computer.

Control : Control is a type of Responder, which offers user interface like a control such as botton, radio botton, check box, etc. in the personal computer.

2. Creating an Applet

Here is the minimum code necessary to run an applet developed using SophiaFramework.

#include <SophiaFramework.hpp>

SFMTYPEDEFCLASS(Demo)
class Demo : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new Demo());
    }
	
  private:
    inline Demo(Void)
    {
      return;
    }
	
    virtual inline ~Demo(Void)
    {
      return;
    }
};

SFCInvokerSPP SFCApplet::Boot(AEECLSID id)
{
  return((id == AEECLSID_DEMO) ? Demo::Constructor : NULL);
}

In the code above, an applet does nothing.

The Demo class inherits from SFRApplication that is the basis for creating an applet using SophiaFramework.

The SFCApplet::Boot() function is the applet boot loader to create the instance of the Demo class. For details, please refer to Initialization .

Let's create an applet that displays "Hello Brew world" on the handset screen using SophiaFramework.

#include <SophiaFramework.hpp>

SFMTYPEDEFCLASS(HelloBrew)
class HelloBrew : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new HelloBrew());
    }
	
  private:
    inline HelloBrew(Void)
    {
      RegisterHandler(SREVT_RESPONDER_RENDER, SRP16_RENDER_CONTENT, HANDLER_BEFORE, Update_static, this);
      return;
    }
	
    virtual inline ~HelloBrew(Void)
    {
      return;
    }
	
    static inline Bool Update_static(ConstSFUEventRef event, VoidPtr responder)
    {
      HelloBrewPtr(responder)->Update_handler(SFUGraphicsPtr(event.P32()));
      return(TRUE);
    }
	
    inline Void Update_handler(SFUGraphicsPtr graphic)
    {
      SFRApplication::ContentHandler(graphic);
      graphic->SetColor(SFUColor(0x00, 0x00, 0x00));
      graphic->DrawString("Hello Brew world.", GetContentWorld());
      return;
    }
};

SFCInvokerSPP SFCApplet::Boot(AEECLSID id)
{
  return((id == AEECLSID_HELLOBREW) ? HelloBrew::Constructor : NULL);
}

About the parts added:

  1. add the rendering handler Update_handler to draw "Hello Brew world"
  2. add the helper function Update_static to register the Update_handler
  3. register the rendering handler inside its constructor using RegisterHandler
[Note] Note 1

Update_handler is the rendering function that calls the SFRApplication::ContentHandler() function, which is the default rendering handler for the SFRApplication class.

You have to declare Update_handler explicitly when you overwrite the SFRApplication::ContentHandler() function that paints the screen in white.

Then, call the graphic->SetColor() function to set the color with an argument of the SFUColor object.

Finally, call the graphic->DrawString() funtion to draw the letters.

The graphic->DrawString() function takes a string and a rectangle as arguments and draws the string inside the rectangle, automatically inserting newline characters as needed to fit the text in the rectangle.

[Note] Note 2

Update_static is the helper function that registers the rendering handler Update_handler as a static function.

If the handler does all its processing inside a static function, it can be registered without the Update_static helper function.

In order to be able to compile and run this application, we need to create the MIF file and class ID as we do for standard BREW applets.
For details, refer to the SophiaFramework tutorial or to the BREW SDK reference.

3. Initialization

Here is the minimum code necessary to run an applet developed using SophiaFramework.

#include <SophiaFramework.hpp>

SFMTYPEDEFCLASS(Demo)
class Demo : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new Demo());
    }
	
  private:
    inline Demo(Void)
    {
      return;
    }
	
    virtual inline ~Demo(Void)
    {
      return;
    }
};

SFCInvokerSPP SFCApplet::Boot(AEECLSID id)
{
  return((id == AEECLSID_DEMO) ? Demo::Constructor : NULL);
}

The Demo class inhereting from SFRApplication class is the heart of this application, and necessary to define a static member function. The Demo object is constructed automatically only once during its initialization by the constructor of the Demo class.

The SFCApplet::Boot() function is the applet boot loader and executed first of all. This function has to be implemented by the developer and returns a pointer of the SFCInvokerSPP type, which is responsible for initializing and constructing the Demo application.

Applets created using SophiaFramework are initialized in the following order:

  1. the SFCApplet::Boot() function
  2. the function* returned by the SFCApplet::Boot() function

( * In our example, this function is Demo::Constructor(). The Demo object is constructed by the Demo::Constructor() function. )

Thanks to this structure used in SophiaFramework, it is possible to switch among multiple Class IDs and change the application for each different Class ID.

Here is a sample code to switch among multiple applets with different class IDs.

#include <SophiaFramework.hpp>

SFMTYPEDEFCLASS(Demo1)
class Demo1 : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new Demo1());
    }
	
  private:
    inline Demo1(Void)
    {
      return;
    }
	
    virtual inline ~Demo1(Void)
    {
      return;
    }
};

SFMTYPEDEFCLASS(Demo2)
class Demo2 : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new Demo2());
    }
	
  private:
    inline Demo2(Void)
    {
      return;
    }
	
    virtual inline ~Demo2(Void)
    {
      return;
    }
};

SFCInvokerSPP SFCApplet::Boot(AEECLSID id)
{
  SFCInvokerSPP  result  = NULL;

  switch (id) {
    case AEECLSID_DEMO1:
      result = Demo1::Constructor;
      break;
    case AEECLSID_DEMO2:
      result = Demo2::Constructor;
      break;
  }
  return(result);
}

4. From Applet Boot to Termination

Now you will see the steps from applet boot to its termination.

In the next sample code, when the SELECT key is pressed, the applet will terminate.

#include <SophiaFramework.hpp>

SFMTYPEDEFCLASS(QuitDemo)
class QuitDemo : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new QuitDemo());
    }
    
  private:
    inline QuitDemo(Void)
    {
      RegisterHandler(SFEVT_KEY, AVK_SELECT, HANDLER_AFTER, Key_static, this);
      return;
    }
    
    virtual inline ~QuitDemo(Void)
    {
      return;
    }
    
    static inline Bool Key_static(ConstSFUEventRef /*event*/, VoidPtr responder)
    {
      QuitDemoPtr(responder)->Key_handler();
      return(TRUE);
    }
    
    inline Void Key_handler(Void)
    {
      SFBShell::Instance()->CloseApplet(FALSE);
      return;
    }
};

SFCInvokerSPP SFCApplet::Boot(AEECLSID id)
{
  return((id == AEECLSID_QUITDEMO) ? QuitDemo::Constructor : NULL);
}

This sample program is almost the same as "Hello Brew world". The only difference is that a key handler instead of a rendering handler is registered. The points of interest here are the handler function Key_handler, the helper function Key_static, and the code for registering this handler.

When the applet is initialized, the QuitDemo application is constructed. In the constructor of the QuitDemo application, the key handler Key_handler is registered. The processing so far corresponds to the part from applet initialization to the time EVT_APP_START is received.

When the initialization is completed, EVT_APP_START event is received, but since no handler is registered, the default handler of the SFRApplication class that does nothing will be used.

Then, the applet enters into the event-waiting state. When any key is pressed, EVT_KEY event is received. If the first parameter for EVT_KEY is AVK_SELECT, the registered key handler will be executed. By calling the CloseApplet() function of the SFBShell class, the request to terminate this application is sent to the BREW shell.

As the CloseApplet() function is called, the applet enters into the termination phase, and the EVT_APP_STOP event is received. In this sample code, since no handler for EVT_APP_STOP is registered, the default handler of the SFRApplication class that does nothing will be used.

Before the destructor of the QuitDemo application is executed, all the UI components that still exist will be destroyed automatically.

Finally the applet will finish and be destroyed.

5. Event

In SophiaFramework, you can use BREW standard events, SophiaFramework extended events, and your own events customized.

The event value is of the AEEEvent type if BREW standard one, and the SFCEventEnum type if SophiaFramework extended one.

The BREW standard event such as EVT_KEY, EVT_APP_START, etc. is renamed by the SophiaFramework event name such as SFEVT_KEY, SFEVT_APP_START, etc. However, the first and the second parameter are the same with the BREW standard one.

The event type name related to Responder starts with SREVT_ and its first parameter name always starts with SRP16_.

As for BREW standard events, please refer to the BREW reference.

Here you will learn only about the events related to Responder.

In the table below, SFCEventEnum is the event type, P16 is the first parameter of the UInt16 type, and P32 is the second parameter of the Bool type, SFUGraphicsPtr, SFRDialogPtr, etc.

Type: SREVT_RESPONDER_RENDER
P16: SRP16_RENDER_INVOKE
P32: Bool type
This event starts the Renderer to redraw the Responder. P32 is always TRUE. You must not process this event. Sending this event is not recommended.
Type: SREVT_RESPONDER_RENDER
P16: SRP16_RENDER_BASE
P32: SFUGraphicsPtr type
This event starts the Renderer to redraw the Base area of the Responder. P32 is a pointer to the Graphics object. This event is used to draw the Responder. You must not send this event.
Type: SREVT_RESPONDER_RENDER
P16: SRP16_RENDER_CONTENT
P32: SFUGraphicsPtr type
This event starts the Renderer to redraw the Contents area of the Responder. P32 is a pointer to the Graphics object. This event is used to draw the Responder. You must not send this event.
Type: SREVT_RESPONDER_TERMINATE
P16: SRP16_TERMINATE_INVOKE
P32: Bool type
This event destroys the Responder object. P32 is TRUE during force destruction. You must not process this event.
Type: SREVT_RESPONDER_TERMINATE
P16: SRP16_TERMINATE_TRY
P32: Bool type
This event destroys the Responder object. P32 is an argument that controls if the Responder object is forcedly destroyed or its destruction is denied. After processing this event, the destruction is aborted if TRUE is returned, and the destruction continues if FALSE is returned. This event is propagated to all the child Responder objects in the hierarchy. If any of the child Responder objects returns TRUE, the Responder object destruction is interrupted. You must not send this event.
Type: SREVT_DIALOG
P16: UInt16 type
P32: SFRDialogPtr type
This event occurs when a key is pressed in a Dialog. In the P16 parameter, the reason why the Dialog was closed is set. In case the OK button is pressed, it is set to SRP16_OK; if the clear key is pressed, it is set to SRP16_ESCAPE. when the CLEAR key is pressed. In P32 parameter, the pointer to the Dialog object is set.
Type: SREVT_MENU
P16: UInt16 type
P32: SFRMenuPtr type
This event occurs when a key is pressed in a Menu. In the P16 parameter, the reason why the Menu is closed or, if an item is selected, its index is set. In the P32 parameter, the pointer to the Menu object is set.
Type: SREVT_CONTROL
P16: UInt16 type
P32: SFRControlPtr type
This event occurs when a key is pressed in a Control. In the P16 parameter, the Control value is set. There is a unique value for each Control. In the P32 parameter, the pointer to the Control object is set.

The SREVT_RESPONDER_RENDER rendering event can be sent with the SRP16_RENDER_INVOKE value to an application like the code below.

SFRApplicationPtr  app;

app->Invoke(SFUEvent(SREVT_RESPONDER_RENDER, SRP16_RENDER_INVOKE, TRUE));
[Tip] Tip
The above event refreshes the screen immediately, which makes the processing speed relatively slow. Therefore it may not be recommended to use this event many times.

The SRP16_RENDER_BASE and SRP16_RENDER_CONTENT events can be only received. To respond to these events, you have to register their handlers.

SFRResponderPtr  responder;

responder->RegisterHandler(SREVT_RESPONDER_RENDER, SRP16_RENDER_CONTENT,
 HANDLER_BEFORE, Update_static, responder);
[Warning] Warning
The above event can be only received. The behavior of sending this event is not defined. Therefore it may not be recommended to send this event.

The SREVT_RESPONDER_TERMINATE event is related to the destruction of the Responder object. The SRP16_TERMINATE_INVOKE event is sent to the Responder object to be destroyed.

Before the destruction of the Responder object, the SRP16_TERMINATE_TRY event is used to confirm the Responder object whether it can be destroyed or not. This process is executed inside the Responder object.

The method to receive and send this event is the same as the rendering events. There is no other way to destroy the Responder object except for using the SRP16_TERMINATE_INVOKE event.*

[Note] Note *
The object will be destroyed using the delete operator. However, the event handling system may not work correctly as a result.

The SREVT_DIALOG, SREVT_MENU and SREVT_CONTROL events can be also sent and received.

6. Using Window

Here is the sample code to display the "Hello Brew world" string in the Window object and close the Window object when the SELECT key is pressed.

#include <SophiaFramework.hpp>

SFMTYPEDEFCLASS(HelloWindow)
class HelloWindow : public SFRFrameWindow {
  public:
    inline HelloWindow(SFRApplicationPtr app) : 
	SFRFrameWindow(app, SFURect(10, 10, 100, 100))
    {
      RegisterHandler(SREVT_RESPONDER_RENDER, SRP16_RENDER_CONTENT, HANDLER_BEFORE, Update_static, this);
      RegisterHandler(SFEVT_KEY, AVK_SELECT, HANDLER_AFTER, Key_static, this);
      return;
    }
    
    virtual inline ~HelloWindow(Void)
    {
      return;
    }
    
    static inline Bool Update_static(ConstSFUEventRef event, VoidPtr responder)
    {
      HelloWindowPtr(responder)->Update_handler(SFUGraphicsPtr(event.P32()));
      return(TRUE);
    }
    
    inline Void Update_handler(SFUGraphicsPtr graphic)
    {
      SFRFrameWindow::ContentHandler(graphic);
      graphic->SetColor(SFUColor(0x00, 0x00, 0x00));
      graphic->DrawString("Hello Brew world.", GetContentWorld());
      return;
    }

    static inline Bool Key_static(ConstSFUEventRef /*event*/, VoidPtr responder)
    {
      HelloWindowPtr(responder)->Key_handler();
      return(TRUE);
    }
    
    inline Void Key_handler(Void)
    {
      Invoke(SFUEvent(SREVT_RESPONDER_TERMINATE, SRP16_TERMINATE_INVOKE, TRUE));
      return;
    }
};

SFMTYPEDEFCLASS(WindowHelloBrew)
class WindowHelloBrew : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new WindowHelloBrew());
    }
    
  private:
    inline WindowHelloBrew(Void)
    {
      new HelloWindow(this);
      return;
    }
    
    virtual inline ~WindowHelloBrew(Void)
    {
      return;
    }
};

SFCInvokerSPP SFCApplet::Boot(AEECLSID id)
{
  return((id == AEECLSID_WINDOWHELLOBREW) ? WindowHelloBrew::Constructor : NULL);
}

The rendering handler Update_handler used in this example has exactly the code as the one used in the first example. In this case the handler to render text is not in the Application class but in the Window class.

The key handler Key_handler is also registered in the Window object so that the Window object may close when the SELECT key is pressed.

Here is the sample code to display the "Hello Brew world" string and the Botton object in the Window object, and close the Window object when the SELECT key is pressed.

#include <SophiaFramework.hpp>

SFMTYPEDEFCLASS(HelloWindow2)
class HelloWindow2 : public SFRFrameWindow {
  public:
    inline HelloWindow2(SFRApplicationPtr app) : SFRFrameWindow(app, 
	SFURect(10, 10, 100, 100))
    {
      SFRControlPtr  control;
  
      RegisterHandler(SREVT_RESPONDER_RENDER, SRP16_RENDER_CONTENT, HANDLER_BEFORE, 
	  Update_static, this);
      control = new SFRButtonControl(this, SFURect(10, 70, 80, 18), "Close");
      control->RegisterHandler(SREVT_CONTROL, HANDLER_BEFORE, Control_static, this);
      return;
    }
    
    virtual inline ~HelloWindow2(Void)
    {
      return;
    }
    
    static inline Bool Update_static(ConstSFUEventRef event, VoidPtr responder)
    {
      HelloWindow2Ptr(responder)->Update_handler(SFUGraphicsPtr(event.P32()));
      return(TRUE);
    }
    
    inline Void Update_handler(SFUGraphicsPtr graphic)
    {
      SFRFrameWindow::ContentHandler(graphic);
      graphic->SetColor(SFUColor(0x00, 0x00, 0x00));
      graphic->DrawString("Hello Brew world.", GetContentWorld());
      return;
    }

    static inline Bool Control_static(ConstSFUEventRef /*event*/, VoidPtr responder)
    {
      HelloWindow2Ptr(responder)->Control_handler();
      return(TRUE);
    }
    
    inline Void Control_handler(Void)
    {
      Invoke(SFUEvent(SREVT_RESPONDER_TERMINATE, SRP16_TERMINATE_INVOKE, TRUE));
      return;
    }
};

SFMTYPEDEFCLASS(WindowHelloBrew2)
class WindowHelloBrew2 : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new WindowHelloBrew2());
    }
    
  private:
    inline WindowHelloBrew2(Void)
    {
      new HelloWindow2(this);
      return;
    }
    
    virtual inline ~WindowHelloBrew2(Void)
    {
      return;
    }
};

SFCInvokerSPP SFCApplet::Boot(AEECLSID id)
{
  return((id == AEECLSID_WINDOWHELLOBREW2) ? WindowHelloBrew2::Constructor : NULL);
}

In the code above, the control handler Control_handler is registered instead of the key handler Key_handler.

After the Window object is created, a Button object is created and pasted in the Window object.

Inside the control handler Control_handler, the SREVT_RESPONDER_TERMINATE event is sent to the Window object for destroying it.

7. Responder

In SophiaFramework, UI component such as Window or Button is referred to as Responder. By default, SophiaFramework offers Event Handler and Renderer for each Responder.

As Event Handler and Renderer are abstractly designed based on the Responder class, it is easy to reuse the codes of the Responder class. For example, when you have developed a Window class in a project, you can reuse its code in another project almost without any change.

7.1 UI Component

According to the base class inheriting from, UI component of SophiaFramework can be broadly classified into the following four categories:

  1. Application ( SFRApplication )
  2. Window ( SFRWindow )
  3. Menu ( SFRMenu )
  4. Control ( SFRControl )

UI Components are organized into the hierarchy where Responder manages Application and then Application manages Control.

SFRApplication is at the topmost position in the Responder ownership relation , and only one instance of the Application class is necessary for each applet.

Usually we start to program an Application class inheriting from the SFRApplication class.

As Application is a type of UI Component ( Responder ), you can paste any number of UI Components such as Window or Menu into it. Likewise, you can paste any number of Control into Window.

Dialog is an extension of Window, with the difference that Dialog has its own predefined Event Handler.

Diagram 1. Responder Inheritance Relation

Ui Component inherite

Diagram 2. Responder Ownership Relation

Ui Component Ownership

7.2. Glossary

Type

Responder has a so-called Type, which is a four-letter literal identifier.

Type is used to distinguish Responder such as Application, Window, etc., and can be set only when new Responder class is defined by inheriting from the SFRResponder class.

The four-letter literal of Type can be gotten by using the FOUR_CHAR_CODE macro.

[Note] Note

The lowercase literal identifiers are not allowed as Type because they are reserved to SophiaFramework.

To get the Type of Responder, you have to use the SFRResponder::GetType() function.

Attribute

Responder has a so-called Attribute, which is a four-letter literal identifier.

Attribute indicates the object type. For example, for Window, an Attribute indicates whether it has a title or not. There is also Attribute for each Control. You can override the Attribute by replacing it with your own custom one, when you create a new Responder object. Retrieval function can be easily used by overriding its Attribute.

The four-letter literal of Attribute can be gotten by using the FOUR_CHAR_CODE macro.

[Note] Note

The lowercase literal identifiers are not allowed as Attribute because they are reserved to SophiaFramework.

To get an Attribute, you have to use the SFRResponder::GetAttribute() function.

Behavior

A Responder object has a number of flags that manage their Status, Appearance and Property.

Status is anything that may change according to the user operation, like whether a Responder object is visible or not, for example.

A Property is anything that doesn't change with the user operation, like whether a Responder object is transparent or movable, for example.

Appearance and Property can be set only when the Responder object is constructed.

Status

BEHAVIOR_NONE
STATUS_VISIBLE
STATUS_ENABLE
STATUS_FOCUS
STATUS_TARGET

The STATUS_VISIBLE flag controls whether a Responder is visible or not. By default, objects will be rendered only if this flag is set.

The STATUS_ENABLE flag controls whether a Responder is enabled or not. By default, objects will respond to key events and others, only if this flag is set. This flag is also used to define whether an object can receive focus or not.

The STATUS_FOCUS flag controls whether an object has the focus or not. This flag also controls whether the object can be targeted or not.

The STATUS_TARGET flag controls whether the object is being targeted or not.

Appearance

APPEARANCE_TRANSPARENT

APPEARANCE_TRANSPAREN controls whether the UI Component has any transparent region or not. If this flag is set, a transparency-aware algorithm is used in the rendering process.

[Warning] Warning

The transparent rendering can be applied to some of the Controls such as Checkbox, Radio Button, etc. It can be also applied to Window or other types of UI Component, but the rendering process will get extremely slow.

Property

PROPERTY_DIRECT
PROPERTY_SELECT
PROPERTY_CLOSABLE
PROPERTY_MOVABLE
PROPERTY_SCROLLABLE

The PROPERTY_DIRECT flag indicates whether a Responder object can receive an event or not even if not targeted. When this flag is set, STATUS_TARGET is always set and cannot be reset by any function. The Responder objects like Control may have this flag set. For more details on targeting, please look at the figure below.

The PROPERTY_SELECT flag indicates whether a Responder object on the background will be brought to the foreground or not if targeted. In case of Responder objects like Window, this flag is set.

The PROPERTY_CLOSABLE flag indicates whether a Responder object will be destroyed or not if the "CLEAR" key is pressed. In all Responder objects, this flag is not set by default.

The PROPERTY_MOVABLE flag indicates whether a Responder object is movable or not. This flag does not apply to the case when you move a Responder object by calling the Move or GroupMove function. By default, all Responder objects are immovable.

The PROPERTY_SCROLLABLE flag indicates whether the user can scroll a Responder object in the Virtual Region or not. This flag does not apply to the case when you scroll components by calling the Scroll or GroupScroll function. By default, all Responder objects except the SFRApplication class are not scrollable.

Status transition in SophiaFramework is defined as:

When STATUS_VISIBLE is set, STATUS_ENABLE is enabled. When STATUS_ENABLE is set, STATUS_FOCUS is enabled. When STATUS_FOCUS is set, STATUS_TARGET is enabled. When STATUS_TARGET is set, the object is locked.

STATUS_TARGET is automatically set whenever PROPERTY_DIRECT is set.

The PROPERTY_CLOSABLE and PROPERTY_MOVABLE flags are automatically enabled whenever STATUS_TARGET is set. The PROPERTY_SELECT flag indicates whether a Responder object in the background will be brought to the top or not when its status turns to STATUS_TARGET.

Diagram 3. Transition from Focus to Target

SophiaFramework : Focus-Target

Region

Each Responder has three distinct regions about the rendering area and its position.

Base Region :
Indicates the Responder position. The coordinate is set relatively in the Virtual Region of the parent Responder.

Contents Region :
Indicates the region actually rendered in the Virtual Region. This region is never larger than the Base Region.

Frame Region :
Indicates the region between the Contents Region and the Base Region. When the Base Region and Contents Region are the same, there is no Frame Region.

Virtual Region :
Indicates the virtual region to be rendered. This region may be bigger than the visible region.

Diagram 4. Region

Regions

Diagram 5. Region of Window

Region with a window

7.3 Management of Component

UI Components are managed using an object search system, where Type, Attribute and Status are the search keys. This system enables you to program BREW applets abstractly as there is no need to keep a pointer to the Window or Control object.

Following are the methods to search the element by matching the Type, Attribute and Status.

  1. Get the top element
  2. Get the bottom element
  3. Get the nth element from the top one
  4. Get the nth element from the bottom one
  5. Get the next element
  6. Get the previous element
  7. Get the next element among the grouped elements
  8. Get the previous element among the grouped elements
[Note] Note

In the searching methods above, 1, 2, 3 and 4 search the element in the descendents, while 5, 6, 7 and 8 search it in the same hierarchy level.

The wildcards can be used for Type and Attribute.

To get the first visible, enabled Window object from the top, you can use the following code:

SFRResponderPtr responder;
SFRWindowPtr    window;

window = SFRWindowPtr(responder->GetFront(TYPE_WINDOW));

To get the first visible, enabled Title Window object from the top, you can use the following code:

SFRResponderPtr responder;
SFRWindowPtr    window;

window = SFRWindowPtr(responder->GetFront(TYPE_WINDOW, ATTRIBUTE_TITLEWINDOW));

To get the Window object on the top, regardless of whether it is visible or not and enabled or not, you can use this code:

SFRResponderPtr responder;
SFRWindowPtr    window;

window = SFRWindowPtr(responder->GetFront(TYPE_WINDOW, ATTRIBUTE_WILDCARD, BEHAVIOR_NONE));

To go from the topmost visisble, enabled Window object to the bottom visisble, enabled Window one, you can use this code:

SFRResponderPtr responder;
SFRWindowPtr    window, temp;

if ((window = SFRWindowPtr(responder->GetFront(TYPE_WINDOW))) != NULL) {
  // first window
  temp = window;
  while ((temp = SFRWindowPtr(temp->GetNext(TYPE_WINDOW))) != NULL && temp != window) {
    // second window or ...
  }
}

To get the third visible, enabled Title Window object from the top, you can use the following code:

SFRResponderPtr responder;
SFRWindowPtr    window;

window = SFRWindowPtr(responder->GetNth(2, TYPE_WINDOW, ATTRIBUTE_TITLEWINDOW));
[Tip] Tip

The condition expressed by the last argument is not identity, i.e., whether it matches or not. The setting flags are added to the search categories. Therefore, if we set BEHAVIOR_NONE = 0, it doesn't include any condition related to status. If we set STATUS_VISIBLE, only visibility will be considered, all other status flags being ignored. You can set flags only from STATUS_VISIBLE to STATUS_TARGET, as all the other flags will be ignored. However, in the future, more flags may be included as search conditions, therefore, avoid setting unnecessary flags.

7.4 Event Handling

Event handling is done automatically by using Tracer and Handler.

However, you should know them thoroughly in order to take much more advantage of SophiaFramework.

7.4.1 Tracer

Tracer holds the rules by which the events will be posted to each UI component.

More precisely speaking, Tracer controls how the events will be posted to the Child objects post from their Parent object.

The Tracer inheriting from the Parent class can be overridden at its Child class.

For example, the rule on the SFEVT_KEY event is that this event will be posted to the focused Responder objects in a given order. And the SFEVT_RESUME event's one is that this event will be posted to all the Responder objects.

The following are the elements of the Tracer rule:

  1. Event type and its first parameter
  2. Tracing order
  3. Forced posting
  4. Status filter
[Note] Note

Event type and its first parameter : the same as in BREW

Tracing order : a rule by which events are posted to the Child objects (without posting to the Child objects, to the focused objects, from the back object to the front one, from the front object to the back one)

Forced posting : a flag whether the Parent object continues to post the event to the Child objects or not, even after some other class has already processed the event.
* In general, there is no need to continue posting the event such as SFEVT_KEY, therefore, Forced posting is not set by default. On the other hand, since it would be inconvenient in case of the event such as SFEVT_RESUME, Forced posting is set by default.

Status filter : a filter that the event will only be received under certain status, such as visible or enabled

As the Tracer is inherited from the Parent class, most of the Tracer rules are registered in the Application class by default. Likewise, most of the Tracer rules for the events on Menu or Control are registered in the Menu or and Control class by default, respectively. To change some of the Tracer rules, you have only to register a new Tracer rule.

The default rules are as follows:

Table 1. Standard Tracer
1
Range: SFEVT_APPLICATION_CLASS_BEGIN to SFEVT_APPLICATION_CLASS_END
Posts: no
Forced: no
Status: all
2
Range: SFEVT_APP_SUSPEND
Posts: from foreground to background
Forced: yes
Status: all
3
Range: SFEVT_APP_RESUME
Posts: from foreground to background
Forced: yes
Status: all
4
Range: from SFEVT_KEY_CLASS_BEGIN to SFEVT_KEY_CLASS_END
Posts: focus
Forced: no
Status: visible, enabled, focus, and targeting (all set)
5
Range: from SFEVT_CONTROL_CLASS_BEGIN to SFEVT_CONTROL_CLASS_END
Posts: focus
Forced: no
Status: visible, enabled, focus, and targeting (all set)
6
Range: from SFEVT_DIALOG_CLASS_BEGIN to SFEVT_DIALOG_CLASS_END
Posts: focus
Forced: no
Status: visible, enabled, focus, and targeting (all set)
7
Range: from SFEVT_SHELL_CLASS_BEGIN to SFEVT_SHELL_CLASS_END
Posts: no
Forced: yes
Status: all
8
Range: from SFEVT_DEVICE_CLASS_BEGIN to SFEVT_DEVICE_CLASS_END
Posts: no
Forced: yes
Status: all
9
Range: from SFEVT_CLIPBOARD_CLASS_BEGIN to SFEVT_CLIPBOARD_CLASS_END
Posts: no
Forced: yes
Status: all
10
Range: SREVT_RESPONDER_RENDER
Posts: no
Forced: yes
Status: visible
11.1
Range: SREVT_RESPONDER_TERMINATE
Posts: no
Forced: no
Status: all
11.2
Range: SREVT_RESPONDER_TERMINATE, SRP16_TERMINATE_TRY
Posts: from foreground to background
Forced: yes
Status: all
12
Range: SREVT_MENU
Posts: no
Forced: no
Status: all
13
Range: SREVT_DIALOG
Posts: no
Forced: no
Status: all
14
Range: SREVT_CONTROL
Posts: no
Forced: no
Status: all

7.4.2 Handler

Handler holds the functions that will handle the dispatched event.

In registering the Handler function, the following elements can be set:

1: Event type and its fist parameter
2: Processing timing
[Note] Note

Event type and its first parameter : the same as in BREW

Processing timing : timing to handle an event can be set to as "before" or "after" posting it to the Child objects, by using HANLDER_BEFORE and HANDLER_AFTER.

For example, Processing time on the SFEVT_KEY event is set to "after", since its event handling starts at the focused Child object,

The figure below shows how an event is handled.

Diagram 6. The Flow of Event Handling

The flow of event handling

By default, standard handlers are provided with in the SophiaFramework, but it is also possible to define and register new custom handlers or to override handlers registered in the Parent class.

Handler must be a static member function of the following type:

Bool  (*SFRResponderSPP)  (ConstSFUEventRef event, VoidPtr reference);

Here is a sample code to register a Handler.

To register a Handler or unregister, you have to use the RegisterHandler or UnregisterHandler function, respectively.

When you register a new Handler function on a given event, existing Handlers to that event will be overridden.

Since SophiaFramework offers a great number of functions to be overloaded, the RegisterHandler and UnregisterHandler functions are easy to use.

In the code below, the SREVT_CONTROL event is handled before the Child objects, and the SFEVT_KEY to SFEVT_KEY_HELD with its first parameter (AVK_SELECT) events are handled after the Child objects.

SFRResponderPtr responder;
SFCError        error;

error = responder->RegisterHandler(SREVT_CONTROL, HANDLER_BEFORE, Control_static, this);
SFRResponderPtr responder;
SFCError        error;

error = responder->RegisterHandler(SFEVT_KEY, SFEVT_KEY_HELD, AVK_SELECT, HANDLER_AFTER, Key_static, this);

Here is a sample code to use a Handler, which must be declared as a static member function:

inline SomeClass::SomeClass(Void)
{
  RegisterHandler(SFEVT_KEY, HANDLER_AFTER, Key_static, this);
  return;
}

static inline Bool Key_static(ConstSFUEventRef event, VoidPtr responder)
{
  return(SomeClassPtr(responder)->Key_handler(event));
}

inline Bool Key_handler(ConstSFUEventRef event)
{
  // something to do
  return(TRUE);
}

When the custom Handler to do nothing except return TRUE is needed, you can register the function only to return TRUE.

However, it is more efficient that its callback is registered as NULL. When the callback is NULL, no function is called, but the event handling is considered as "done".

Here is a sample code to handle and disable all the events related to key.

SFRResponderPtr responder;
SFCError        error;

error = responder->RegisterHandler(SFEVT_KEY, SFEVT_KEY_HELD, HANDLER_BEFORE, NULL, NULL);
[Warning] Warning

Whether the code above really disables the events or not depends on the settings of Tracer.

The Handler that is registered last is valid. For example, the two sample codes below have a different behavior.

SFRResponderPtr responder;

responder->RegisterHandler(SFEVT_KEY, HANDLER_AFTER, Key_static, this);
responder->RegisterHandler(SFEVT_KEY, SFEVT_KEY_HELD, HANDLER_AFTER, Held1_static, this);
responder->RegisterHandler(SFEVT_KEY, SFEVT_KEY_HELD, HANDLER_AFTER, Held2_static, this);
SFRResponderPtr responder;

responder->RegisterHandler(SFEVT_KEY, SFEVT_KEY_HELD, HANDLER_AFTER, Held1_static, this);
responder->RegisterHandler(SFEVT_KEY, SFEVT_KEY_HELD, HANDLER_AFTER, Held2_static, this);
responder->RegisterHandler(SFEVT_KEY, HANDLER_AFTER, Key_static, this);

A Tracer or Handler can be registered and unregistered, and the event type and its first parameter can be also set within a given range.

For example, you can set the event type to "from SFEVT_KEY to SFEVT_KEY_HELD" and AVK_SELECT as its first parameter. Or you can set the event type to SFEVT_KEY and its first parameter to anything from AVK_1 to AVK_9.

In any case, when you register a Handler or Tracer, the rules registered in the Parent class will be overridden.

7.5 Rendering

Only once at the end of every event loop the Renderer is activated, and the scheduled update region is redrawn.

A rectangular region can be registered as an area to be redrawn. In case you register more than two rectangular regions, larger rectangular region containing both rectangles will be redrawn.

Before rendering, update regions are optimized so that invisible objects and objects that are hidden behind other objects may not be redrawn. Regions that are outside the screen or cannot be seen by users will not be redrawn, as well.

Then the Renderer for each Responder object to be redrawn is executed only once.

Since each object does not have its off-screen memory, the Renderer must draw the entire screen every time. However, the regions unnecessary to be redrawn are clipped beforehand, so that they can be excluded from the rendering area.

Here is a sample code to force the update region redrawn immediately.

SFRApplicationPtr app;
SFRResponderPtr   responder;

responder.InvalidateContent(SFURect(0,0,30,30));
app->Invoke(SFUEvent(SREVT_RESPONDER_RENDER, SRP16_RENDER_INVOKE, TRUE));
[Tip] Tip
Sending the above event refreshes the screen immediately, which makes the processing speed relatively slow. Therefore it may not be recommended to use this event many times.
[Warning] Warning

Sending the above redraw event to classes other than Application is possible, but not supported.

To update a Frame Region or Contents Region, you have to call the InvalidateBase() or InvalidateContent() function respectively.

Here is a sample code to register the update region inside the Contents Region to be redrawn.

SFRResponderPtr responder;
SFURect         rect;

rect.set(0, 0, 10, 10); // example
responder->InvalidateContent(rect);

Here is a sample code to register the update region inside the Base Region to be redrawn.

SFRResponderPtr responder;
SFURect         rect;

rect.set(0, 0, 10, 10); // example
responder->InvalidateBase(rect);
[Note] Note

In ordinary applet development, the InvalidateContent() function may be used more frequently than the InvalidateBase() function.

7.6 Component Destruction

Destroying the Responder object by the delete operator is not supported after it has been successfully created.

To destroy a Responder object, you have to send the SREVT_RESPONDER_TERMINATE event to it.

[Note] Exception

When an error occurs inside the Responder constructor, you can use the delete operator without any problem.

Here is the sample code to create a Responder object and destroy it immediately.

SFRWindowPtr  window;

if ((window = new SFRTitleWindow(this, SFURect(0, 0, 100, 100),
 "Sample")) != NULL) {
  if (window->Exception() == NO_ERROR) {
    window->Invoke(SFUEvent(SREVT_RESPONDER_TERMINATE, 
	SRP16_TERMINATE_INVOKE, TRUE));
  }
  else {
    delete window;
  }
}

In the above code, if the window->Exception() function returns an error, the Responder object can be destroyed using the delete operator.

Once a Responder object has been successfully created, you have to send the SREVT_RESPONDER_TERMINATE event using the window->Invoke() function in order to destroy it safely.

[Note] Note

The destructor of classes that inherit from the Responder class ( SFRResponder ) must be declared as virtual.

8. Application

Application is a type of Responder, which is at the topmost position in the Responder ownership hierarch and has the so-called Standard Tracer by default.

8.1 Starting an Applet

A very simple applet using SophiaFramework looks like this:

SFMTYPEDEFCLASS(Demo)
class Demo : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new Demo());
    }
	
  private:
    inline Demo(Void)
    {
      return;
    }
	
    virtual inline ~Demo(Void)
    {
      return;
    }
};
7
SFCInvokerSPP SFCApplet::Boot(AEECLSID id)
{
  SFCInvokerSPP  result  = NULL;

  switch (id) {
    case AEECLSID_Demo:
      result = Demo::Constructor;
      break;
  }
  return(result);
}

The Demo class is the applet's main class.

When you start the application, the SFCApplet::Boot() function is executed.

In the SFCApplet::Boot() function, if Class ID matches its own Class ID, it returns the pointer to the Demo::Constructor() function.

After the instance of the Demo class is created by the Demo::Constructor() function, it starts to handle events as the applet's core.

The function returned by SFCApplet::Boot must be a type a member function of the following type:

SFCInvokerPtr  (*SFCInvokerSPP)  (Void);

8.2 Event Handling

To receive events in an application, we register a handler. A number of handlers is registered in the base class ofApplication by default.

For example, handlers that always return TRUE like SFEVT_SUSPEND and SFEVT_RESUME, and handlers that clear the entire screen for SREVT_RESPONDER_RENDER and SRP16_RENDER_CONTENT are already registered.

Now you are going to register a handler to receive a key event. To make the applet that you showed before receive key events, you can change it like this:

SFMTYPEDEFCLASS(Demo)
class Demo : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new Demo());
    }
	
  private:
    inline Demo(Void)
    {
      if (Exception() == NO_ERROR) {
        Exception(RegisterHandler(SFEVT_KEY, HANDLER_AFTER, Key_static, this));
      }
      return;
    }
	
    virtual inline ~Demo(Void)
    {
      return;
    }
	
    static inline Bool Key_static(ConstSFUEventRef event, VoidPtr responder)
    {
      return(DemoPtr(responder)->Key_handler(event));
    }
	
    inline Bool Key_handler(ConstSFUEventRef event)
    {
      // something to do
      return(TRUE);
    }
};

SFCInvokerSPP SFCApplet::Boot(AEECLSID id)
{
  SFCInvokerSPP  result  = NULL;

  switch (id) {
    case AEECLSID_Demo:
      result = Demo::Constructor;
      break;
  }
  return(result);
}

Now, the applet can receive key events in the Key_handler function.

To customize the way that the Contents area is rendered, you have only to register its handler. The code below shows how to create an instance of the Application that receives an event to redraw the Contents area.

SFMTYPEDEFCLASS(Demo)
class Demo : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new Demo());
    }
	
  private:
    inline Demo(Void)
    {
      if (Exception() == NO_ERROR) {
        Exception(RegisterHandler(SREVT_RESPONDER_RENDER, SRP16_RENDER_CONTENT,
		 HANDLER_BEFORE, Update_static, this));
      }
      return;
    }
	
    virtual inline ~Demo(Void)
    {
      return;
    }
	
    static inline Bool Update_static(ConstSFUEventRef event, VoidPtr responder)
    {
      DemoPtr(responder)->Update_handler(SFUGraphicsPtr(event.p32()));
      return(TRUE);
    }
	
    inline Void Update_handler(SFUGraphicsPtr graphic)
    {
      SFUBrewPtr<SFBBitmap>  i;

      SFRApplication::ContentHandler(graphic);
      i = SFBShell::Instance()->LoadResBitmap("Demo.bar", 1000);
      if (i != NULL) {
        graphic->DrawBitmap(i, SFUPoint(0, 0));
      }
      return;
    }
};

SFCInvokerSPP SFCApplet::Boot(AEECLSID id)
{
  SFCInvokerSPP  result  = NULL;

  switch (id) {
    case AEECLSID_Demo:
      result = Demo::Constructor;
      break;
  }
  return(result);
}

In the code above, an event to redraw the Contents Region is received, and a Bitmap picture from the resources is drawn in the Contents Region.

8.3 Closing an Applet

To close the applet, you have to call the CloseApplet() function in the SFBShell class.

9. Window

Window is a type of Responder, which offers user interface like a window in the personal computer.

9.1 Constructing a Window

To display a Window object, you have only to create it using the new operator.

Here is a sample code to create a Window object.

SFMTYPEDEFCLASS(Demo)
class Demo : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new Demo());
    }
	
  private:
    inline Demo(Void)
    {
      SFRWindowPtr  window;

      if (Exception() == NO_ERROR) {
        window = new SFRTitleWindow(this, SFURect(10, 10, 100, 100), "Hello");
        if (window != NULL) {
          if (Exception(window->Exception()) != NO_ERROR) {
            delete window;
          }
        }
        else {
          Exception(ENOMEMORY);
        }
      }
      return;
    }
	
    virtual inline ~Demo(Void)
    {
      return;
    }
};

SFCInvokerSPP SFCApplet::Boot(AEECLSID id)
{
  SFCInvokerSPP  result  = NULL;

  switch (id) {
    case AEECLSID_Demo:
      result = Demo::Constructor;
      break;
  }
  return(result);
}

9.2 Event Handling

To receive events, you have to register handlers in the Window class. By default, some handlers are already registered in the base class of Window. The Event Handling of Window is almost the same as Application. For a more concrete explanation on the Event Handling of Application, please refer to Application.

To receive the base region redraw event, register a handler of the SREVT_RESPONDER_RENDER type with the first parameter being of the SRP16_RENDER_BASE type.

9.3 Destroying a Window

To destroy a Window object, you have to send the SREVT_RESPONDER_TERMINATE event to it. For details, refer to Component Destruction.

It is possible to destroy a Window object explicitly. When the applet exists, all Window objects are destroyed automatically.

9.4 Types of Windows

Three types of Window are defined by default:

  1. SFRPlainWindow
  2. SFRFrameWindow
  3. SFRTitleWindow

You can create your own customized Window by inheriting from one of the above classes.

To define a completely different Window class from the standard one, you have to inherit from SFRWindow.

SFBShell::Instance()->CloseApplet(FALSE);

As for the CloseApplet() function, please refer to the BREW SDK reference. When the CloseApplet() function is called, BREW sends the SFEVT_APP_STOP event to the applet.

10. Dialog

Dialog is a type of Responder, which offers user interface like a dialog in the personal computer.

Dialog is used to display an alert or warning message to the user. The method to create a Dialog object is almost the same as Window.

10.1 Creating a Dialog

To display a Dialog, you have only to create a Dialog object using the new operator.

Here is a sample code to create a warning Dialog object.

SFMTYPEDEFCLASS(Demo)
class Demo : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new Demo());
    }
	
  private:
    inline Demo(Void)
    {
      SFRDialogPtr   dialog;

      if (Exception() == NO_ERROR) {
        dialog = new SFRAlertDialog(this, 
                                    SFURect(10, 10, 100, 100), 
                                    "Alert", 
                                    "Warning !", 
                                    "OK", 
                                    SFUSize(50, 18));
        if (dialog != NULL) {
          if (Exception(dialog->Exception()) != NO_ERROR) {
            delete dialog;
          }
        }
        else {
          Exception(ENOMEMORY);
        }
      }
      return;
    }
	
    virtual inline ~Demo(Void)
    {
      return;
    }
};

10.2 Event Handling

In the code above, a warning Dialog is displayed. And if the OK or Clear key are pressed, the Dialog closes as the default behavior.

To customize the Dialog behavior, you have to register a handler to receive the SREVT_DIALOG event, as shown in the code below.

SFMTYPEDEFCLASS(Demo)
class Demo : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new Demo());
    }
	
  private:
    inline Demo(Void)
    {
      SFRDialogPtr   dialog;

      if (Exception() == NO_ERROR) {
        dialog = new SFRAlertDialog(this, 
                                    SFURect(10, 10, 100, 100), 
                                    "Alert", 
                                    "Warning !", 
                                    "OK", 
                                    SFUSize(50, 18));
        if (dialog != NULL) {
          if (Exception(dialog->Exception()) == NO_ERROR) {
            Exception(dialog->RegisterHandler(srevt_dialog, HANDLER_BEFORE, Dialog_static, this));
          }
          else {
            delete dialog;
          }
        }
        else {
          Exception(ENOMEMORY);
        }
      }
      return;
    }
	
    virtual inline ~Demo(Void)
    {
      return;
    }
	
    static inline Bool Dialog_static(ConstSFUEventRef event, VoidPtr responder)
    {
      DemoPtr(responder)->Dialog_handler(event.p16(), SFRAlertDialogPtr(event.p32()));
      return(TRUE);
    }
	
    inline Void Dialog_handler(UInt16 status, SFRAlertDialogPtr dialog)
    {
      switch (status) {
        case SRP16_ESCAPE:
          // something to do
          break;
        case SRP16_OK:
          // something to do
          break;
      }
      dialog->DialogHandler();
      //As an alternative, you can use the code below.
      //dialog->Invoke(SFUEvent(SREVT_RESPONDER_TERMINATE, SRP16_TERMINATE_INVOKE, TRUE));
      return;
    }
};

In the code above, when the OK button is pressed or when the Dialog is escaped by the Clear Key, the Dialog_handler function is called with the arguments of the event value and the pointer to this Dialog object for processing the events.

One of the following event values is passed to this Dialog_handler function:

  1. SRP16_OK, if the OK button is pressed
  2. SRP16_ESCAPE, if the Clear Key is pressed

When the Dialog is registered, its default behavior is overwritten, therefore it must be explicitly destroyed, otherwise the Dialog will not close.

There are two ways to destroy a Dialog the same as other Responders.

One way is to call the default handler of the Dialog class. The other way is to send the SREVT_RESPONDER_TERMINATE event to the Dialog object.

10.3 Types of Dialog

The following two types of Dialog are defined by default:

  1. SFRAlertDialog
  2. SFRAskDialog

You cannot create your own Dialog by inheriting from the above classes.

To define a completely different Dialog class from the standard one, you have to inherit it from the SFRDialog class.

11. Menu

Menu is a type of Responder, which offers user interface like a menu in the personal computer. The method to create a Menu object is almost the same as Window.

11.1 Creating a Menu

To display a Menu object, you have only to create it using the new operator.

Here is a sample code to create a Text Menu object.

SFMTYPEDEFCLASS(Demo)
class Demo : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new Demo());
    }
	
  private:
    inline Demo(Void)
    {
      SFRMenuPtr     menu;
      SFUWideString  item[]  = {"item0", "item1", "item2"};

      if (Exception() == NO_ERROR) {
        menu = new SFRTextMenu(this, SFURect(10, 10, 100, 100), "Sample", item, sizearray(item));
        if (menu != NULL) {
          if (Exception(menu->Exception()) != NO_ERROR) {
            delete menu;
          }
        }
        else {
          Exception(ENOMEMORY);
        }
      }
      return;
    }
	
    virtual inline ~Demo(Void)
    {
      return;
    }
};

11.2 Event Handling

In the code above if the Select or Clear key is pressed, the Menu closes as the default behavior.

To customize the behavior of Menu, you have to register a handler to the SREVT_MENU event, as shown in the code below.

SFMTYPEDEFCLASS(Demo)
class Demo : public SFRApplication {
  public:
    static inline SFCInvokerPtr Constructor(Void)
    {
      return(new Demo());
    }
	
  private:
    inline Demo(Void)
    {
      SFRMenuPtr     menu;
      SFUWideString  item[]  = {"item0", "item1", "item2"};

      if (Exception() == NO_ERROR) {
        menu = new SFRTextMenu(this, SFURect(10, 10, 100, 100), "Sample", item, sizearray(item));
        if (menu != NULL) {
          if (Exception(menu->Exception()) == NO_ERROR) {
            Exception(menu->RegisterHandler(SREVT_MENU, HANDLER_BEFORE, Menu_static, this));
          }
          else {
            delete menu;
          }
        }
        else {
          Exception(ENOMEMORY);
        }
      }
      return;
    }
	
    virtual inline ~Demo(Void)
    {
      return;
    }
	
    static inline Bool Menu_static(ConstSFUEventRef event, VoidPtr responder)
    {
      DemoPtr(responder)->Menu_handler(event.p16(), SFRTextMenuPtr(event.p32()));
      return(TRUE);
    }
	
    inline Void Menu_handler(UInt16 select, SFRTextMenuPtr menu)
    {
      switch (select) {
        case SRP16_ESCAPE:
          // something to do
          break;
        /*case SRP16_CANCEL:
          break;*/
        default:
          // something to do
          break;
      }
      menu->MenuHandler();
      // As an alternative, you can use the following line.
      //menu->Invoke(SFUEvent(SREVT_RESPONDER_TERMINATE, P16_TERMINATE_INVOKE, TRUE));
      return;
    }
};

In the above code, when the Select or Clear key is pressed, the Menu_handler function is called with the arguments of the event value and the pointer to this Menu object for processing the events.

One of the following event values is passed to this Menu_handler function:

  1. an index number, in case the Menu is selected
  2. SRP16_CANCEL, in case the Menu is canceled for other reasons
  3. SRP16_ESCAPE, in case the Clear key is pressed

As the default behavior of Menu has been overridden, you have to destroy it explicitly in order to close it.

There are two ways to destroy a Menu object same as other Responder.

One is to call the default handler of Menu. The other is to send the SREVT_RESPONDER_TERMINATE event to the Menu object.

[Note] Note

The Menu item indexed above 65000 is used to represent the reason why the Menu is canceled.
Therefore, the Menu items cannot be numbered more than 65000, and the number of the Menu items must be less than 65000.

11.3 Types of Menu

Only one type of Menu is defined: SFRTextMenu.

You cannot create your own Menu by inheriting from the SFRTextMenu class.

To define a completely different Menu class from the standard one, you have to inherit from the SFRMenu class.

12. Control

Control is a type of Responder, which offers user interface like a control such as botton, radio botton, checkbox, etc. in the personal computer. The method to create a Control object is almost the same as Window.

12.1 Creating a Control

To display a Control object, you have only to create it using the new operator.

Here is a sample code to create a Checkbox Control object and attach it to a Window.

SFMTYPEDEFCLASS(MyWindow)
class MyWindow : public SFRTitleWindow {
  public:
    inline MyWindow(SFRApplicationPtr app) : SFRTitleWindow(app, SFURect(10, 10, 100, 100), "Hello")
    {
      SFRControlPtr  control;

      if (Exception() == NO_ERROR) {
        control = new SFRCheckboxControl(this, SFURect(5, 5, 0, 0), "Checkbox");
        if (control != NULL) {
          if (Exception(control->Exception()) != NO_ERROR) {
            delete control;
          }
        }
        else {
          Exception(ENOMEMORY);
        }
      }
      return;
    }
	
    virtual inline ~MyWindow(Void)
    {
      return;
    }
};

12.2 Event Handling

In the code above, when the Select key is pressed, the Checkbox Control displayed alternates the Checked state with the Unchecked one.

To customize the behavior of Checkbox Control, you have only to register a handler to receive the SREVT_CONTROL event.

Here is a code showing how to do it.

SFMTYPEDEFCLASS(MyWindow)
class MyWindow : public SFRTitleWindow {
  public:
    inline MyWindow(SFRApplicationPtr app) : SFRTitleWindow(app, SFURect(10, 10, 100, 100), "Hello")
    {
      SFRControlPtr  control;

      if (Exception() == NO_ERROR) {
        control = new SFRCheckboxControl(this, SFURect(5, 5, 0, 0),"Checkbox");
        if (control != NULL) {
          if (Exception(control->Exception()) == NO_ERROR) {
            Exception(control->RegisterHandler(SREVT_CONTROL, HANDLER_BEFORE, Control_static, this));
          }
          else {
            delete control;
          }
        }
        else {
          Exception(ENOMEMORY);
        }
      }
      return;
    }
	
    virtual inline ~MyWindow(Void)
    {
      return;
    }

    static inline Bool Control_static(ConstSFUEventRef event, VoidPtr responder)
    {
      MyWindowPtr(responder->Control_handler(event.p16(), CheckboxControlPtr(event.p32()));
      return(TRUE);
    }
	
    inline Void Control_handler(UInt16 value, SFRCheckboxControlPtr control)
    {
      switch (value) {
        case ...
          // something to do
          break;
      }
      return;
    }
};

In the code above, when the Select key is pressed, the Controle_handler function is called with the arguments of the event value and the pointer to this Checkbox Control object for processing the events.

The method to use the other Controls is almost the same as Checkbox Control. But, in the Botton Control specification, the SFREVT_CONTROL event is sent when a key is released.

12.3 Types of Control

SophiaFramework offers many standard Controls by default. All you have to do is to instantiate the Control class and change its attributes such as color, font, etc.

These are the standard Control classes included with SophiaFramework :

You cannot inherit from the above Controls and create a customized one.

However, the following base classes of Control can be inherited from:

To define a completely different Control class from the standard one, you have to inherit from the SFRControl class.