Building custom widgets with the Zinzala SDK - page 6

3. The cDConsoleView class

To build the multimedia console widget, we are going to derive the widget cDrawView. This class defines and implements a very basic type of widget, making it the perfect starting point for building a custom widget. It provides various drawing methods that we will be using to render the console contents.

Here's the declaration of cDConsoleView:

class cDConsoleView : public cDrawView { public: static cDConsoleView *NewL(cDSkin &aSkin); virtual ~cDConsoleView(); void SetState(tConsoleState aState); tConsoleState GetState() const {return iState;}; protected: virtual void PlayPressed(tBool aActive) {}; virtual void PausePressed(tBool aActive) {}; virtual void StopPressed(tBool aActive) {}; virtual void FwdPressed(tBool aActive) {}; virtual void BwdPressed(tBool aActive) {}; protected: void OnScreen(); void Beat(); void MouseUp(uPoint aPoint); void MouseDown(uPoint aPoint); void OutBound(uPoint aPoint); protected: cDConsoleView(); virtual void ConstructL(cDSkin &aSkin); private: tUint8 FindButton(uPoint aPoint) const; void Render(tUint8 aButton,tBool aBackground = false); void Pressed(tUint8 aButton); void Invoked(); private: typedef struct tButton; private: tConsoleState iState; // Console state cBitmap* iBackground; // Background bitmap cBitmap** iBStates; // Button's states bitmaps cBitmap** iBLabelsN; // Button's labels bitmaps (non dimmed) cBitmap** iBLabelsD; // Button's labels bitmaps (dimmed) tButton* iButtons; // Button's data tUint8 iPressedButton; // ID of the button currently pressed tUint8 iActiveButton; // ID of the button currently active tUint8 iPrevState; // Previous state of the current pressed button tInt8 iActiveDir; // Direction of the Active button animation };

The console defines five callback methods to be implemented by derived classes. PlayPressed() will respond to a user action on the Play button, PausePressed() on the Pause button, and so on. The console implements how to handle user actions in the methods MouseDown(), MouseUp() and OutBound().

The state of the console can be changed at anytime with the method SetState(). The console itself will not change its state, however; the state will be used when rendering the console. Here's the definition of tConsoleState:

enum tConsoleState { ePlaying, eStopped, ePaused, eForward, eBackward };

Construction & Destruction

Implementing a two-phase construction is not difficult. However, it does require a bit more coding than just a standard C++ constructor. The following methods are involved in the construction of an object: cDConsoleView(), ConstructL() and NewL(). NewL() is a factory function, the front-end of the creation of an object. Instead of using the new C++ operator, we will call this method to instantiate a new object. To enforce that NewL() is the only possibility for object instantiation, we have set the constructor as a protected method.

Let's see the code of the C++ constructor cDConsoleView():

cDConsoleView::cDConsoleView() : cDrawView(uRect(kConsoleWidth,kConsoleHeight),"console",kFollowNone, kFlgBeatNeeded | kFlgInteractive | kFlgOffscreen) { iBackground = NULL; iBStates = NULL; iBLabelsN = NULL; iBLabelsD = NULL; iButtons = NULL; iPressedButton = kButtonsCount; iActiveButton = kButtonsCount; iActiveDir = 1; iState = eStopped; if(!iFault) { iButtons = new tButton[kButtonsCount]; if(!iButtons) iFault = kErrOutOfMemory; else { iBStates = new (cBitmap *)[kStatesCount]; if(!iBStates) iFault = kErrOutOfMemory; else { memset(iBStates,0,sizeof(cBitmap *) * kStatesCount); iBLabelsN = new (cBitmap *)[kLabelsCount]; if(!iBLabelsN) iFault = kErrOutOfMemory; else { memset(iBLabelsN,0,sizeof(cBitmap *) * kLabelsCount); iBLabelsD = new (cBitmap *)[kLabelsCount]; if(!iBLabelsD) iFault = kErrOutOfMemory; else memset(iBLabelsD,0,sizeof(cBitmap *) * kLabelsCount); } } } } }

Using the two-phase construction idiom doesn't mean that no memory allocation should ever be done in the C++ constructor. But if we choose to do so, we must make sure that it can still be deleted if the construction fails and that the partially constructed object is destroyed.

After some initialization, we try to allocate the 4 arrays that will contain all the buttons data (iButtons) and the various corresponding bitmaps (iBStates, iBLabelsN, iBLabelsD). If any of the memory allocation fails, we will mark the object as faulty by setting the data member iFault to kErrOutOfMemory. This member variable is inherited from deep inside the Zinzala SDK (class pBase from the Cincinella Kit). Because the constructor of the base class cDrawView could be wrong, it is recommended that you test whether or not iFault already indicates a fault. There is no point in allocating more memory if we going to delete the object right away because it is faulty.

Print version

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