Index
- What's the GUI Framework?
- How to Use the GUI Framework
- Structure of the GUI Framework
- Event Handling
- Rendering
- Appendix: GUI Framework of SophiaFramework 2.2
What's the GUI Framework?
The GUI Framework is an application framework which automates GUI-related processes such as event handling and rendering, and offers standard GUI components including window, dialog, menu, button, label, checkbox, etc.
With the GUI Framework, there is no need to program complex codes on event handling or rendering the GUI components.
SophiaFramework UNIVERSE provides the GUI components called Responder as the GUI Framework.
Responder List
Application
| Class Name | Description |
|---|---|
| SFRApplication | Application base class * |
Window
| Class Name | Description |
|---|---|
| SFRWindow | Window base class * |
| SFRPlainWindow | Plain window without frame |
| SFRFrameWindow | Plain window with frame |
| SFRTitleWindow | 3-D window with frame and title bar |
Dialog
| Class Name | Description | SFRDialog | Dialog base class * |
|---|---|
| SFRPlainDialog | Plain dialog without frame |
| SFRFrameDialog | Plain dialog with frame |
| SFRTitleDialog | 3-D dialog with frame and title bar |
| SFRMessageDialog | Message dialog with at most 1 button |
| SFRMultiDialog | Selection dialog with at most 3 buttons |
Menu
| Class Name | Description |
|---|---|
| SFRMenu | Menu base class * |
| SFRTextMenu | Menu displaying text-based items |
Pane
| Class Name | Description |
|---|---|
| SFRPane | Plain base class * |
| SFRPlainPane | Plain pane without frame |
| SFRTabPane | Plain pane reserved for SFRTabControl |
Control
| Class Name | Description |
|---|---|
| SFRControl | Control base class * |
| SFRLabelControl | Label control |
| SFRButtonControl | Button control |
| SFRCheckboxControl | Checkbox control |
| SFRRadiobuttonControl | Radio button control |
| SFRComboboxControl | Combo box control |
| SFRTabControl | Tab control |
| SFREditboxControl | Text input control |
| SFRBrowserControl | Control displaying HTML browser |
* The Responder base classes are used to create custom GUI components.
How to Use the GUI Framework
To use the GUI Framework you need to create an Application class which inherits from the SFRApplication class. When creating a project using Application Wizard, choose "Yes" when asked "Is the GUI framework used?" The automatically generated application class can be used as a template.
The Application class must have the same name with the application itself, such as "HelloWorld" or "MyApp".
SophiaFramework UNIVERSE Tutorial : HelloWorld Application
Example : Creating a Window
SFRWindowPtr window;
window = ::new SFRTitleWindow(SFRApplication::GetInstance(),
SFXRectangle(0, 0, 240, 320),
"my window");
Example : Creating a Button
SFRButtonControlPtr button;
button = ::new SFRButtonControl(window,
SFXRectangle(10, 10, 128, 24),
"my button");
Example : Displaying Debugging Output
button->RegisterHandler(SREVT_CONTROL, HANDLER_BEFORE, HANDLER_FUNCTION(OnButton));
HANDLER_IMPLEMENT_VOIDCONTROL(MyApp, OnButton, result, control)
{
TRACE("my button was pushed.");
return;
}
An application with complex GUI can be easily developed by configuring the Control objects such as Button and Checkbox in the Window object and registering functions that are called when the Contol objects is operated.
Structure of the GUI Framework
In the GUI Framework, the Application class inherits from the SFRApplication class. The Application object controls the Window objects, and the Window object controls the Control objects. The diagram below shows its hierarchy.
Diagram : Inheritance Relation
Diagram : Ownership Relation
The Dialog, Menu and Window classes are on the same hierarchical level. The Pane object controls the Control objects; The Pane object can be controlled by the Control object as well.
This hierarchy automates event handling and rendering the GUI components in the BREW environment.
Event Handling
The event triggered by user operation is sent to the application by the BREW environment. After the application receives the event, Event Handling Engine handles it.
According to the Tracer rules, Event Handling Engine distributes each BREW event to the appropriate Responder objects, and executes the functions called Handler registered by the developer.
Event Driven Structure
The BREW application has the event driven structure, which means that an event triggered by user operation or external interruption is dispatched and handled.
The application processes such as initialization or key operation are done depending on the event type.
From the application boot-up to its termination, a variety of events from the BREW environment are dispatched to the application.
Diagram : Lifecycle
With the GUI Framework, there is no need to write complex code for event handling by hand from scratch. Because Event Handling Engine automatically dispatches each event to the appropriate handler function.
Booting up Application
When a user boots up an application, Event Handling Engine instantiates once the Application class which inherits from the SFRApplication class.
Next, the SFEVT_APP_START event is dispatched to the application from the BREW environment, and the application initialization begins.
Sequence Diagram : Booting up Application
Initialization process such as creating a Window obeject is processed within the constructor of Application class or the handler for the SFEVT_APP_START event.
Terminating Application
When a user terminates the application by selecting the QUIT option in the menu or by pressing the POWER key, the SFEVT_APP_NO_CLOSE event is dispatched from the BREW environment. Then, Event Handling Engine returns "false" to this event.
* about SFEVT_APP_NO_CLOSE : Return "false" to this event when the application should be ended. But to make it not be ended, return "true" to this event.
Next, the SFEVT_APP_STOP event is dispatched from the BREW environment, and its termination begins.
When the handling for the SFEVT_APP_STOP event finishes normally, Event Handling Engine is released, and the application itself is also automatically released.
Sequence Diagram : Terminating Application
The diagram above shows that the user pressed the QUIT button in the Window object; the SFRApplication::Terminate() function is executed and the application is ended.
Termination process such as destroying the Window object are done within the Application destructor or the handler for the SFEVT_APP_STOP event.
Tracer
Each event is dispatched to the appropriate Responder objects according to its type by Event Handling Engine.
For instance, the KEY event is dispatched to the Responder objects that are focused for user operation, and the SUSPEND or RESUME event is dispatched to all Responder objects.
This complex event dispatching is controlled by the rules set forth by what is called Tracer.
SFEVT_KEY Event Flow Chart
SFEVT_APP_RESUME Event Flow Chart
The GUI framework includes Standard Tracer that can be overridden if necessary. The Child Responder class inherits the Tracer rules from its Parent Responder class. Unless the settings are overridden explicitly, Standard Tracer registered in the Application class is used.
The RegisterTracer() function is used to register the Tracer rules, which are shown below. The settings for event dispatching can be done according to the Responder status.
| Tracer Rule | Description |
|---|---|
| TRACER_NONE | Does not dispatch to Child Responder objects |
| TRACER_FORWARD | Dispatches from foreground to background Child Responder objects |
| TRACER_BACKWARD | Dispatches from background to foreground Child Responder objects |
| TRACER_FOCUS | Dispatches to focused Child Responder objects |
| TRACER_PROVIDE | Permits duplicated event handling |
Example : Registering a Tracer
class MyApp : public SFRApplication {
public:
explicit MyApp(Void) static_throws;
};
MyApp::MyApp(Void) static_throws
{
if (static_try()) {
// dispatch the SOFTKEY 1-3 events to all Responder objects
// from foreground to background
//
// as Child Responder inherites Tracer rules,
// these are valid for Window and Control
static_throw(RegisterTracer(SFEVT_KEY,
AVK_SOFT1,
AVK_SOFT3,
BEHAVIOR_NONE,
TRACER_FORWARD));
}
return;
}
Standard Tracer
The GUI Framework includes the Tracer rules indicated below as Standard Tracer.
Dispatching Order : In case of "-", the event is not dispatched to the Child Responder objects.
Duplicate Event Handling : In case of "-", the event is not duplicately handled. If an event is handled by a Responder object, it will be never dispatched to the other Responder objects.
Status Filter : In case of "Ο", the event can be dispatched to the Responder object according to its status. In case of blank space, the event can be dispatched to the Responder object independently of its status.
Table : Standard Tracer
| Event Range | Dispatching Order | Duplicate Event Handling | Status Filter * | |||
| V | E | F | T | |||
| Tracer rules on BREW Events included in the SFRApplication Class | ||||||
| SFEVT_APPLICATION_CLASS_BEGIN ~ SFEVT_APPLICATION_CLASS_END |
- | - | ||||
| SFEVT_APP_RESUME | Foreground to Background | Permitted | ||||
| SFEVT_APP_SUSPEND | Foreground to Background | Permitted | ||||
| SFEVT_KEY_CLASS_BEGIN ~ SFEVT_KEY_CLASS_END |
Focused | - | Ο | Ο | Ο | Ο |
| SFEVT_CONTROL_CLASS_BEGIN ~ SFEVT_CONTROL_CLASS_END |
Focused | - | Ο | Ο | Ο | Ο |
| SFEVT_CTL_TAB | Focused | Permitted | Ο | Ο | Ο | Ο |
| SFEVT_CTL_TEXT_MODECHANGED | Focused | Permitted | Ο | Ο | Ο | Ο |
| SFEVT_DIALOG_CLASS_BEGIN ~ SFEVT_DIALOG_CLASS_END |
Focused | - | Ο | Ο | Ο | Ο |
| SFEVT_SHELL_CLASS_BEGIN ~ SFEVT_SHELL_CLASS_END |
- | Permitted | ||||
| SFEVT_DEVICE_CLASS_BEGIN ~ SFEVT_DEVICE_CLASS_END |
- | Permitted | ||||
| SFEVT_CLIPBOARD_CLASS_BEGIN ~ SFEVT_CLIPBOARD_CLASS_END |
- | Permitted | ||||
| Tracer rules on SophiaFramework UNIVERSE Events included in the SFRApplication Class | ||||||
| SREVT_RESPONDER_INITIALIZE | - | Permitted | ||||
| SREVT_RESPONDER_TERMINATE | - | - | ||||
| SREVT_RESPONDER_TERMINATE, SRP16_TERMINATE_TRY |
Foreground to Background | Permitted | ||||
| SREVT_RESPONDER_RENDER | - | Permitted | Ο | |||
| SREVT_RESPONDER_STATUS | - | - | ||||
| SREVT_APPLICATION | - | - | ||||
| Tracer rules on SophiaFramework UNIVERSE Event included in the SFRWindow Class | ||||||
| SREVT_WINDOW | - | - | ||||
| Tracer rules on SophiaFramework UNIVERSE Event included in the SFRDialog Class | ||||||
| SREVT_DIALOG | - | - | ||||
| Tracer rules on SophiaFramework UNIVERSE Event included in the SFRMenu Class | ||||||
| SREVT_MENU | - | - | ||||
| Tracer rules on SophiaFramework UNIVERSE Event included in the SFRPane Class | ||||||
| SREVT_PANE | - | - | ||||
| Tracer rules on SophiaFramework UNIVERSE Event included in the SFRControl Class | ||||||
| SREVT_CONTROL | - | - | ||||
* Status Filter Items in the above Tracer rules
| Comparison Item | Description |
|---|---|
| V | Visible or not |
| E | Can be operated or not |
| F | Focused or not |
| T | Targeted or not |
Handler
A function for handling an event triggered by user operation or network communication is called Handler.
Each event has its priority to be handled according to its type. For instance, the KEY event is handled at the lowest Responder object in its hierarchy, because a user operates the foreground Responder object that has focus.
Diagram : Priority of Event Handling
To implement the above scheme, the Parent Responder object must handle the events after the Child Responder objects. Thus, there are two types of Handlers: Before-Handler and After-Handler.
Before-Hander is a handler called before an event is dispatched to the Child Responder objects, and After-Handler is a handler called after an event is handled by the Child Responder objects.
The RegisterHanlder() function is used to register a handler. The possible rules for the handler settings are shown below.
| Handler Type | Description |
|---|---|
| HANDLER_BEFORE | Handles an event before the Child Responder objects |
| HANDLER_AFTER | Handles an event after the Child Responder objects |
The following Macro functions are used to create handlers ( Specialized Macro functions are also available )
| Macro | Description |
|---|---|
| HANDLER_DECLARE_BOOLEVENT | Macro for declaration |
| HANDLER_IMPLEMENT_BOOLEVENT | Macro for implementation |
Example : Registering and Implementing a Key Handler
class MyWin : public SFRPlainWindow {
public:
explicit MyWin(Void) static_throws;
private:
HANDLER_DECLARE_BOOLEVENT(OnKey)
};
MyWin::MyWin(Void) static_throws : SFRPlainWindow(...)
{
if (static_try()) {
// Register a handler OnKey for the Key event
static_throw(RegisterHandler(SFEVT_KEY,
HANDLER_AFTER,
HANDLER_FUNCTION(OnKey)));
}
return;
}
HANDLER_IMPLEMENT_BOOLEVENT(MyWin, OnKey, event)
{
switch (event.GetP16()) {
case AVK_SELECT:
DoSelect();
return true;
case AVK_CLR:
DoClear();
return true;
}
return false;
}
The Handler function returns true if the event is handled, or else false. In case of true, Event Handling Engine creates the Rendering event that boots up Rendering Engine if necessary.
Rendering
When Event Handling Engine finishes, Rendering Engine boots up if necessary. Rendering Engine optimizes its execution based on the status and configuration of the Responder objects.
Within each event loop, only the necessary rendering handlers are called such that performance will not deteriorate even with complex screen rendering.
Timing to be Rendered
The screen is rendered in the final stage of each event loop. When the event handler returns true, Event Handling Engine boots up Rendering Engine, which checks whether the rendering regions are registered or not.
Sequence Diagram : Event Being Handled
If Rendering Engine does not boot up because the event handler returns false, or there are no regions to be rendered, the screen is not rendered.
Sequence Diagram : Event Not Being Handled
Handler
All rendering is done within the hander customized specifically for rendering called Rendering Handler.
The rendering handler is also a type of Handler and registered with the RegisterHanlder() function. The macro functions below are used to implement it.
| Macro | Description |
|---|---|
| HANDLER_DECLARE_VOIDRENDER | Macro for declaration |
| HANDLER_IMPLEMENT_VOIDRENDER | Macro for implementation |
The argument of the rendering handler is an instance of the SFXGraphics class, which is used to render the screen.
Example : Registering and implementing the rendering handler
class MyWin : public SFRPlainWindow {
public:
explicit MyWin(Void) static_throws;
private:
HANDLER_DECLARE_VOIDRENDER(OnRender)
};
MyWin::MyWin(Void) static_throws : SFRPlainWindow(...)
{
if (static_try()) {
// register OnRender as rendering handler
static_throw(RegisterHandler(SREVT_RESPONDER_RENDER,
SRP16_RENDER_CONTENT,
HANDLER_BEFORE,
HANDLER_FUNCTION(OnRender)));
}
return;
}
HANDLER_IMPLEMENT_VOIDRENDER(MyWin, OnRender, graphics)
{
// use graphics instance to render within the rendering handler
graphics->FillRectangle(GetContentWorld(),
SFXRGBColor(0x00, 0xFF, 0xFF, 0x00));
return;
}
Rendered Region
The rendered region should be registered if necessary. The actual rendering itself is done within the rendering handler.
For instance, if the text string of a label control is changed with the SetText() function, this label control must be rendered. In this case, register the rendering region in Rendering Engine using the InvalidateContent() function within the SetText() function.
When the control is moved to Rendering Engine, the registered regions are rendered all together.
Example : Registering the Rendered Region
class MyLabel : public SFRControl {
public:
explicit MyLabel(SFRResponderPtr director) static_throws;
Void SetText(SFXAnsiStringConstRef param);
private:
HANDLER_DECLARE_VOIDRENDER(OnRender)
};
MyLabel::MyLabel(SFRResponderPtr director) static_throws
: SFRControl(director, ...)
{
if (static_try()) {
// register OnRender as rendering handler
static_throw(RegisterHandler(SREVT_RESPONDER_RENDER,
SRP16_RENDER_CONTENT,
HANDLER_BEFORE,
HANDLER_FUNCTION(OnRender)));
}
return;
}
Void MyLabel::SetText(SFXAnsiStringConstRef param)
{
if (param != _text) {
_text = param;
// register in Rendering Engine for rendering
InvalidateContent();
}
return;
}
HANDLER_IMPLEMENT_VOIDRENDER(MyLabel, OnRender, graphics)
{
SFXRectangle rect(GetContentWorld());
// render within the rendering handler
graphics->FillRectangle(rect, SFXRGBColor(0xFF, 0xFF, 0xFF, 0x00));
graphics->DrawString(_text, rect, SFXRGBColor(0x00, 0x00, 0x00, 0x00));
return;
}
When the rendered region is registered, the rendering handler is called at the end of each event loop.
By using the overloaded InvalidateContent() function with a rectangle argument and limiting the rendered region, rendering performance can be improved.
Explicit Rendering
Since Rendering Engine boots up at the end of each event loop, Rendering Engine can not be booted up by a callback from outside the event loop, such as network callback or timer callback.
Sequence Diagram : Callback
Rendering Engine needs to be explicitly booted up in order to render the screen after the network communication.
Sequence Diagram : Booting up Rendering Engine
Rendering Engine can be explicitly booted up by sending the rendering event to the SFRApplication object. (Sending the rendering event to the Responder objects other than SFRApplication is not supported)
Example : Explicit Rendering
CALLBACK_IMPLEMENT_SFXHTTPCONNECTION(MyWin, OnConnect, error)
{
SFRApplicationPtr app(SFRApplication::GetInstance());
// change the text string of the label
_label->SetText("OnConnect");
// boot up Rendering Engine explicitly
//
// rendering does not occur without the code below
// and the result of the SetText() function cannot be observed
app->Invoke(SFXEvent(SREVT_RESPONDER_RENDER, SRP16_RENDER_INVOKE, false));
return;
}
Rendering Engine can be explicitly booted up by sending the SFXEvent(SREVT_RESPONDER_RENDER, SRP16_RENDER_INVOKE, false) event.
* When the SFXEvent(SREVT_RESPONDER_RENDER, SRP16_RENDER_INVOKE, true) event is sent, all Responder objects are forcedly rendered by rendering handlers regardless of the registration of the rendering regions.



















