examples/AppFramework/UIControls/CustomControls/CustomControls.cpp

00001 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
00002 // All rights reserved.
00003 // This component and the accompanying materials are made available
00004 // under the terms of "Eclipse Public License v1.0"
00005 // which accompanies this distribution, and is available
00006 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
00007 //
00008 // Initial Contributors:
00009 // Nokia Corporation - initial contribution.
00010 //
00011 // Contributors:
00012 //
00013 // Description:
00014 // UI Control Framework example program
00015 // This example demonstrates how to write new control classes.
00016 // The example creates three new control classes:
00017 // 1. CSmiley              - a simple control which displays a 
00018 // smiley face that can have two moods,
00019 // happy and sad. The user can change
00020 // the smiley's mood by pressing the
00021 // space bar.
00022 // 2. CSmileyContainer     - a compound control which contains
00023 // two CSmiley controls, side by side.
00024 // The user can move the keyboard focus
00025 // from one CSmiley to the other using
00026 // the arrow keys, or the pointer.
00027 // 3. CMainWinControl      - a compound control which does nothing
00028 // except act as a background window and a 
00029 // container for other controls in the 
00030 // application.
00031 // When the application starts up, it creates a CMainWinControl to cover
00032 // the entire screen, and a CSmileyContainer inside this main window.
00033 // The application's menu contains just two options. One of them closes 
00034 // the application; the other creates a dialog which contains a 
00035 // CSmileyContainer. CSmileyContainer therefore illustrates how to write 
00036 // a control that can be created both in a dialog and within the
00037 // application's main view.
00038 //
00039 
00040 #include "CustomControls.h"
00041 #include <eikstart.h>
00042 
00043 
00045 //
00046 // -----> CMainWinControl(implementation)
00047 //
00049 CMainWinControl::CMainWinControl()
00050         {
00051         }
00052 
00053 CMainWinControl::~CMainWinControl()
00054         {
00055         delete iContainer;
00056         }
00057 
00058 // CMainWinControl needs a ConstructL(), because it is a compound control
00059 // (and a window-owning control).
00060 void CMainWinControl::ConstructL(const TRect& rect)
00061         {
00062         // Make this a window-owning control.
00063         CreateWindowL();
00064         SetRect(rect);
00065 
00066         // Create its only component, a CSmileyContainer
00067         iContainer = new(ELeave) CSmileyContainer;
00068         iContainer->SetContainerWindowL(*this);
00069         TRect containerRect=Rect();
00070         iContainer->ConstructL(containerRect);
00071         // Activate the main window control - this will also activate the 
00072         // CSmileyContainer and its components.
00073         ActivateL();
00074         DrawNow();
00075         }
00076 
00077 // The following two functions have to be implemented for all compound controls.
00078 TInt CMainWinControl::CountComponentControls() const
00079         {
00080         return 1;
00081         }
00082 
00083 CCoeControl* CMainWinControl::ComponentControl(TInt /*aIndex*/) const
00084         {
00085         return iContainer;
00086         }
00087 
00088 // Draw the main window.
00089 void CMainWinControl::Draw(const TRect& /*aRect*/) const
00090         {
00091         CWindowGc& gc=SystemGc();
00092         gc.SetBrushColor(KRgbWhite);
00093         gc.Clear(Rect());
00094         }
00095 
00096 // CSmileyContainer can't be put on the control stack, because it's a component of this 
00097 // control. The main window control goes on the stack and passes on any key events it gets
00098 // to the CSmileyContainer.
00099 TKeyResponse CMainWinControl::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType)
00100         {
00101         return (iContainer->OfferKeyEventL(aKeyEvent, aType));
00102         }
00103 
00105 //
00106 // -----> CSmileyContainer (implementation)
00107 //
00109 CSmileyContainer::CSmileyContainer()
00110         {}
00111 
00112         
00113 CSmileyContainer::~CSmileyContainer()
00114         {
00115           // Delete all the contained controls 
00116         delete iSmiley1;
00117         delete iSmiley2;
00118         }
00119 
00120 
00121 // Because CSmileyContainer is a compound control, it needs a
00122 // ConstructL() for when it's created outside a dialog, and a
00123 // ConstructFromResourceL() for when it's created inside a dialog.
00124 void CSmileyContainer::ConstructL(const TRect& aRect)
00125         {
00126         TBool isSmiling=ETrue;
00127 
00128         // Create the two CSmileys. Their size and position is 
00129         // set in CSmileyContainer::SizeChangedL().
00130         iSmiley1 = new(ELeave) CSmiley(isSmiling);
00131         iSmiley1->SetContainerWindowL(*this);
00132 
00133         isSmiling=EFalse;
00134 
00135         iSmiley2 = new(ELeave) CSmiley(isSmiling);
00136         iSmiley2->SetContainerWindowL(*this);
00137 
00138         iSmiley1->SetFocus(ETrue);
00139 
00140         // Set the container as the observer of the two CSmileys. This 
00141         // is for handling keyboard focus. When an arrow key is pressed 
00142         // or the pointer is clicked on one of the CSmileys, an 
00143         // EEventRequestFocus event is sent to the container, and the
00144         // container changes the focus if applicable.
00145         iSmiley1->SetObserver(this);
00146         iSmiley2->SetObserver(this);
00147 
00148         // Set the bounding rectangle of this control (this will result in 
00149         // a call to SizeChangedL(). The component controls must be 
00150         // created before calling this, because SizeChangedL() sets their
00151         // sizes.
00152         SetRect(aRect);
00153         }
00154 
00155 
00156 // This function is used when the CSmileyContainer is created inside a dialog.
00157 void CSmileyContainer::ConstructFromResourceL(TResourceReader& aReader)
00158         {
00159         // Read the smiley mood from the resource file
00160         TBool isSmiling=(TBool)aReader.ReadInt8();
00161         // Read the width of the smiley container from the resource file.
00162         TInt width=aReader.ReadInt16();
00163         // Set the height of the container to be half its width
00164         TSize containerSize (width, width/2);
00165 
00166         iSmiley1 = new(ELeave) CSmiley(isSmiling);
00167         iSmiley1->SetContainerWindowL(*this);
00168 
00169         iSmiley2 = new(ELeave) CSmiley(isSmiling);
00170         iSmiley2->SetContainerWindowL(*this);
00171 
00172         iSmiley1->SetFocus(ETrue);
00173 
00174         iSmiley1->SetObserver(this);
00175         iSmiley2->SetObserver(this);
00176 
00177         SetSize(containerSize);
00178 
00179         ActivateL();    
00180         }
00181 
00182 // The following two functions have to be implemented for all compound controls.
00183 TInt CSmileyContainer::CountComponentControls() const
00184         {
00185         return 2;
00186         }
00187 
00188 CCoeControl* CSmileyContainer::ComponentControl(TInt aIndex) const
00189         {
00190         if (aIndex==0)
00191                 return iSmiley1;
00192         else
00193                 return iSmiley2;
00194         }
00195 
00196 // This function gets called whenever one of the size-setting functions is called.
00197 // As this is a compound control, this function calculates and sets the size and  
00198 // position for its components, based on its own size.
00199 void CSmileyContainer::SizeChanged()
00200     {
00201         TInt containerWidth=Size().iWidth;
00202         TInt containerHeight=Size().iHeight;
00203         // Find half of the greater - width or height
00204         TInt length=containerHeight>containerWidth ? containerWidth/4 : containerHeight/4; 
00205         TSize smileySize(length,length);
00206 
00207         // Do some preliminary calculations so that Draw() is as short
00208         // as possible.
00209         TInt xOffset=smileySize.iWidth/4; // x offset from the center
00210         TInt yOffset=(containerHeight - smileySize.iHeight) / 2;
00211         iSmiley1->SetPosition(Position() +
00212                 TPoint(containerWidth/2 - smileySize.iWidth - xOffset, yOffset));
00213         iSmiley2->SetPosition(Position() + 
00214                 TPoint(containerWidth/2 + xOffset, yOffset));
00215         // Calling SetSizeL() causes the components' SizeChanged() to be called.
00216         iSmiley1->SetSize(smileySize);
00217         iSmiley2->SetSize(smileySize);
00218         }
00219         
00220 void CSmileyContainer::Draw(const TRect& aRect) const
00221         {
00222         // Just draw a rectangle round the edge of the control.
00223         CWindowGc& gc=SystemGc();
00224         gc.Clear(aRect);
00225         gc.SetClippingRect(aRect);
00226         gc.DrawRect(Rect());
00227         }
00228 
00229 // This function is defined by MCoeControlObserver. It gets called whenever
00230 // a control that this control is observing calls ReportEventL().
00231 // In this example, the CSmileyContainer is the observer for both of the 
00232 // CSmileys.  CCoeControl::ProcessPointerEventL() calls ReportEvent(), 
00233 // sending an event of type EEventRequestFocus, whenever an EButton1Down event
00234 // occurs in the CSmiley that doesn't currently have focus.
00235 void CSmileyContainer::HandleControlEventL(CCoeControl* aControl,
00236                                                                                 TCoeEvent aEventType)
00237         {
00238         switch (aEventType)
00239                 {
00240                 case EEventRequestFocus:
00241                         {
00242                         if (aControl->IsFocused())
00243                                 return;
00244                         SwapFocus(aControl);
00245                         }
00246                         break;
00247                 default:
00248                         break;
00249                 }
00250         }
00251 
00252 // This function is called by the framework whenever a component in a dialog is 
00253 // about to lose focus. It checks that the data in ithe component is valid. In
00254 // this example, there's a "rule" that both the CSmileys in the container can't
00255 // be miserable! If they are, the function leaves. The framework issues the message 
00256 // we give it, and doesn't move focus away from the CSmileyContainer.
00257 void CSmileyContainer::PrepareForFocusLossL()   
00258         {
00259         if (!iSmiley1->IsSmiling() && !iSmiley2->IsSmiling())
00260                 {
00261                 CEikonEnv::Static()->LeaveWithInfoMsg(R_EXAMPLE_TEXT_VALIDATE);
00262                 }
00263         }
00264 
00265 // This function gets called whenever the application calls SetFocus().
00266 // It redraws the CSmileyContainer, so that they are updated to show 
00267 // which one now has focus.
00268 void CSmileyContainer::FocusChanged(TDrawNow aDrawNow)
00269         {
00270         if (IsFocused())
00271                 {
00272                 iSmiley1->SetFocus(ETrue, EDrawNow);
00273                 }
00274         else
00275                 {
00276                         if (iSmiley1->IsFocused())
00277                         iSmiley1->SetFocus(EFalse, EDrawNow);
00278                         else
00279                         iSmiley2->SetFocus(EFalse, EDrawNow);
00280                 }
00281         if (aDrawNow)
00282                 DrawNow();
00283         }
00284 
00285 
00286 void CSmileyContainer::SwapFocus(CCoeControl* aControl)
00287         {
00288         if (aControl==iSmiley1)
00289                 {
00290                 iSmiley2->SetFocus(EFalse, EDrawNow);
00291                 iSmiley1->SetFocus(ETrue, EDrawNow);
00292                 }
00293         else
00294                 {
00295                 iSmiley1->SetFocus(EFalse, EDrawNow);
00296                 iSmiley2->SetFocus(ETrue, EDrawNow);
00297                 }
00298         }
00299 
00300 TKeyResponse CSmileyContainer::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
00301         {
00302         // Use the arrow keys to move focus between the two CSmileys.
00303         switch (aKeyEvent.iScanCode)
00304                 {
00305                 case EStdKeySpace:
00306                         if (iSmiley1->IsFocused())
00307                                 return iSmiley1->OfferKeyEventL(aKeyEvent, aType);
00308                         else if (iSmiley2->IsFocused())
00309                                 return iSmiley2->OfferKeyEventL(aKeyEvent, aType);
00310                         break;
00311                 case EStdKeyRightArrow:
00312                         if (iSmiley1->IsFocused())
00313                                 SwapFocus(iSmiley2);
00314                         else
00315                         return EKeyWasConsumed;
00316                         break;
00317                 case EStdKeyLeftArrow:
00318                         if (iSmiley2->IsFocused())
00319                                 SwapFocus(iSmiley1);
00320                         else
00321                         return EKeyWasConsumed;
00322                         break;
00323                 default:
00324                         break;
00325                 }
00326         // If the CSmileyContainer didn't use the key event, it must return EKeyWasNotConsumed,
00327         // so that the key event is passed to other controls on the stack.
00328         return EKeyWasNotConsumed;
00329         }
00330 
00331 
00332 
00333 
00335 //
00336 // -----> CSmiley (implementation)
00337 //
00339 
00340 // CSmiley doesn't need a ConstructL() because it's a simple control.
00341 
00342 CSmiley::CSmiley(TBool aSmiling) : iSmiling(aSmiling)
00343         {
00344         }
00345 
00346 CSmiley::~CSmiley()
00347         {
00348         }
00349 
00350 TBool CSmiley::IsSmiling()
00351         {
00352         return iSmiling;
00353         }
00354 
00355 void CSmiley::Draw(const TRect& aRect) const
00356         {
00357         CWindowGc& gc=SystemGc();
00358         if (IsFocused())
00359                 {
00360                 gc.SetPenColor(KRgbBlack);
00361                 }
00362         else
00363                 {
00364                 gc.SetPenColor(KRgbWhite);
00365                 }
00366         gc.SetBrushColor(KRgbWhite);
00367         gc.Clear(Rect());
00368         gc.DrawRect(Rect());
00369 
00370         gc.SetClippingRect(aRect);
00371 
00372         // Draw the smiley face, smiling or looking sad
00373         gc.SetPenColor(KRgbBlack);
00374         // Draw a circle for the face
00375         gc.DrawEllipse(iSmileyRect);
00376         // Draw the eyes
00377         TPoint leftEye(iSmileyWidth/3, iSmileyHeight/3);
00378         TPoint rightEye(iSmileyWidth*2/3, iSmileyHeight/3);
00379         gc.SetPenSize(TSize(5,5));
00380         gc.Plot(iSmileyRect.iTl+leftEye);
00381         gc.Plot(iSmileyRect.iTl+rightEye);
00382         //Draw the mouth, smiling or looking sad.
00383         gc.SetPenSize(TSize(1,1));
00384         gc.SetPenColor(KRgbWhite);
00385         if (iSmiling)
00386                 gc.DrawArc(iFrownRect, iFrownRect.iTl+TPoint(iSmileyWidth/2,iFrownRect.Height()/2), 
00387                                                           iFrownRect.iTl+TPoint(0,iFrownRect.Height()/2));
00388         else
00389                 gc.DrawArc(iSmileRect, iSmileRect.iTl+TPoint(0,iSmileRect.Height()/2), 
00390                                                           iSmileRect.iTl+TPoint(iSmileyWidth/2,iSmileRect.Height()/2));
00391         gc.SetPenColor(KRgbBlack);
00392         if (iSmiling)
00393                 gc.DrawArc(iSmileRect, iSmileRect.iTl+TPoint(0,iSmileRect.Height()/2), 
00394                                                           iSmileRect.iTl+TPoint(iSmileyWidth/2,iSmileRect.Height()/2));
00395         else
00396                 gc.DrawArc(iFrownRect, iFrownRect.iTl+TPoint(iSmileyWidth/2,iFrownRect.Height()/2), 
00397                                                           iFrownRect.iTl+TPoint(0,iFrownRect.Height()/2));
00398         }
00399 
00400 void CSmiley::SizeChanged()
00401         {
00402         // Calculate sizes of rectangles for drawing face and mouth
00403         iSmileyRect=Rect();
00404         // Allow room for the focus rectangle round the outside
00405         iSmileyRect.Shrink(3,3);
00406         iSmileyWidth=iSmileyRect.Width();
00407         iSmileyHeight=iSmileyRect.Height();
00408         iSmileRect.SetRect(iSmileyRect.iTl+TPoint(iSmileyWidth/4, iSmileyHeight/2),
00409                                         TSize(iSmileyWidth/2, iSmileyHeight/3));
00410         iFrownRect.SetRect(iSmileyRect.iTl+TPoint(iSmileyWidth/4, iSmileyHeight*2/3),
00411                                         TSize(iSmileyWidth/2, iSmileyHeight/3));
00412         }
00413 
00414 void CSmiley::FocusChanged(TDrawNow aDrawNow)
00415         {
00416         if (aDrawNow)
00417                 DrawNow();
00418         }
00419 
00420 void CSmiley::HandlePointerEventL(const TPointerEvent& aPointerEvent)
00421         {
00422         if (aPointerEvent.iType==TPointerEvent::EButton1Down)
00423                 {
00424                 iSmiling = !iSmiling;
00425                 DrawNow();
00426                 }
00427         }
00428 
00429 TKeyResponse CSmiley::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
00430         {
00431         // The space bar changes the "mood" of the CSmiley.
00432         if (aType==EEventKey && aKeyEvent.iScanCode==EStdKeySpace)
00433                 {
00434                 iSmiling = !iSmiling;
00435                 DrawNow();
00436                 return EKeyWasConsumed;
00437                 }
00438         else
00439                 {
00440                 return EKeyWasNotConsumed;
00441                 }
00442         }
00443 
00445 //
00446 // -----> CSmileyDialog(implementation)
00447 //
00449 TBool CSmileyDialog::RunDlgLD()
00450         {
00451         CEikDialog* dialog = new (ELeave) CSmileyDialog();
00452         return (dialog->ExecuteLD(R_SMILEY_DIALOG));
00453         }
00454 
00455 // This function is used by CEikForm::ConstructByTypeL() to create the custom 
00456 // control within the dialog.
00457 SEikControlInfo CSmileyDialog::CreateCustomControlL(TInt aControlType)
00458         {
00459         SEikControlInfo controlInfo;
00460         controlInfo.iControl = NULL;
00461         controlInfo.iTrailerTextId = 0;
00462         controlInfo.iFlags = 0;
00463 
00464     switch (aControlType)
00465         {
00466     case ESmileyControl:
00467                 controlInfo.iControl = new(ELeave) CSmileyContainer;
00468                 break;
00469         default:
00470                 break;
00471                 }
00472     return controlInfo;
00473         }
00474 
00476 //
00477 // -----> CExampleAppUi (implementation)
00478 //
00480 void CExampleAppUi::ConstructL()
00481         {
00482           // Allow base class (CEikAppUi) to perform necessary construction
00483         BaseConstructL();
00484         // Construct the CMainWinControl which forms the main view
00485         // for this application.
00486         iMainWinControl=new(ELeave) CMainWinControl;
00487         iMainWinControl->ConstructL(ClientRect());
00488         // The main window is added to the control stack (for key event
00489         // handling).   
00490         AddToStackL(iMainWinControl);
00491         }
00492         
00493 
00494 CExampleAppUi::~CExampleAppUi()
00495         {
00496         RemoveFromStack(iMainWinControl);
00497           // Delete the main window
00498         delete iMainWinControl;
00499         }
00500 
00501 void CExampleAppUi::HandleCommandL(TInt aCommand)
00502         {
00503           // Handle the command generated by:
00504           //   1. menu item selection
00505           //   2. short-cut key press
00506         switch (aCommand)
00507                 {
00508         // EXIT comand
00509         case EEikCmdExit:
00510                 OnCmdExit();
00511                 break;
00512         case ECreateSmileyDialog:
00513                 CSmileyDialog::RunDlgLD();
00514                 break;
00515         default :
00516                 break;
00517                 }
00518         }
00519 
00520 void CExampleAppUi::OnCmdExit()
00521         {
00522         CBaActiveScheduler::Exit();
00523         }
00524 
00525 void CExampleAppUi::HandleModelChangeL()
00526         {
00527         }
00528 
00530 //
00531 // -----> CExampleDocument (implementation)
00532 //
00534 
00535 CExampleDocument::CExampleDocument(CEikApplication& aApp)
00536          : CEikDocument(aApp)
00537         {}
00538 
00539 CExampleDocument::~CExampleDocument()
00540         {
00541         }
00542 
00543 CExampleDocument* CExampleDocument::NewL(CEikApplication& aApp)
00544         {
00545         CExampleDocument* self=new(ELeave) CExampleDocument(aApp);
00546         CleanupStack::PushL(self);
00547         self->CreateModelL();
00548         CleanupStack::Pop();
00549         return self;
00550         }
00551 
00552 void CExampleDocument::ResetModelL()
00553         {
00554         CreateModelL();
00555         }
00556 
00557 void CExampleDocument::CreateModelL()
00558         {
00559         }
00560 
00561 CEikAppUi* CExampleDocument::CreateAppUiL()
00562         {
00563     return(new(ELeave) CExampleAppUi);
00564         }
00565 
00566 void CExampleDocument::NewDocumentL()
00567         {
00568         ResetModelL();
00569         }
00570 
00571 void CExampleDocument::StoreL(CStreamStore& /*aStore*/,CStreamDictionary& /*aStreamDic*/) const
00572         {
00573         }
00574 
00575 void CExampleDocument::RestoreL(const CStreamStore& /*aStore*/,const CStreamDictionary& /*aStreamDic*/)
00576         {
00577         }
00578 
00579 
00581 //
00582 // -----> CExampleApplication (implementation)
00583 //
00585 TUid CExampleApplication::AppDllUid() const
00586         {
00587         return(KUidExampleApp);
00588         }
00589 
00590 
00591 CApaDocument* CExampleApplication::CreateDocumentL()
00592         {
00593         return CExampleDocument::NewL(*this);
00594         }
00595 
00596 
00597 //
00598 // EXPORTed functions
00599 //
00600 
00601 
00602 LOCAL_C CApaApplication* NewApplication()
00603         {
00604         return new CExampleApplication;
00605         }
00606         
00607 GLDEF_C TInt E32Main()
00608         {
00609         return EikStart::RunApplication(NewApplication);
00610         }
00611 
00612 
00613 
00614 
00615 

Generated by  doxygen 1.6.2