Building custom widgets with the Zinzala SDK - page 7

The flags passed to the base class cDrawView sets a couple of behaviors for the widget. kFlgBeatNeeded indicates that the widget will make use of the window beat. At a given interval, the method Beat() of the widget will be called. We need this flag to render the animation of the active button. kFlgInteractive specifies that the widget will accept user inputs. The flag kFlgOffscreen is specific to the widget cDrawView, and indicates that we will be using an offscreen bitmap to render the widget in order to avoid any flickering. For instance, when drawing the animation.

Here's the definition of the various constants we have used in the constructor:

const tUint16 kConsoleWidth = 321; const tUint16 kConsoleHeight = 98; const tUint8 kButtonsCount = 4; const tUint8 kStatesCount = 7; const tUint8 kLabelsCount = 5;

We also need to define tButton whose implementation is hidden from the class users:

typedef struct cDConsoleView::tButton { uRect iBFrame; // frame of the button uRect iLFrame; // frame of the label tUint8 iState; // button state tUint8 iLabel; // label displayed on the button } tButton;

This type holds all the button specific information, such as its position within the console or its state.

The method ConstructL() contains the rest of the widget's construction where exceptions can be raised. Here's its implementation:

void cDConsoleView::ConstructL(cDSkin &aSkin) { uPoint lPoint; // If the view is already faulty, we will leave right away sEnv::LeaveIfError(iFault);

Because this method will be called right after the class constructor is called, the widget might already be faulty. If this is the case, there is no need to proceed, we will leave right away.

// Instantiate the background bitmap iBackground = CreateBitmapFromResourceL(aSkin.GetResourceL(eResBackground),false); // Instantiate the button bitmaps iBStates[kStateNormal] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResNormal)); iBStates[kStateDimmed] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResDimmed)); iBStates[kStatePressed] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResPressed)); iBStates[kStateActive] = iBStates[kStateNormal]; // use same bitmap as the normal state iBStates[kStateActive1] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResAnimate1)); iBStates[kStateActive2] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResAnimate2)); iBStates[kStateActive3] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResAnimate3)); // Instantiate the label bitmaps iBLabelsN[kLabelBwd] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResBackwardN)); iBLabelsN[kLabelFwd] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResForwardN)); iBLabelsN[kLabelStop] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResStopN)); iBLabelsN[kLabelPlay] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResPlayN)); iBLabelsN[kLabelPause] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResPauseN)); iBLabelsD[kLabelBwd] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResBackwardD)); iBLabelsD[kLabelFwd] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResForwardD)); iBLabelsD[kLabelStop] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResStopD)); iBLabelsD[kLabelPlay] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResPlayD)); iBLabelsD[kLabelPause] = CreateBitmapFromResourceL(aSkin.GetResourceL(eResPauseD));

The function CreateBitmapFromResourceL() that we will see later, instantiates a cBitmap from the resource contained in the skin. If something goes wrong, it will leave.

tUint16 lX = kPositionX; // initialize the buttons data (all are dimmed) for(tUint8 i=0;i<kButtonsCount;i++) { iButtons[i].iState = kStateDimmed; iButtons[i].iLabel = i; iButtons[i].iBFrame.Set(lX,kPositionY,lX + kButtonWidth,kPositionY + kButtonHeight); lPoint.Set(lX + kButtonWidth / 2,kPositionY + kButtonHeight / 2); lPoint.iX -= kLabelWidth / 2; lPoint.iY -= kLabelHeight / 2; iButtons[i].iLFrame.Set(lPoint.iX,lPoint.iY,lPoint.iX+kLabelWidth,lPoint.iY+kLabelHeight); lX += kButtonWidth + kSpacing; }

Besides initializing the button's data, we compute its position within the console and its label's position, which is always centered within the button.

// The play button is not dimmed by default iButtons[kButtonPlay].iState = kStateNormal; }

Here's the definition of the various constants we have used in ConstructL():

const tUint16 kButtonWidth = 64; const tUint16 kButtonHeight = 64; const tUint16 kLabelWidth = 25; const tUint16 kLabelHeight = 25; const tUint16 kPositionX = 18; const tUint16 kPositionY = 17; const tUint16 kSpacing = 10; const tUint8 kButtonBwd = 0; const tUint8 kButtonPlay = 1; const tUint8 kButtonPause = 2; const tUint8 kButtonFwd = 3; const tUint8 kStateDimmed = 0; const tUint8 kStatePressed = 1; const tUint8 kStateNormal = 2; const tUint8 kStateActive = 3; const tUint8 kStateActive1 = 4; const tUint8 kStateActive2 = 5; const tUint8 kStateActive3 = 6; const tUint8 kLabelBwd = 0; const tUint8 kLabelPlay = 1; const tUint8 kLabelPause = 2; const tUint8 kLabelFwd = 3; const tUint8 kLabelStop = 4;

In order to instantiate the class cDConsoleView, we now need to implement the method NewL(). It's simple and short:

cDConsoleView *cDConsoleView::NewL(cDSkin &aSkin) { cDConsoleView *lView = new cDConsoleView(); cDConsoleView::VerifyLC(lView); lView->ConstructL(aSkin); sCleanupStack::PopL(lView); return lView; }

As you can see, we first construct a new object using the standard C++ operator new. Then we use the method VerifyLC(), inherited from the base class pBase, to verify that the object is valid. The LC at the end of the method's name indicates that it can leave. If it doesn't leave, the object in lView will be left on the cleanup stack. We need the object to be on the stack before we call the ConstructL() method on the object. Since this method can leave, we need to make sure that it will be deleted automatically when the exception is handled. If there is no problem in the construction of the object, we will pop the object from the stack then return it.

Print version

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