Let's suppose that we are building the application framework for a QNX based in-car device, similar to the ones made by G-Net. Our console widget is going to be one of the many custom widgets that will be available to the application developers. For instance, it could be used by the music and video player. Each application will use class derivations in order to program the console widget to perform specific actions when the user interacts with the GUI. For instance, causing the current audio track to start playing with the user presses the Play button.
The application framework (let's call it Carrozza) that we will be using to build our applications is not limited to the GUI side of the embedded system. It could also provide libraries for audio playback, data persistence or networking. This framework is simply an extra layer, intended to unify the development of every application by offering architects and developers all the components they will need. Of course, this doesn't forbid the use of some of the classes available from the lower layers. Providing a set of components designed to fit the common needs of all applications, help reduce the risk of duplication of code. This also leads to a modular solution where components can be selected, combined and reused. This provides a powerful, consistent and efficient platform.
Here's a representation of the layering:
Although Photon is part of the QNX platform, I have placed it on its own layer to show Zinzala's dependencies. We will expect application developers to only go as low as the Zinzala layer, which is composed of Cincinella and Farfalla. Low level components, such as a CD player control class, will probably require access to the QNX API. However, they will be made available to the application developers from the top layer.
Zooming in ...
Now that we have pitched the overall view, let's go back to the console widget. We will walk through the construction of the widget, and then show how to integrate it to a simple test application. Here's what we are going to look at:
- How to create a shared object from the raw skin graphics
- How the widget will use the skin
- How to render the console and each button's states
- How to render an animation effect for the active button
- How to handle user inputs
- How to support the change of skin on the fly
All the graphics we will be using have been created by hexaZen for this article. In a real system, images such as these would be provided to the development teams by the UI designers to ensure consistency across the entire product line.
Here is a green skin for example:
Button states (normal,
dimmed and pressed)
Active button animation
Button labels (normal)
Button labels (dimmed)
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, perhaps one with a bigger screen, 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.