examples/AppFramework/UIControls/CustomControls/CustomControls.cpp

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

Generated by  doxygen 1.6.2