exampleapps/alfexanalogdialer/src/alfexanalogdialercontrol2.cpp
changeset 0 15bf7259bb7c
equal deleted inserted replaced
-1:000000000000 0:15bf7259bb7c
       
     1 /*
       
     2 * Copyright (c) 2008-2008 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:   Implementation of member functions of 
       
    15 *                AlfExAnalogDialerControl.
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 
       
    21 #include <coemain.h>
       
    22 
       
    23 // Visuals
       
    24 #include <alf/alfgridlayout.h>
       
    25 #include <alf/alftextvisual.h>
       
    26 #include <alf/alfimagevisual.h>
       
    27 #include <alf/alflinevisual.h>
       
    28 
       
    29 // Layouts
       
    30 #include <alf/alfdecklayout.h>
       
    31 #include <alf/alfcurvepath.h>
       
    32 #include <alf/alfcurvepathlayout.h>
       
    33 
       
    34 // Brushes
       
    35 #include <alf/alfborderbrush.h>
       
    36 #include <alf/alfbrusharray.h>
       
    37 #include <alf/alfimagebrush.h>
       
    38 #include <alf/alfimage.h>
       
    39 #include <alf/alfshadowborderbrush.h>
       
    40 #include <alf/alfgradientbrush.h>
       
    41 
       
    42 // Unsorted
       
    43 #include <aknutils.h>
       
    44 #include <alf/alftransformation.h>
       
    45 #include <alf/alfevent.h>
       
    46 #include <alf/alfdisplay.h>
       
    47 #include <alf/alfenv.h>
       
    48 #include <alf/alfmappingfunctions.h>
       
    49 #include <alf/alfroster.h>
       
    50 
       
    51 #include <e32math.h>
       
    52 
       
    53 #include "alfexanalogdialercontrol.h"
       
    54 #include "alfexanalogdialerfeedback.h"
       
    55 
       
    56 // Image names
       
    57 _LIT(KImageAnalogDialerBackground, "background.png");
       
    58 _LIT(KImageAnalogDialerNumbers, "numbers.png");
       
    59 _LIT(KImageAnalogDialerPlate, "plate.png");
       
    60 _LIT(KImageAnalogDialerStopper, "stopper.png");
       
    61 
       
    62 #define RADTODEG(Rad) ((180.0 * Rad) / KPi)
       
    63 
       
    64 // dimension of grid
       
    65 const TInt KDimensionsOfGrid = 2;
       
    66 
       
    67 // Tags for visuals which have always same appearance. 
       
    68 // TTagAnalogDialerVisual is used for indexing
       
    69 const char* KTagArrayTheRest[] =
       
    70     {
       
    71     "main",
       
    72     "display",
       
    73     "phone",
       
    74     "plate-deck",
       
    75     "plate-image",
       
    76     "stopper"
       
    77     };     
       
    78 
       
    79 // Dimensions of grid. iLayoutMode is used for indexing
       
    80 const TInt KRowsAndColumnsOfGrid[][KDimensionsOfGrid] =
       
    81     {
       
    82     { 1, 2 },   // columns, rows
       
    83     { 2, 1 }  
       
    84     };
       
    85      
       
    86 // Templates for displaying number
       
    87 _LIT(KNumberDisplayTemplate, "%d");
       
    88 
       
    89 // Radius of Clear area of plate. Per cents from radius of plate.
       
    90 const TInt KPlateClearRadius = 25;
       
    91 
       
    92 // Unit speed of returning plate to idle position
       
    93 const TInt KPlateReturnSpeed = 65;
       
    94 
       
    95 // As dragging events occur very often, redrawing plate is optimised that
       
    96 // it is not drawn after every dragging event. Change of KPlateDraggingDelta 
       
    97 // degrees is needed.
       
    98 const TInt KPlateDraggingDelta = 2;
       
    99 
       
   100 // position of stopper in degrees. Angle is 43
       
   101 const TInt KStopperAngle = 360-43;
       
   102 
       
   103 // Angle of first number
       
   104 // Numbers are on angle between KPlateNumbersStartAngle and (KPlateNumbersStartAngle + KPlateNumbersDistributionAngle)
       
   105 const TInt KPlateNumbersStartAngle = 3;
       
   106 
       
   107 // angle of arch on which numbers (or holes of plate) are distributed
       
   108 // Numbers are on angle between KPlateNumbersStartAngle and (KPlateNumbersStartAngle + KPlateNumbersDistributionAngle)
       
   109 const TInt KPlateNumbersDistributionAngle = 290;
       
   110 
       
   111 // minimum rotation of plate that number becomes selected
       
   112 const TInt KPlateMinimumRotateAngle=43;
       
   113 
       
   114 // font color 
       
   115 const TRgb KFontColor = TRgb(192,192,192);
       
   116 // Size of padding of the root grid layout
       
   117 //const TReal32 KPaddingPercentage = .05;
       
   118 
       
   119  
       
   120 // ---------------------------------------------------------------------------
       
   121 // NewL
       
   122 // ---------------------------------------------------------------------------
       
   123 //
       
   124 CAlfExAnalogDialerControl* CAlfExAnalogDialerControl::NewL(CAlfEnv& aEnv)
       
   125     {
       
   126     CAlfExAnalogDialerControl* self = CAlfExAnalogDialerControl::NewLC(aEnv);
       
   127     CleanupStack::Pop(self);
       
   128     return self;
       
   129     }
       
   130 
       
   131 // ---------------------------------------------------------------------------
       
   132 // NewLC
       
   133 // ---------------------------------------------------------------------------
       
   134 //
       
   135 CAlfExAnalogDialerControl* CAlfExAnalogDialerControl::NewLC(CAlfEnv& aEnv)
       
   136     {
       
   137     CAlfExAnalogDialerControl* self = new (ELeave) CAlfExAnalogDialerControl();
       
   138     CleanupStack::PushL(self);
       
   139     self->ConstructL(aEnv);
       
   140     return self;
       
   141     }
       
   142 
       
   143 // ---------------------------------------------------------------------------
       
   144 // ~CAlfExAnalogDialerControl
       
   145 // ---------------------------------------------------------------------------
       
   146 //
       
   147 CAlfExAnalogDialerControl::~CAlfExAnalogDialerControl()
       
   148     {
       
   149     if (iFlags & EAnalogDialerControlFlagLongTapRegistered)
       
   150         {
       
   151         Display()->Roster().RemovePointerEventObserver(EAlfPointerEventReportLongTap, *this);
       
   152         }
       
   153     Env().CancelCommands(this);
       
   154     delete iFeedback;
       
   155     }
       
   156 
       
   157 // ---------------------------------------------------------------------------
       
   158 // CAlfExAnalogDialerControl
       
   159 // ---------------------------------------------------------------------------
       
   160 //
       
   161 CAlfExAnalogDialerControl::CAlfExAnalogDialerControl()
       
   162         : CAlfControl()
       
   163     {
       
   164     }
       
   165 
       
   166 // ---------------------------------------------------------------------------
       
   167 // ConstructL
       
   168 // ---------------------------------------------------------------------------
       
   169 //
       
   170 void CAlfExAnalogDialerControl::ConstructL(CAlfEnv& aEnv)
       
   171     {
       
   172     CAlfControl::ConstructL(aEnv);
       
   173     // Id cannot be be set in constructor
       
   174 	SetId(KAlfExAnalogDialerControlId);
       
   175 
       
   176     // resolve layout: portrait or landscape
       
   177     iLayoutMode = ResolveLayout(iSquareSide,
       
   178                             iLongerSide);
       
   179     (iLayoutMode == ELayoutAnalogDialerPortrait) ? SetupPortraitModeL() : SetupLandscapeModeL();
       
   180 
       
   181     // set up vibra system
       
   182     iFeedback = CAlfExAnalogDialerFeedback::NewL();
       
   183     }   
       
   184     
       
   185     
       
   186     
       
   187 // ---------------------------------------------------------------------------
       
   188 // Creates layouts and visual for portrait layout
       
   189 // ---------------------------------------------------------------------------
       
   190 //
       
   191 void CAlfExAnalogDialerControl::SetupPortraitModeL()
       
   192     {
       
   193     // resolve layout: portrait or landscape
       
   194     AddGridLayoutL();
       
   195 
       
   196     // from top to bottom 1) display pane 2) dialer
       
   197     AddDisplayPaneL();
       
   198     AddDialerL();
       
   199     
       
   200     //AddEffectLayout();
       
   201     }
       
   202 
       
   203 // ---------------------------------------------------------------------------
       
   204 // Creates layouts and visual for portrait layout
       
   205 // ---------------------------------------------------------------------------
       
   206 //
       
   207 void CAlfExAnalogDialerControl::SetupLandscapeModeL()
       
   208     {
       
   209     // resolve layout: portrait or landscape
       
   210     AddGridLayoutL();
       
   211 
       
   212     // from left to right 1) dialer 2) display pane
       
   213     AddDialerL();
       
   214     AddDisplayPaneL();
       
   215     
       
   216     //AddEffectLayout();
       
   217     }
       
   218 
       
   219 
       
   220 // ---------------------------------------------------------------------------
       
   221 // Creates grid layout and returns it
       
   222 // ---------------------------------------------------------------------------
       
   223 //
       
   224 void CAlfExAnalogDialerControl::AddGridLayoutL()
       
   225     {
       
   226       // Create a grid layout to act as the root layout visual. Not owned
       
   227     if (!iRootLayout)
       
   228         {
       
   229         iRootLayout = CAlfGridLayout::AddNewL(*this, 
       
   230                                             KRowsAndColumnsOfGrid[iLayoutMode][EColumn], 
       
   231                                             KRowsAndColumnsOfGrid[iLayoutMode][ERow]);
       
   232         iRootLayout->SetTagL(_L8(KTagArrayTheRest[ETagAnalogDialerMain]));   
       
   233         // Brushed must enabled before they can be used
       
   234         iRootLayout->EnableBrushesL();      
       
   235 
       
   236         // Background image is implemented using image brush
       
   237         CAlfTexture& backgroundTexture = Env().TextureManager().LoadTextureL( 
       
   238                                             KImageAnalogDialerBackground,
       
   239                                             EAlfTextureFlagDefault, 
       
   240                                             KAlfAutoGeneratedTextureId);        
       
   241         // Default scale mode CAlfImageVisual::EScaleFit is OK
       
   242         CAlfImageBrush* brush = CAlfImageBrush::NewLC(Env(), TAlfImage(backgroundTexture));
       
   243         // sets background image behind the visual
       
   244         brush->SetLayer(EAlfBrushLayerBackground);
       
   245         iRootLayout->Brushes()->AppendL(brush, EAlfHasOwnership);
       
   246         CleanupStack::Pop(brush);
       
   247         }
       
   248     else
       
   249         {
       
   250         // Reset current dimensions
       
   251         // There is only one dimension
       
   252         for(TInt i=0; i<KDimensionsOfGrid; i++)
       
   253             {
       
   254             // resetting non existing weights causes Leave
       
   255             TRAP_IGNORE(iRootLayout->RemoveWeightL(EAlfGridColumn, i));
       
   256             TRAP_IGNORE(iRootLayout->RemoveWeightL(EAlfGridRow, i));
       
   257             }
       
   258         // now set new dimension
       
   259         iRootLayout->SetColumnsL(KRowsAndColumnsOfGrid[iLayoutMode][EColumn]);
       
   260         iRootLayout->SetRowsL(KRowsAndColumnsOfGrid[iLayoutMode][ERow]);
       
   261         }
       
   262 
       
   263     // Sets weights of grid
       
   264     SetWeightsOfGridL(*iRootLayout,
       
   265                       iLayoutMode,
       
   266                       iSquareSide,
       
   267                       iLongerSide,
       
   268                       iPlateTopOffset);
       
   269                              
       
   270     // Set the padding of the root layout
       
   271     
       
   272     // TODO: Padding disabled for now. This seems to mess the angle calculations as we the calculations do not consider
       
   273     // the effect of padding.
       
   274 
       
   275     /*
       
   276     TRect displayRect = Env().PrimaryDisplay().VisibleArea();
       
   277     TInt pad = displayRect.Height();
       
   278     if ( iLayoutMode == ELayoutAnalogDialerLandscape )
       
   279         {
       
   280         pad = displayRect.Width();
       
   281         }   
       
   282     layout->SetInnerPadding(TPoint( 
       
   283     		pad * KPaddingExtents[iLayoutMode][EColumn],
       
   284     		pad * KPaddingExtents[iLayoutMode][ERow]));
       
   285     layout->SetPadding(pad * KPaddingPercentage);*/
       
   286     }
       
   287 
       
   288 
       
   289 // ---------------------------------------------------------------------------
       
   290 // Handles pointer down events
       
   291 // ---------------------------------------------------------------------------
       
   292 //
       
   293 TBool CAlfExAnalogDialerControl::HandlePointerDownEventL(const TAlfEvent& aEvent)
       
   294 	{
       
   295 	CAlfVisual* onVisual = aEvent.Visual();
       
   296 	// Dragging may start only on top of image
       
   297 	if (onVisual == iStopper)
       
   298 	    {      
       
   299 	    // Is plate rotating starting?
       
   300         if (IsPointerEventFollowingNumbersArcPath(aEvent))
       
   301             {
       
   302             // Plate rotation is starting
       
   303     	    // Register to receive dragging events
       
   304     	    Display()->Roster().AddPointerEventObserver(EAlfPointerEventReportDrag, *this);   
       
   305     		ResetDraggingData();
       
   306 
       
   307             // Start dragging
       
   308     	    iFlags |= EAnalogDialerControlDragging;
       
   309             }
       
   310         // Is clear key pressed?
       
   311         else if (IsPointerEventOnClearKey(aEvent))
       
   312             {
       
   313     		ResetClearKeyData();
       
   314     	        
       
   315     	    // Register for long tap events
       
   316             if (!(iFlags & EAnalogDialerControlFlagLongTapRegistered))
       
   317                 {
       
   318                 // Clear key handling needs long tap events
       
   319                 Display()->Roster().AddPointerEventObserver(EAlfPointerEventReportLongTap, *this);   
       
   320                 iFlags |= EAnalogDialerControlFlagLongTapRegistered;
       
   321                 }
       
   322             // Start clear key event
       
   323     	    iFlags |= EAnalogDialerControlClearKeyEvent;
       
   324             }
       
   325 	    }
       
   326 	return ETrue;
       
   327 	}
       
   328 
       
   329 // ---------------------------------------------------------------------------
       
   330 // Handles events while dragging
       
   331 // ---------------------------------------------------------------------------
       
   332 //
       
   333 TBool CAlfExAnalogDialerControl::HandleDraggingEventL(const TAlfEvent& aEvent)
       
   334 	{
       
   335     if (iFlags & EAnalogDialerControlDragging)
       
   336         {
       
   337     	TPoint plateCentricPoint;
       
   338     	ConvertEventToPlateCentricPosition(aEvent,
       
   339     	                                   iPlateTopOffset,
       
   340     	                                   iSquareSide,
       
   341     	                                   plateCentricPoint);
       
   342     	TInt plateRadius = iSquareSide / 2;
       
   343     	if (!IsPointerEventOnArcPath(plateCentricPoint,
       
   344     	                             plateRadius,
       
   345     	                             plateRadius * KPlateClearRadius / 100))
       
   346     		{
       
   347     		FinishDragging();
       
   348     		}
       
   349         else
       
   350             {
       
   351             // Pointer event is following path
       
   352             // Get angle of pointer event and do further calculation based on it
       
   353             TInt degrees = Angle(plateCentricPoint.iX, plateCentricPoint.iY);
       
   354 
       
   355             // Save the angle of first dragging pointer event.
       
   356             // It is used to resolve selected number.
       
   357         	if (iDraggingData.iInitialAngle == 0)
       
   358         	    {
       
   359         	    iDraggingData.iInitialAngle = degrees; 
       
   360         	    iDraggingData.iPreviousAngle = degrees;
       
   361         	    }
       
   362         	        
       
   363             // As dragging events occur very often, redrawing plate is optimised that
       
   364             // it is not drawn after every dragging event. Change of KPlateDraggingDelta degrees
       
   365             // is needed until plate is redrawn.
       
   366             if (    degrees >= iDraggingData.iPreviousAngle + KPlateDraggingDelta 
       
   367                 ||  degrees <= iDraggingData.iPreviousAngle - KPlateDraggingDelta)
       
   368                 {
       
   369                 ResolveXAxisCrossing(degrees);                     
       
   370                 iDraggingData.iPreviousAngle = degrees;
       
   371                             
       
   372                 if (    iDraggingData.iIsClockWiseOverZeroReached
       
   373                     &&  degrees < KStopperAngle)
       
   374                     {
       
   375                     if (iDraggingData.iStopperReached)
       
   376                         {
       
   377                         // do not redraw as plate cannot rotate more
       
   378                         return ETrue;
       
   379                         }
       
   380                     // stopper has been reached
       
   381                     iDraggingData.iStopperReached = ETrue;
       
   382                     }
       
   383                 else if (   !iDraggingData.iIsClockWiseOverZeroReached
       
   384                         &&  degrees > iDraggingData.iInitialAngle)
       
   385                     {
       
   386                     // Rotation counter clockwise to the left of idle position is asked
       
   387                     // Plate does not rotate counterclockwise to the left of idle position
       
   388                     return ETrue;
       
   389                     }
       
   390                 else if (iDraggingData.iStopperReached)
       
   391                     {                        
       
   392                     // user has dragged 360 degrees and and is dragging now between idle and stopper position
       
   393                     return ETrue;
       
   394                     }
       
   395                  else
       
   396                     {
       
   397                     // rotating when angle is between idle and stopper position
       
   398                     iDraggingData.iStopperReached = EFalse;
       
   399                     }
       
   400                 //DebugDraggingData(degrees);
       
   401                 RotatePlate(    *iImage,
       
   402                                 iDraggingData.iInitialAngle,
       
   403                                 degrees,
       
   404                                 iDraggingData.iIsClockWiseOverZeroReached);
       
   405                 }
       
   406             // else - delta of rotation has not reached KPlateDraggingDelta
       
   407             }
       
   408         }
       
   409     return ETrue;
       
   410 	}
       
   411 
       
   412 // ---------------------------------------------------------------------------
       
   413 // Handle pointer up event
       
   414 // ---------------------------------------------------------------------------
       
   415 //
       
   416 TBool CAlfExAnalogDialerControl::HandlePointerUpEventL(const TAlfEvent& aEvent)
       
   417 	{
       
   418 	if (iFlags & EAnalogDialerControlDragging)
       
   419 		{
       
   420 		FinishDragging();
       
   421 		}
       
   422     else if (iFlags & EAnalogDialerControlClearKeyEvent)
       
   423         {
       
   424         if (IsPointerEventOnClearKey(aEvent))
       
   425             {
       
   426             ClearNumberDisplay(iFlags&EAnalogDialerControlFlagLongTapPressed);
       
   427             }
       
   428         // else - lifting pointer outside Clear key area cancels clearing number
       
   429         ResetClearKeyData();
       
   430         }
       
   431     return ETrue;
       
   432 	}
       
   433 
       
   434 // ---------------------------------------------------------------------------
       
   435 // Handle long tap event
       
   436 // ---------------------------------------------------------------------------
       
   437 //
       
   438 TBool CAlfExAnalogDialerControl::HandlePointerLongTapEventL(const TAlfEvent& /*aEvent*/)
       
   439     {
       
   440     if (iFlags & EAnalogDialerControlClearKeyEvent)
       
   441         {
       
   442         iFlags |= EAnalogDialerControlFlagLongTapPressed;
       
   443         }
       
   444     return ETrue;  
       
   445     }
       
   446 
       
   447 // ---------------------------------------------------------------------------
       
   448 // Events from framework
       
   449 // ---------------------------------------------------------------------------
       
   450 //
       
   451 TBool CAlfExAnalogDialerControl::OfferEventL(const TAlfEvent& aEvent)
       
   452     {
       
   453     if (aEvent.IsPointerEvent() && aEvent.PointerDown())
       
   454 	    {
       
   455 	    return HandlePointerDownEventL(aEvent);    
       
   456 	    }
       
   457 	 
       
   458 	else if(aEvent.IsPointerEvent() && aEvent.PointerEvent().iType == TPointerEvent::EDrag )
       
   459 	    {
       
   460 	    return HandleDraggingEventL(aEvent);
       
   461 	    }
       
   462 	
       
   463 	else if(aEvent.IsPointerEvent() && aEvent.PointerUp())
       
   464 	    {
       
   465 	    return HandlePointerUpEventL(aEvent);
       
   466 	    }
       
   467 
       
   468 	else if(aEvent.IsPointerEvent() && aEvent.PointerLongTap())
       
   469 	    {
       
   470 	    return HandlePointerLongTapEventL(aEvent);
       
   471 	    }
       
   472 	    
       
   473 	return EFalse;
       
   474 	}
       
   475 
       
   476 // ---------------------------------------------------------------------------
       
   477 // AddNumberToDisplayPaneL
       
   478 // ---------------------------------------------------------------------------
       
   479 //
       
   480 void CAlfExAnalogDialerControl::AddNumberToDisplayPaneL(TInt aNumber)
       
   481 	{	
       
   482     TBuf<8> number;        
       
   483     // Second parameter: number cannot be 10
       
   484     number.Format(KNumberDisplayTemplate, (aNumber+1)%10);
       
   485     if (iDisplayNumber.Length() + number.Length() <= KNumberDisplayBufferLength)
       
   486     	{
       
   487     	iDisplayNumber.Append(number);    
       
   488     	iDisplayPane->SetTextL(iDisplayNumber);
       
   489     	}
       
   490 	}
       
   491 	
       
   492 // ---------------------------------------------------------------------------
       
   493 // Adds content into display pane of the application
       
   494 // ---------------------------------------------------------------------------
       
   495 //
       
   496 void CAlfExAnalogDialerControl::AddDisplayPaneL()
       
   497     {
       
   498     CAlfDeckLayout* displayDeck = CAlfDeckLayout::AddNewL(*this, iRootLayout);
       
   499     // Add TextVisual for displaying text
       
   500     iDisplayPane = CAlfTextVisual::AddNewL(*this, displayDeck);
       
   501     iDisplayPane->SetTagL(_L8( KTagArrayTheRest[ETagAnalogDialerDisplay]));
       
   502     iDisplayPane->EnableBrushesL();      
       
   503     iDisplayPane->SetAlign(EAlfAlignHRight, EAlfAlignVCenter);      
       
   504     iDisplayPane->SetFlag(EAlfVisualFlagManualLayout);
       
   505     
       
   506     // Decoration
       
   507     if (iLayoutMode == ELayoutAnalogDialerPortrait)
       
   508     	{
       
   509     	iDisplayPane->SetCenteredPosAndSize(TPoint(180,100),TSize(300,50));
       
   510     	}
       
   511     else 
       
   512     	{
       
   513     	iDisplayPane->SetCenteredPosAndSize(TPoint(150,180),TSize(200,300));
       
   514     	}
       
   515     iDisplayPane->SetStyle(EAlfTextStyleTitle);
       
   516     iDisplayPane->SetColor(KFontColor);    
       
   517     
       
   518     // Display rectangular 
       
   519     CAlfShadowBorderBrush* brush = CAlfShadowBorderBrush::NewLC(Env(),6);
       
   520     brush->SetOpacity(.25f);
       
   521     // Attach brush and transfer its ownership to the visual.    
       
   522     iDisplayPane->Brushes()->AppendL(brush, EAlfHasOwnership);    
       
   523     CleanupStack::Pop(brush);    
       
   524     }
       
   525 
       
   526 // ---------------------------------------------------------------------------
       
   527 // Adds content into dialer pane of the application
       
   528 // ---------------------------------------------------------------------------
       
   529 //
       
   530 void CAlfExAnalogDialerControl::AddDialerL()
       
   531     {
       
   532     // Deck
       
   533     CAlfDeckLayout* dialerDeck = CAlfDeckLayout::AddNewL(*this, iRootLayout);
       
   534     
       
   535     dialerDeck->SetTagL(_L8(KTagArrayTheRest[ETagAnalogDialerDialer]));
       
   536     // TODO: for testing
       
   537     dialerDeck->EnableTransformationL();
       
   538     dialerDeck->EnableBrushesL();
       
   539     
       
   540 	// load textures 
       
   541 	// the dialer consists of 3 pictures which are put on top of each other.
       
   542     
       
   543     // Bottom most is the image with the numbers
       
   544     CAlfTexture& dialerBgTexture = Env().TextureManager().LoadTextureL( KImageAnalogDialerNumbers, 
       
   545                                                                         EAlfTextureFlagDefault, 
       
   546                                                                         KAlfAutoGeneratedTextureId);
       
   547     // Default scale mode CAlfImageVisual::EScaleFit is OK
       
   548 	CAlfImageVisual* image2  = CAlfImageVisual::AddNewL(*this,dialerDeck); 
       
   549 	// attach texture to image visual
       
   550 	image2->SetImage(TAlfImage(dialerBgTexture));
       
   551 	
       
   552 	// on top of the numbers is the plate picture, which will be rotated
       
   553 	CAlfTexture& circle = Env().TextureManager().LoadTextureL(  KImageAnalogDialerPlate, 
       
   554 	                                                            EAlfTextureFlagDefault, 
       
   555 	                                                            KAlfAutoGeneratedTextureId);
       
   556     // Default scale mode CAlfImageVisual::EScaleFit is OK
       
   557 	iImage  = CAlfImageVisual::AddNewL(*this,dialerDeck); 
       
   558 	iImage->SetImage(TAlfImage(circle));
       
   559 
       
   560 	// on top the rotating plate is image with the stopper and shadows
       
   561 	CAlfTexture& stopper = Env().TextureManager().LoadTextureL( KImageAnalogDialerStopper, 
       
   562 	                                                            EAlfTextureFlagDefault, 
       
   563 	                                                            KAlfAutoGeneratedTextureId);
       
   564     // Default scale mode CAlfImageVisual::EScaleFit is OK
       
   565 	iStopper  = CAlfImageVisual::AddNewL(*this,dialerDeck); 
       
   566 	iStopper->SetImage(TAlfImage(stopper));
       
   567     
       
   568     }
       
   569 
       
   570 // ---------------------------------------------------------------------------
       
   571 // SwitchLayoutL
       
   572 // ---------------------------------------------------------------------------
       
   573 //
       
   574 void CAlfExAnalogDialerControl::SwitchLayoutL()
       
   575     {
       
   576     iLayoutMode = ResolveLayout(iSquareSide,
       
   577                             iLongerSide);
       
   578     iLayoutMode == ELayoutAnalogDialerPortrait ? SetupPortraitModeL() : SetupLandscapeModeL();
       
   579     if (iLayoutMode == ELayoutAnalogDialerPortrait)
       
   580         {
       
   581         MoveVisualToFirst(_L8(KTagArrayTheRest[ETagAnalogDialerDisplay]));
       
   582         }
       
   583     else
       
   584         {
       
   585         MoveVisualToFirst(_L8(KTagArrayTheRest[ETagAnalogDialerDialer]));
       
   586         }
       
   587 
       
   588     iFeedback->Start();
       
   589 
       
   590     // expose new root layout
       
   591     TAlfTimedValue opacity(0.0f);
       
   592     opacity.SetTarget(255, 500);
       
   593     iRootLayout->SetOpacity(opacity);   
       
   594 
       
   595     }
       
   596     
       
   597 // ---------------------------------------------------------------------------
       
   598 // Moves visual with given tag to first visual in the layout
       
   599 // ---------------------------------------------------------------------------
       
   600 // 
       
   601 void CAlfExAnalogDialerControl::MoveVisualToFirst(const TDesC8& aTag)
       
   602     {
       
   603     CAlfVisual* layout = FindTag(aTag);
       
   604     if (layout)
       
   605         {
       
   606         // layout to move, index in the layout, transition time
       
   607         iRootLayout->Reorder(*layout, 0, 0);
       
   608         }
       
   609     }
       
   610 
       
   611 // ---------------------------------------------------------------------------
       
   612 // Hides the visual
       
   613 // ---------------------------------------------------------------------------
       
   614 // 
       
   615 void CAlfExAnalogDialerControl::PrepareForLayoutSwitchL()
       
   616     {
       
   617     CAlfVisual* layout = FindTag(_L8(KTagArrayTheRest[ETagAnalogDialerMain]));
       
   618     if ( layout )
       
   619         {
       
   620         TAlfTimedValue opacity(1.0f);
       
   621         opacity.SetTarget( 0.0f, 500);
       
   622         layout->SetOpacity(opacity);   
       
   623         }
       
   624     iFeedback->Start();
       
   625     User::After(500000);
       
   626     }
       
   627 
       
   628 
       
   629 // ---------------------------------------------------------------------------
       
   630 // Resolves current layout.
       
   631 // ---------------------------------------------------------------------------
       
   632 // 
       
   633 CAlfExAnalogDialerControl::TLayoutMode CAlfExAnalogDialerControl::ResolveLayout(
       
   634                                             TInt& aShorterSide,
       
   635                                             TInt& aLongerSide) const
       
   636     {
       
   637     TLayoutMode layoutMode = ELayoutAnalogDialerPortrait;
       
   638     TRect displayRect = Env().PrimaryDisplay().VisibleArea();
       
   639     TInt height = displayRect.Height();
       
   640     TInt width = displayRect.Width();
       
   641     if (width > height)
       
   642         {
       
   643         layoutMode = ELayoutAnalogDialerLandscape;
       
   644         aShorterSide = height;
       
   645         aLongerSide = width;
       
   646         }
       
   647     else
       
   648         {
       
   649         // default mode OK
       
   650         aShorterSide = width;
       
   651         aLongerSide = height;
       
   652         }
       
   653     return layoutMode;
       
   654     }
       
   655  
       
   656 // ---------------------------------------------------------------------------
       
   657 // ResolveXAxisCrossing
       
   658 // ---------------------------------------------------------------------------
       
   659 //
       
   660 void CAlfExAnalogDialerControl::ResolveXAxisCrossing(TInt aAngle)
       
   661     {   
       
   662     // Delta of angle change, which indicates X-axis crossing
       
   663     const TInt KXAxisCrossingAngleDelta = 300;
       
   664 
       
   665     TInt degreesDelta = aAngle - iDraggingData.iPreviousAngle;
       
   666     // switch from 0 to 359?
       
   667     if (degreesDelta > KXAxisCrossingAngleDelta)
       
   668         {
       
   669         iDraggingData.iIsClockWiseOverZeroReached = ETrue;
       
   670         }
       
   671     // switch from 359 to 0?
       
   672     else if (   iDraggingData.iIsClockWiseOverZeroReached
       
   673             &&  degreesDelta < (-KXAxisCrossingAngleDelta))
       
   674         {
       
   675         iDraggingData.iIsClockWiseOverZeroReached = EFalse;
       
   676         }    
       
   677     }
       
   678 
       
   679 
       
   680 // ---------------------------------------------------------------------------
       
   681 // Calculate angle of triangle, when adjacent and opposite sides are known
       
   682 // ---------------------------------------------------------------------------
       
   683 // 
       
   684 TInt CAlfExAnalogDialerControl::Angle(TReal32 aAdjacent, TReal32 aOpposite)
       
   685 	{
       
   686 	if (aAdjacent == 0)
       
   687 	    {
       
   688 	    aAdjacent = 0.01;
       
   689 	    }
       
   690 	
       
   691 	if (aOpposite == 0)
       
   692 		{
       
   693 		aOpposite = 0.01;
       
   694 		}
       
   695 
       
   696 	TReal angle;
       
   697 	Math::ATan(angle, Abs(aOpposite / aAdjacent));
       
   698 	
       
   699 	if (aAdjacent < 0 && aOpposite > 0)
       
   700 		{
       
   701 		angle =  KPi - angle;
       
   702 		}
       
   703 	else if (aAdjacent < 0 && aOpposite < 0)
       
   704 		{
       
   705 		angle = KPi + angle; 
       
   706 		}
       
   707     else if (aAdjacent > 0 && aOpposite < 0)
       
   708 		{
       
   709 		angle = 2* KPi -  angle;
       
   710 		}
       
   711     return RADTODEG(angle);			
       
   712 	}
       
   713 
       
   714 // ---------------------------------------------------------------------------
       
   715 // Calculate hypotenuse of triangle when length of adjacent and opposite sides are known
       
   716 // ---------------------------------------------------------------------------
       
   717 // 
       
   718 TInt CAlfExAnalogDialerControl::Hypotenuse(TInt aA, TInt aB)
       
   719 	{
       
   720 	aA *= aA;
       
   721 	aB *= aB;
       
   722 		
       
   723 	TReal hypotenuse;
       
   724 	Math::Sqrt(hypotenuse, aA + aB);
       
   725 	return hypotenuse;
       
   726 	}
       
   727 	
       
   728 
       
   729 // ---------------------------------------------------------------------------
       
   730 // Layout of portrait and landscape modes are hardwired into implementation. 
       
   731 // ---------------------------------------------------------------------------
       
   732 // 
       
   733 void CAlfExAnalogDialerControl::SetWeightsOfGridL(  CAlfGridLayout& aGridLayout,
       
   734                                                     TLayoutMode     aLayout,
       
   735                                                     TInt            aSquareSide,
       
   736                                                     TInt            aLongerSide,
       
   737                                                     TInt&           aPlateTop)
       
   738     {
       
   739     // Set up a variable for default value.
       
   740     RArray<TInt> weightsDefault;
       
   741     User::LeaveIfError(weightsDefault.Append(1));   
       
   742 
       
   743     // sets weights of grid. Use pixels to get exact adjustment of pane sizes
       
   744     RArray<TInt> weights;
       
   745     if (aLayout == ELayoutAnalogDialerPortrait)
       
   746         {
       
   747         // top: display
       
   748         User::LeaveIfError(weights.Append(aLongerSide-aSquareSide));
       
   749         // bottom: dialer
       
   750         User::LeaveIfError(weights.Append(aSquareSide));
       
   751         aGridLayout.SetRowsL(weights);
       
   752         aGridLayout.SetColumnsL(weightsDefault);
       
   753         
       
   754         aPlateTop = aLongerSide-aSquareSide;
       
   755         }
       
   756     else
       
   757         {
       
   758         // left: dialer
       
   759         User::LeaveIfError(weights.Append(aSquareSide));
       
   760         // right: display
       
   761         User::LeaveIfError(weights.Append(aLongerSide-aSquareSide));
       
   762         aGridLayout.SetRowsL(weightsDefault);
       
   763         aGridLayout.SetColumnsL(weights);
       
   764         
       
   765         aPlateTop = 0;
       
   766         }         
       
   767     weights.Close(); 
       
   768     weightsDefault.Close(); 
       
   769     }
       
   770     
       
   771     
       
   772 // ---------------------------------------------------------------------------
       
   773 // ConvertEventToPlateCentricPosition
       
   774 // ---------------------------------------------------------------------------
       
   775 // 
       
   776 void CAlfExAnalogDialerControl::ConvertEventToPlateCentricPosition(
       
   777                                         const TAlfEvent&    aEvent,
       
   778 	                                    TInt                aPlateTopOffset,
       
   779 	                                    TInt                aSquareSide,
       
   780 	                                    TPoint&             aPlateCentricPoint)
       
   781     {
       
   782     // event position is converted in a such way that centre position of the plate is (0,0)
       
   783     // iY: value is negative, if position is above the centre position
       
   784     // iY: value is position, if position is under the centre position
       
   785     // iX: value is negative, if position is to the left the centre position
       
   786     // iX: value is position, if position is to the right of the centre position
       
   787 	const TInt plateCentreY = aPlateTopOffset + aSquareSide / 2;
       
   788 	aPlateCentricPoint.iX = aEvent.PointerEvent().iParentPosition.iX - aSquareSide / 2;
       
   789 	aPlateCentricPoint.iY = plateCentreY - aEvent.PointerEvent().iParentPosition.iY ;
       
   790     }
       
   791     
       
   792     
       
   793 // ---------------------------------------------------------------------------
       
   794 // Checks whether pointer event occurred between outer and inner radius
       
   795 // ---------------------------------------------------------------------------
       
   796 // 
       
   797 TBool CAlfExAnalogDialerControl::IsPointerEventOnArcPath(   TPoint& aPlateCentricPoint,
       
   798 	                                                        TInt    aOuterRadius,
       
   799 	                                                        TInt    aInnerRadius)
       
   800     {  
       
   801     // Checks whether position is along a path, which is between two imaginary circles.
       
   802     // Radius of circles are given. 
       
   803     TBool ret = ETrue;   
       
   804 	TInt distanceFromPlateCentre = Hypotenuse(aPlateCentricPoint.iX, aPlateCentricPoint.iY); 	
       
   805 	if (distanceFromPlateCentre > aOuterRadius || distanceFromPlateCentre < aInnerRadius)
       
   806 	    {
       
   807 	    ret = EFalse;
       
   808 	    }
       
   809 	return ret;
       
   810     }
       
   811     
       
   812 // ---------------------------------------------------------------------------
       
   813 // Dragging has been stopped. Resets dragging data
       
   814 // ---------------------------------------------------------------------------
       
   815 // 
       
   816 void CAlfExAnalogDialerControl::ResetDraggingData()
       
   817     {
       
   818 	iFlags &= (~EAnalogDialerControlDragging);
       
   819 	iDraggingData.iInitialAngle = 0;
       
   820 	iDraggingData.iPreviousAngle = 0;
       
   821 	iDraggingData.iIsClockWiseOverZeroReached = EFalse;
       
   822 	iDraggingData.iStopperReached=EFalse;
       
   823     }
       
   824 
       
   825 // ---------------------------------------------------------------------------
       
   826 // Dragging has been stopped. Resets dragging data
       
   827 // ---------------------------------------------------------------------------
       
   828 // 
       
   829 void CAlfExAnalogDialerControl::ResetClearKeyData()
       
   830     {
       
   831 	iFlags &= (~EAnalogDialerControlClearKeyEvent);
       
   832     iFlags &= (~EAnalogDialerControlFlagLongTapPressed);
       
   833     }
       
   834 
       
   835 
       
   836 // ---------------------------------------------------------------------------
       
   837 // Turns plate image back to idle position
       
   838 // ---------------------------------------------------------------------------
       
   839 // 
       
   840 void CAlfExAnalogDialerControl::RotatePlateToIdlePosition(CAlfImageVisual&    aImage)
       
   841     {
       
   842 	// Rotate the image. This has immediate effect.
       
   843 	TAlfTimedValue tValue;
       
   844 	tValue.SetTargetWithSpeed(0,  // position zero 
       
   845 	                          KPlateReturnSpeed);
       
   846 	aImage.SetTurnAngle(tValue);
       
   847     }
       
   848     
       
   849     
       
   850 // ---------------------------------------------------------------------------
       
   851 // Rotates image
       
   852 // ---------------------------------------------------------------------------
       
   853 // 
       
   854 void CAlfExAnalogDialerControl::RotatePlate(
       
   855                                     CAlfImageVisual&    aImage,
       
   856                                     TInt                aInitialAngle,
       
   857                                     TInt                aTargetAngle,
       
   858                                     TBool               aIsClockWiseOverZeroReached)
       
   859     {
       
   860     // When rotates clockwise, rotation angle is negative
       
   861     TInt rotateDelta = aTargetAngle-aInitialAngle;
       
   862     if (aIsClockWiseOverZeroReached)
       
   863         {
       
   864         // Angle is big value (near to 360), which cannot be used as such
       
   865         // Convert it to negative value
       
   866         rotateDelta = (aTargetAngle-360)-aInitialAngle;
       
   867         }
       
   868     //RDebug::Printf("***AnalogDialer rotateDelta : %d",rotateDelta);
       
   869     TAlfTimedValue tValue(rotateDelta);
       
   870     aImage.SetTurnAngle(tValue);
       
   871     }
       
   872     
       
   873 // ---------------------------------------------------------------------------
       
   874 // Debugs dragging data + given angle 
       
   875 // ---------------------------------------------------------------------------
       
   876 // 
       
   877 void CAlfExAnalogDialerControl::DebugDraggingData(TInt aAngle)
       
   878     {
       
   879     RDebug::Printf("\n***AnalogDialer:");
       
   880     RDebug::Printf("***AnalogDialer iFlags & EAnalogDialerControlDragging: %d",iFlags & EAnalogDialerControlDragging);
       
   881     RDebug::Printf("***AnalogDialer iDraggingData.iInitialAngle: %d",iDraggingData.iInitialAngle);
       
   882     RDebug::Printf("***AnalogDialer iDraggingData.iPreviousAngle: %d",iDraggingData.iPreviousAngle);
       
   883     RDebug::Printf("***AnalogDialer iDraggingData.iIsClockWiseOverZeroReached: %d",iDraggingData.iIsClockWiseOverZeroReached);
       
   884     RDebug::Printf("***AnalogDialer iDraggingData.iStopperReached: %d",iDraggingData.iStopperReached);
       
   885     RDebug::Printf("***AnalogDialer aAngle: %d",aAngle);
       
   886     RDebug::Printf("\n");
       
   887     }
       
   888 
       
   889 
       
   890 // ---------------------------------------------------------------------------
       
   891 // Returns selected number based on rotated angle of plate 
       
   892 // ---------------------------------------------------------------------------
       
   893 // 
       
   894 TInt CAlfExAnalogDialerControl::DialedNumber(   TInt aInitialAngle,
       
   895                                                 TInt aCurrentAngle) const
       
   896     {
       
   897     // Default value when dragging event has not crossed zero-angle X-axis
       
   898     TInt deltaAngle = aCurrentAngle-aInitialAngle;
       
   899     
       
   900     // aCurrentAngle must be an angle derived directly from ConvertEventToPlateCentricPosition
       
   901     if (iDraggingData.iIsClockWiseOverZeroReached)
       
   902         {
       
   903         deltaAngle = aInitialAngle+(360-KStopperAngle);
       
   904         }
       
   905     
       
   906     // subtract required minimun angle
       
   907     deltaAngle = Abs(deltaAngle)-KPlateMinimumRotateAngle;
       
   908     if (deltaAngle<0)
       
   909         {
       
   910         return KErrNotFound;
       
   911         }
       
   912     // TODO. These values could be made constant to use plate with other number systems as decimal
       
   913     // e.g. binary, or hexadecimal
       
   914     // Finally calculate dialed number based on rotated angle
       
   915     TInt angleOfANumber(KPlateNumbersDistributionAngle/10);
       
   916     TInt dialedNumber = deltaAngle/angleOfANumber;
       
   917     if (dialedNumber > 9)
       
   918         {
       
   919         dialedNumber = 9;
       
   920         }
       
   921     return dialedNumber;
       
   922     }
       
   923 
       
   924 
       
   925 // ---------------------------------------------------------------------------
       
   926 // Checks whether pointer is on path allowed for plate rotation
       
   927 // ---------------------------------------------------------------------------
       
   928 // 
       
   929 TBool CAlfExAnalogDialerControl::IsPointerEventFollowingNumbersArcPath( const TAlfEvent& aEvent ) const
       
   930     {
       
   931 	TPoint plateCentricPoint;
       
   932 	ConvertEventToPlateCentricPosition(aEvent,
       
   933 	                                    iPlateTopOffset,
       
   934 	                                    iSquareSide,
       
   935 	                                    plateCentricPoint);
       
   936     TInt degrees = Angle( plateCentricPoint.iX, plateCentricPoint.iY);
       
   937 	// Third parameter: Radius of clear area belongs to clear area
       
   938 	TInt plateRadius = iSquareSide / 2;
       
   939 	if ( IsPointerEventOnArcPath( plateCentricPoint,
       
   940 	                              plateRadius,
       
   941 	                              (plateRadius*KPlateClearRadius/100)+1))
       
   942 	    {
       
   943 	    return ETrue;
       
   944 	    }
       
   945     return EFalse;
       
   946     }
       
   947     
       
   948 // ---------------------------------------------------------------------------
       
   949 // Checks whether pointer is on area of clear key
       
   950 // ---------------------------------------------------------------------------
       
   951 // 
       
   952 TBool CAlfExAnalogDialerControl::IsPointerEventOnClearKey( const TAlfEvent& aEvent ) const
       
   953     {
       
   954 	TPoint plateCentricPoint;
       
   955 	ConvertEventToPlateCentricPosition(aEvent,
       
   956 	                                    iPlateTopOffset,
       
   957 	                                    iSquareSide,
       
   958 	                                    plateCentricPoint);
       
   959 	TInt plateRadius = iSquareSide / 2;
       
   960 	if ( IsPointerEventOnArcPath( plateCentricPoint,
       
   961 	                              plateRadius*KPlateClearRadius/100,
       
   962 	                              0))
       
   963 	    {
       
   964 	    return ETrue;
       
   965 	    }
       
   966     return EFalse;
       
   967     }
       
   968     
       
   969 
       
   970 // ---------------------------------------------------------------------------
       
   971 // Performs actions needed when dragging is finished
       
   972 // ---------------------------------------------------------------------------
       
   973 // 
       
   974 void CAlfExAnalogDialerControl::FinishDragging()
       
   975     {
       
   976 	// Dragging has finished
       
   977 	// Remove pointer dragging observer, which will gain us performance
       
   978     Display()->Roster().RemovePointerEventObserver( EAlfPointerEventReportDrag,*this );
       
   979     DialedNumberToDisplay(iDraggingData.iInitialAngle,
       
   980                             iDraggingData.iPreviousAngle);
       
   981     RotatePlateToIdlePosition(*iImage); 
       
   982     ResetDraggingData();
       
   983     }
       
   984     
       
   985 // ---------------------------------------------------------------------------
       
   986 // Puts dialed number into number display
       
   987 // ---------------------------------------------------------------------------
       
   988 // 
       
   989 void CAlfExAnalogDialerControl::DialedNumberToDisplay(  TInt aInitialAngle,
       
   990                                                         TInt aCurrentAngle )
       
   991     {
       
   992     TInt dialedNumber = DialedNumber(   aInitialAngle,
       
   993                                         aCurrentAngle );
       
   994     // Filter KErrNotFound out
       
   995     if (dialedNumber>=0)
       
   996         {
       
   997         TRAP_IGNORE( AddNumberToDisplayPaneL( dialedNumber ) );
       
   998         }
       
   999     }
       
  1000 
       
  1001 // ---------------------------------------------------------------------------
       
  1002 // Clear number display either wholly or last number
       
  1003 // ---------------------------------------------------------------------------
       
  1004 // 
       
  1005 void CAlfExAnalogDialerControl::ClearNumberDisplay(TBool aClearWholeDisplay)
       
  1006     {
       
  1007     TInt lengthNumber = iDisplayNumber.Length();
       
  1008     if (lengthNumber == 0)
       
  1009         {
       
  1010         return;
       
  1011         }
       
  1012 
       
  1013     if (aClearWholeDisplay)
       
  1014         {
       
  1015         TBuf<1> clearBuf;        
       
  1016         iDisplayNumber.Copy(clearBuf);
       
  1017         }
       
  1018     else
       
  1019         {
       
  1020         // delete one number
       
  1021         iDisplayNumber.Delete(lengthNumber-1,1);
       
  1022         }
       
  1023     TRAP_IGNORE( iDisplayPane->SetTextL(iDisplayNumber) );
       
  1024     }
       
  1025 
       
  1026 void CAlfExAnalogDialerControl::AddEffectLayout()
       
  1027 	{
       
  1028 	
       
  1029 	}
       
  1030 // End of File