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
Copyright ©2010 Nokia Corporation and/or its subsidiary(-ies).
All rights
reserved. Unless otherwise stated, these materials are provided under the terms of the Eclipse Public License
v1.0.