Building custom widgets with the Zinzala SDK - page 2

Here is a green skin for example:

Button states (normal, dimmed and pressed)
normal state of button dimmed state of button pressed state of button
64x64 pixels
Active button animation
button in normal state normal button takes on first animated state normal button takes on second animated state normal button takes on third animated state
64x64 pixels
Button labels (normal state)
forward label for normal button pause label for normal button play label for normal button rewind label for normal button stop label for normal button
25x25 pixels
Button labels (dimmed state)
forward label for dimmed button pause label for dimmed button play label for dimmed button rewind label for dimmed button stop label for dimmed button
25x25 pixels
Console background
console background
321x98 pixels

The following figure indicates the position of each of the 4 buttons:

positioning of the 4 buttons

Like many other custom UI, the size and position of our UI elements will be fixed, even when we change skin. This means that if we were to reuse the same widget on a different product with a bigger screen for example, we may have to adapt it instead of just reusing it. A better solution would be to use a scalable UI framework, which would allow each element of the UI to adapt its position and size according to the form factor and UI layout of the product. Such frameworks are not widely in use, although they do increase the reusability of the applications (develop once for any screen size and layout) from a product to another one. This is about to change for some embedded systems such as the smartphones based on Symbian Series 60.

A few considerations

Before we get down to business, let's talk a little about coding conventions and practices that we are going to use. The coding style might be new to you, unless you have already been exposed to some Symbian programming. We will also be using exceptions for error handling associated with two very interesting things called two-phase construction and cleanup stack.

The need for both mechanisms arises from the fact that an embedded system must be stable and must run for a long period of time. This puts pressure on the applications to avoid memory leak, and to be robust to situations where resources are low. Error conditions must also be handled in a safe and appropriate fashion.

The cleanup stack provides a way of cleaning objects allocated on the heap, whose pointers will be lost when an exception occurs. Because a class destructor will not be called on a partially created object, a C++ constructor should not throw an exception in order to avoid memory leak. It is recommended that you use a two-phase construction. This also gives the opportunity to push objects on the cleanup stack. If you have some Symbian experience, it will look very familiar (I hope).

Since we are only focusing on building a custom widget, we are not going to discuss the purpose and usefulness of the two-phase construction and cleanup stack in detail. Instead, you may want to read the first Zinzala newsletter or a document on the Series 60 Application Development to learn more about them.

2. Implementing skinability

In order to support skinability in the widget, we need to answer these two questions: How do I transform a graphic into something useful for the widget? And, how will the widget access it?

Turning a GIF into a resource

Instead of letting the widget load each graphic file, we are going to process and store them into one shared object (a .so). This solution saves the widget the need of transforming each image from a GIF file to a cBitmap object each time we construct it. It also presents a more elegant solution, since all the graphics will be in one file. Now, we are going to transform all our graphics into a set of resources. For that purpose we are going to create a simple tool, which outputs given GIF files into a C++ file to be compiled. We will be calling it img2res.

Loading an image into a cBitmap

First, we will see how we can load a given graphic file into a cBitmap object, which defines a basic bitmap. The current version of the Zinzala SDK does not provide any mechanism to do so in the way BeOS was using translators, so we are going to use a little bit of pure Photon API.

Here's the implementation of the function LoadBitmap():

cBitmap *LoadBitmap(const tChar *aFilename) { PhImage_t* lImage = NULL; PiLoadInfo_t lInfo; PiIoHandler_t* lHandler; const tChar* lExt; tUint16 lPos; // extract extension of the image if(sStrTools::FindLast(aFilename,'.',&lPos)) {

In order to load an image, we need to find out what the image format is from its file extension. By using the static class sStrTools, which provides many methods to manipulate strings, we can search for the position of the last dot in the string. The file extension will be everything after the last dot. If that character cannot be found, sStrTools::FindLast() will return false.

// get the handler for the image format lExt = &aFilename[lPos+1]; lHandler = PiIoGetHandlerByExt(lExt); if(lHandler) {

Print version

All content © 2004-2007, hexaZen - Vancouver BC, Canada