Understanding UI components
From UIQ Books
Contents |
Understanding User Interface Components
In the Chapter Development environment and quick start we built a simple application, QuickStart, and introduced the application framework. In this chapter we present some important concepts in building a user interface: controls, windows, user input events and views. We also examine the parts of the UIQ 3 screen in more detail. In the next chapter, we will put this all together and start programming listboxes with UIQ-specific controls.
Controls and Windows
What are Controls?
Controls are the basic elements used by applications to interact with users. They include such items as: buttons, menus, list boxes and views. In Symbian OS, all controls are derived from the CCoeControl base class. This ensures that all controls present a common set of features and capabilities; for example, position and size.
Controls occupy a rectangular area on screen. They usually display some text or an image to the user and perhaps respond to user, application or system generated events such as key presses or pointer events.
Figure 1 Simple text display control, time and date editor controls
Control Types
Simple controls perform very basic tasks, such as displaying lines, text and images.
We need much more complicated controls, but rather than writing each control afresh, we can combine simple controls together to make a compound control. For example, we can build a compound button control from three simple controls.
Figure 2 Building a compound control from simple controls
In a sophisticated GUI such as UIQ 3, more complicated effects are needed to provide an attractive display. A button needs a graphical background and needs to look different when it is clicked.
Figure 3 Building a button control
Compound controls can themselves be incorporated into other controls. This enables a tree-like structure of controls to be constructed. A compound control (for example C3) can be made up from other compound controls (C1 and C2) and some simple controls (S2 and S6). Following the tree, we find simple controls at the tips. For example, S1 could be a simple text display control that is utilized in C1 and C2.
Figure 4 Tree of controls
The primary advantage to this approach is component re-use. Symbian OS only needs a single text control or a single image control irrespective of how it is incorporated into more substantial user interface controls.
As a second example, a menu could be considered to be bordered control. Within the menu border, the textual menu items and possibly a graphic image is displayed. The exact same controls used to display text and graphic in a button can be reused to display a menu.
Figure 5 Constructing a menu
Drawing Controls
For controls to be visible on the screen, they need to be drawn. The following pseudo-code shows approximately how drawing is handled within CCoeControls when an application calls the DrawNow() method. In particular, it demonstrates how compound controls are firstly drawn, by virtue of their Draw() methods being called, then any component controls are drawn.
void CCoeControl::Draw(const TRect& aRect) const
{
// Implement the control specific drawing here.
}
void CCoeControl::DrawComponents(const TRect& aRect) const
{
TInt count=CountComponentControls();
for (TInt i=0;i<count;i++)
{
CCoeControl* ctrl=ComponentControl(i);
TRect rect(ctrl->Rect());
rect.Intersection(aRect);
if (!rect.IsEmpty())
{
ctrl->Draw(rect);
// Recursively call this method.
ctrl->DrawComponents(rect);
}
}
}
void CCoeControl::DrawNow() const
{
TRect rect(Rect());
ActivateGc();
Window().Invalidate(rect);
Window().BeginRedraw(rect);
Draw(rect);
DrawComponents(rect);
Window().EndRedraw();
DeactivateGc();
}
The DrawComponents() method demonstrates that there are no specific limits as to how many components an individual control may have or how deep the nesting of controls can be.
You should note that this is not the exact code that is executed as there are a number of other conditions that need to be checked for. The code merely demonstrates the recursive nature of compound controls and should help in the understanding of the tree-like control structure that exists in your application.
What are Windows?
The Window Server
Symbian OS is a multi-tasking operating system. This means that more than one application can be running at the same time. A system process called the window server exists to manage shared access to the screen and input hardware, so that user interaction events such as key presses or pen events are delivered to the correct application.
Individual applications are said to be clients of the window server. The window server communicates with its clients by sending them events via the system standard inter-process communication infrastructure. Clients listen out for these events using an active object.
Figure 6 Window server
Controls and Windows
A window is a resource owned by the window server (WSERV) and represents a rectangular area of the screen. Controls exist inside windows. While every control could have its own window, such an arrangement is very resource intensive and in general, many controls share a single window. Each control must be able to reference the window in which it exists.
Figure 7 Window server sessions
Controls that own a window are called window owning controls and use one of the CreateWindowL() methods during its construction. In comparison, a non-window owning controls will require you to call SetContainerWindowL() to specify the window this control shares. In terms of functionality, there is little difference between whether a control owns a window or not. Indeed a control is usually unaware of whether it is window owning or not. In a single application the same control could be window owning when used in one particular way and non-window owning when used in an alternative way.
The Control Environment
Controls do not exist in isolation; they exist within an environment called the control environment, also known as CONE. This is the reason for the Coe in CCoeControl. This environment is provided by the CCoeEnv class and objects such as CEikonEnv which subclass CCoeEnv to extend its functionality.
The CCoeEnv class is an active object. In particular, it is responsible for receiving the events sent by the window server. Once it has received these events, it performs a certain amount of low level generic processing, enabling controls to focus on specific tasks such as redrawing themselves or handling a pointer event.
It is possible to write applications without using any of the control environment and UI framework code; for example, software that does not have a UI, such as a server, does not need the UI framework. For applications with a UI, you are not forced to use the provided framework, but avoiding it is a substantial task and is outside the scope of this book.
User Interaction with Controls
The window server delivers a range of events, but the three events of most interest to us at this time are redraw, pointer and keyboard events.
Redraw Events
The original design principle of the window server is that it does not update windows by itself. Instead, it requests applications to perform the task. UIQ 3 incorporates an advanced technology called the RedrawStore that is capable of caching most drawing operations and replaying them on demand. This technology enables some of the advanced transition and image blending effects that are available on UIQ 3 phones. It does not, however, completely eliminate the need for applications to be able to redraw their screens on demand.
Redraw events are sent to an application when part of a window owned by the application needs to be updated; for example, due to a dialog box being removed.
Figure 8 Window redraw event
The window server does not have any concept of controls, only windows. An application is responsible for determining which specific controls intersect with the window region that needs redrawing and cause those controls to redraw themselves. The client side representation of a window is presented through objects derived from the RWindowBase class such as RWindow. When you construct such an object, you can specify a unique id or handle, which the window server will keep associated with the window.
When a window owning CCoeControl is constructed, it creates the RWindow and sets this handle to be the CCoeControl object pointer. When a redraw event is received, the framework simply has to obtain the handle, which is conveniently passed with the redraw event, and interpret it as a CCoeControl object. Once the framework has identified the CCoeControl it can proceed with drawing all controls and component controls by using the Draw() and DrawComponents() methods outlined previously.
Pointer Events
As with redraw events, pointer events occur within a window. The application is responsible for determining which control happens to be positioned at the location within the window where the pointer event occurred and therefore should process it.
Figure 9 Pointer event
Like redraw events, the handle given to the window construction method is passed with the pointer event. The framework interprets this handle as a CCoeControl and begins its search of which component controls performing something like:
void CCoeControl::HandlePointerEventL(const TPointerEvent& aPointerEvent) const
{
TInt count=CountComponentControls();
for (TInt i=0; i<count; i++)
{
CCoeControl* ctrl=ComponentControl(i);
TRect rect(ctrl->Rect());
if (rect.Contains(aPointerEvent.iPosition))
{
ctrl->ProcessPointerEventL(aPointerEvent);
break;
}
}
}
You should note that pointer events are slightly harder to deal with fully than the above code fragment implies. However, the above shows how the framework traverses the set of compound controls to deal with pointer events in a very similar fashion to dealing with redraw events.
Key Events
Unlike redraw and pointer events, key events are not associated with a single window but with a window group. Strictly speaking, the window server sends key events to the window group that currently has focus. Within the control environment, there is only a single window group per application, so the two are considered synonymous.
On phones that share the screen between multiple applications, the foreground application is the one that has focus. On Symbian OS based mobile phones, applications effectively run maximized all the time, therefore the displayed application is in the foreground and has focus; only one application can be displayed at a time. Key events are therefore sent to the current application.
| Pro tip:
The use of focus correlating to the foreground application should not be confused with the use of focus within an individual application. Focus within an individual application is often displayed visually and used to attract the user’s attention to a specific control. |
Figure 10 Foreground application has focus
Figure 11 Focus inside the Contacts application
Once the control environment has received a key event, it has to determine how to deliver that event to the correct control. Unlike redraw and pointer events, it cannot simply associate the key with a window. Instead, the control environment uses a structure called the control stack. The control stack is a priority-ordered list of all controls that are interested in receiving keyboard events. Typically, only a small number of controls are present on the control stack at any point in time; compound controls only need to register the parent with the control stack for all the components to be registered. If required, the parent can pass the key event to its components.
When a key event is received, the control environment searches the control stack from highest to lowest priority to locate a control prepared to handle the event. You can see this in the method name OfferKeyEventL() and its return values. The key event is first offered to a high priority control. If it reports EKeyWasNotConsumed, then it is offered to a lower priority control, and so on until a control returns EKeyWasConsumed.
The control environment adds a number of controls to the control stack, for example, if the phone has a front end processor (FEP) for data entry a control with priority ECoeStackPriorityFep is added to the control stack. The application menu control is added at ECoeStackPriorityMenu. In general, views within your application will be added to the control stack at ECoeStackPriorityDefault.
The full set of defined priorities is:
enum
{
ECoeStackPriorityDefault=0,
ECoeStackPriorityMenu=10,
ECoeStackPriorityDialog=50,
ECoeStackPriorityCba=60,
ECoeStackPriorityAlert=200,
ECoeStackPriorityFep=250,
ECoeStackPriorityEnvironmentFilter=300
};
You may have noticed that there are gaps between the priority values. This enables applications to insert controls with intermediate priorities if there is a requirement to do so.
Views and the View Server
We say that applications display a view of their data. Some applications may only present a single view. Others, such as an diary type application, have multiple views.
Figure 12 Agenda application day, week and month views
Views may also display temporary data; for example, they can display the progress of an action.
Users frequently perform tasks that need to use the data and functionality of several applications. For example, the user may wish to phone a colleague. The phone application is responsible for actually dialling numbers and establishing a voice call. The user does not want to enter the phone number of the colleague every time and copy/pasting the number from the contacts application as too many steps are involved. The best solution is to provide a ‘call’ function in the Contacts application.
We could provide the phone call functionality in a shared code library, with both applications using that library.
Figure 13 Phone server solution
Alternatively, we could provide a separate dialler application to implement the phone call functionality. The Phone and Contacts applications launch the Dialler when the user makes a phone call.
Figure 14 Dialler application solution
We might also want our Agenda application to send a ‘Happy Birthday’ SMS when a friend in the Contacts database has a birthday. There are many of these opportunities to share data and use the communications facilities of a mobile phone, so it is important to provide a flexible but simple way for applications to perform these cross-functional tasks.
Symbian OS provides a substantial framework to support views, called the view architecture. It was developed to provide a flexible environment within which individual applications exist, but the user can easily perform tasks that happen to be implemented across multiple applications.
The view architecture has two key components: a set of views and the view server. Views are UI controls, ultimately derived from CCoeControl, which implement the abstract view interface defined by MCoeView. All views need to inherit CQikViewBase. Applications supply the views.
Figure 15 UIQ 3 Applications, Views and DNLs between views
The view server is a system-wide component responsible for coordinating the changing of views displayed on a phone. It is implemented as a separate process, hence its name. The view server facilitates the switching of views dependant on the task a user is performing rather than navigating by application. When switching from a view on one application to a view in another, it is called a Direct Navigation Link (DNL). These are described in detail in the Chapter Views and dialogs. Although implemented as a separate process, all the inter process communications with the view server are handled by the framework. Your application needs to interact with the UIQ 3 framework. This may seem complicated but we provide example applications to help you.
Anatomy of the Screen
We now take a look at the UIQ 3 screen in detail and describe the various parts of the UI.
Figure 16 Screen areas in Softkey Style
Figure 17 Screen areas in Pen Style
Status Bar
The status bar contains system indicators such as the battery level, Bluetooth state and mobile network signal strength. The content of the status bar is defined by the phone manufacturer and is not available to application developers. In Softkey Style Touch and Pen Style, the status bar items can be tapped to access further information and settings. In the screenshot below, you can see the task menu that Sony Ericsson has implemented and the battery status indicator.
Figure 18 Status bar on Sony Ericsson P1i
Your application can perform some basic actions such as hiding the status bar:
MEikAppUiFactory* q=iEikonEnv->AppUiFactory(); q->StatusPane()->MakeVisible(EFalse);
Title Bar
The exact content of a title bar varies between view configurations but the following components exist:
Figure 19 Title bar (Softkey Style Touch)
Title text
While this initially contains the application name, you can change the text, for example:
void CAppSpecificListView::ViewConstructL()
{
_LIT(KNewTitle,”New title”);
SetAppTitleNameL(KNewTitle);
}
In Pen Style configurations, an icon is displayed immediately to the right of the title indicating you can tap on it to display a menu.
Figure 20 Menu and category selection in the Contacts application (Pen Style)
If your application supports categories, then on Pen Style phones a second icon is displayed to the far right of the title bar.
To restore the content to the application name you can simply pass KNullDesc to the SetAppTitleNameL() method.
Icon
While this initially contains the application icon, you can change the icon, for example:
void CAppSpecificListView::ViewConstructL()
{
_LIT(KMbmFileName,”*”);
CFbsBitmap* bit=iEikonEnv->CreateBitmapL(
KMbmFileName,EMbmAppIcon);
CFbsBitmap* mask=iEikonEnv->CreateBitmapL(
KMbmFileName,EMbmAppMask);
SetAppTitleIconL(bit,mask);
}
To restore the content to the application icon pass NULL for the image and mask icons.
| Pro tip:
You may wish to note that |
View context area
This area is normally used to display tabs if your view is a multi-page view or to display some application-specific context information, such as a view title, in single page views.
For multi-page views the tab information is normally defined in a QIK_VIEW_PAGE application resource:
QIK_VIEW_PAGE
{
page_id = EAppSpecificListViewPageId1;
tab_bmpid = EMbmListview2Tab1;
tab_bmpmaskid = EMbmListview2Tab1mask;
page_content = r_list_view_page1_control;
},
QIK_VIEW_PAGE
{
page_id = EAppSpecificListViewPageId3;
tab_caption = "Tab3";
page_content = r_list_view_page3_control;
}
For single page views, you can set icons, text and/or progress information controls as decorators in the View context area, for example:
Figure 21 Text, icon and progress indicator controls in View context area
Here is the code:
TBuf<64>bb; iEikonEnv->ReadResource(bb,R_STR_VIEW_TITLE); ViewContext()->AddTextL(1,bb); _LIT(KMbmFile,”*”); CFbsBitmap* bit=iEikonEnv->CreateBitmapL(KMbmFile, EMbmAppIcon); CFbsBitmap* mask=iEikonEnv->CreateBitmapL(KMbmFile, EMbmAppMask); ViewContext()->AddIconL(2,bit,mask); ViewContext()->AddProgressInfoL(EEikProgressTextPercentage,100); ViewContext()->SetAndDrawProgressInfo(50);
| Pro tip:
While the above example does not contain any error handling code, you should note that the |
Button Bar
On Pen Style phones, applications usually have a button bar containing a Back button. Applications can specify any additional commands they wish to be displayed on the button bar, for example:
RESOURCE QIK_CONTENT_MBM r_function1_button
{
bmpid=EMbmAppIcon1;
bmpmask=EMbmAppIcon1mask;
}
QIK_COMMAND
{
id = EAppCmdFunction1;
type = EQikCommandTypeScreen;
cpfFlags = EQikCpfFlagPreferToBePlacedInButtonbar;
icon = r_function1_button;
},
Using icons in the button bar means that you can present more commands that the user can select with a single tap.
Figure 22 Button bar in Agenda application
Softkey Bar
In contrast to a button bar, the softkey bar on a Softkey Style phone usually only contains labels indicating which action will occur if a softkey is depressed.
While applications don’t have direct access to the button bar or softkey bar region, they can strongly influence what is displayed in those regions by appropriate usage of commands.
| Pro tip:
The button bar and softkey bar are treated quite differently within UIQ 3 and should not be considered as alternatives dependent on phone type. For example, the Command Processing Framework flag |
Figure 23 Softkey bar in Contacts
Sony Ericsson phones operating in Softkey Style Touch have a modified design for the softkey bar which looks like a button bar. By using button style labels, the user is reminded that the softkeys can be touched on screen.
Figure 24 Softkey bar on Sony Ericsson P1i
Application Space
Lastly, there is the application space region where your views are displayed.
Figure 25 Application space in Softkey Style
Figure 26 Application space in Pen Style
In general, applications should focus on only using the application-specific region but there are options to hide the other components therefore expanding this region. This code shows you how:
void CAppSpecificListView::ViewConstructL()
{
TQikViewMode mode = ViewMode();
// Normally only 1 of the following used at a time.
// Hides status bar.
mode.SetStatusBar(EFalse);
// Hides the title bar.
mode.SetAppTitleBar(EFalse);
// Hides button bar/soft key bar and status bar.
mode.SetButtonOrSoftkeyBar(EFalse);
// Applies the requested view mode.
SetViewModeL(mode);
}
There is also the option to use the entire screen:
void CAppSpecificListView::ViewConstructL()
{
TQikViewMode mode = ViewMode();
mode.SetFullscreen();
SetViewModeL(mode);
}
You should exercise care if you hide any of the standard components. Ease of use is often derived from a consistent user interface. Varying the interface presented by your application compared to standard applications, such as by hiding the status bar, may be detrimental to your application. On some real phones a Task switch and short cut icon is present within the status bar. If you choose to hide the status bar, the user looses the part of the UI that is normally there. Ensuring that you integrate with the features and functions on a phone can make the difference between happy customers and frustrated ones.





























