exampleapps/alfexanalogdialer/src/alfexanalogdialercontrol2.cpp
changeset 0 15bf7259bb7c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/exampleapps/alfexanalogdialer/src/alfexanalogdialercontrol2.cpp	Tue Feb 02 07:56:43 2010 +0200
@@ -0,0 +1,1030 @@
+/*
+* Copyright (c) 2008-2008 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:   Implementation of member functions of 
+*                AlfExAnalogDialerControl.
+*
+*/
+
+
+
+#include <coemain.h>
+
+// Visuals
+#include <alf/alfgridlayout.h>
+#include <alf/alftextvisual.h>
+#include <alf/alfimagevisual.h>
+#include <alf/alflinevisual.h>
+
+// Layouts
+#include <alf/alfdecklayout.h>
+#include <alf/alfcurvepath.h>
+#include <alf/alfcurvepathlayout.h>
+
+// Brushes
+#include <alf/alfborderbrush.h>
+#include <alf/alfbrusharray.h>
+#include <alf/alfimagebrush.h>
+#include <alf/alfimage.h>
+#include <alf/alfshadowborderbrush.h>
+#include <alf/alfgradientbrush.h>
+
+// Unsorted
+#include <aknutils.h>
+#include <alf/alftransformation.h>
+#include <alf/alfevent.h>
+#include <alf/alfdisplay.h>
+#include <alf/alfenv.h>
+#include <alf/alfmappingfunctions.h>
+#include <alf/alfroster.h>
+
+#include <e32math.h>
+
+#include "alfexanalogdialercontrol.h"
+#include "alfexanalogdialerfeedback.h"
+
+// Image names
+_LIT(KImageAnalogDialerBackground, "background.png");
+_LIT(KImageAnalogDialerNumbers, "numbers.png");
+_LIT(KImageAnalogDialerPlate, "plate.png");
+_LIT(KImageAnalogDialerStopper, "stopper.png");
+
+#define RADTODEG(Rad) ((180.0 * Rad) / KPi)
+
+// dimension of grid
+const TInt KDimensionsOfGrid = 2;
+
+// Tags for visuals which have always same appearance. 
+// TTagAnalogDialerVisual is used for indexing
+const char* KTagArrayTheRest[] =
+    {
+    "main",
+    "display",
+    "phone",
+    "plate-deck",
+    "plate-image",
+    "stopper"
+    };     
+
+// Dimensions of grid. iLayoutMode is used for indexing
+const TInt KRowsAndColumnsOfGrid[][KDimensionsOfGrid] =
+    {
+    { 1, 2 },   // columns, rows
+    { 2, 1 }  
+    };
+     
+// Templates for displaying number
+_LIT(KNumberDisplayTemplate, "%d");
+
+// Radius of Clear area of plate. Per cents from radius of plate.
+const TInt KPlateClearRadius = 25;
+
+// Unit speed of returning plate to idle position
+const TInt KPlateReturnSpeed = 65;
+
+// As dragging events occur very often, redrawing plate is optimised that
+// it is not drawn after every dragging event. Change of KPlateDraggingDelta 
+// degrees is needed.
+const TInt KPlateDraggingDelta = 2;
+
+// position of stopper in degrees. Angle is 43
+const TInt KStopperAngle = 360-43;
+
+// Angle of first number
+// Numbers are on angle between KPlateNumbersStartAngle and (KPlateNumbersStartAngle + KPlateNumbersDistributionAngle)
+const TInt KPlateNumbersStartAngle = 3;
+
+// angle of arch on which numbers (or holes of plate) are distributed
+// Numbers are on angle between KPlateNumbersStartAngle and (KPlateNumbersStartAngle + KPlateNumbersDistributionAngle)
+const TInt KPlateNumbersDistributionAngle = 290;
+
+// minimum rotation of plate that number becomes selected
+const TInt KPlateMinimumRotateAngle=43;
+
+// font color 
+const TRgb KFontColor = TRgb(192,192,192);
+// Size of padding of the root grid layout
+//const TReal32 KPaddingPercentage = .05;
+
+ 
+// ---------------------------------------------------------------------------
+// NewL
+// ---------------------------------------------------------------------------
+//
+CAlfExAnalogDialerControl* CAlfExAnalogDialerControl::NewL(CAlfEnv& aEnv)
+    {
+    CAlfExAnalogDialerControl* self = CAlfExAnalogDialerControl::NewLC(aEnv);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// NewLC
+// ---------------------------------------------------------------------------
+//
+CAlfExAnalogDialerControl* CAlfExAnalogDialerControl::NewLC(CAlfEnv& aEnv)
+    {
+    CAlfExAnalogDialerControl* self = new (ELeave) CAlfExAnalogDialerControl();
+    CleanupStack::PushL(self);
+    self->ConstructL(aEnv);
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// ~CAlfExAnalogDialerControl
+// ---------------------------------------------------------------------------
+//
+CAlfExAnalogDialerControl::~CAlfExAnalogDialerControl()
+    {
+    if (iFlags & EAnalogDialerControlFlagLongTapRegistered)
+        {
+        Display()->Roster().RemovePointerEventObserver(EAlfPointerEventReportLongTap, *this);
+        }
+    Env().CancelCommands(this);
+    delete iFeedback;
+    }
+
+// ---------------------------------------------------------------------------
+// CAlfExAnalogDialerControl
+// ---------------------------------------------------------------------------
+//
+CAlfExAnalogDialerControl::CAlfExAnalogDialerControl()
+        : CAlfControl()
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// ConstructL
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::ConstructL(CAlfEnv& aEnv)
+    {
+    CAlfControl::ConstructL(aEnv);
+    // Id cannot be be set in constructor
+	SetId(KAlfExAnalogDialerControlId);
+
+    // resolve layout: portrait or landscape
+    iLayoutMode = ResolveLayout(iSquareSide,
+                            iLongerSide);
+    (iLayoutMode == ELayoutAnalogDialerPortrait) ? SetupPortraitModeL() : SetupLandscapeModeL();
+
+    // set up vibra system
+    iFeedback = CAlfExAnalogDialerFeedback::NewL();
+    }   
+    
+    
+    
+// ---------------------------------------------------------------------------
+// Creates layouts and visual for portrait layout
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::SetupPortraitModeL()
+    {
+    // resolve layout: portrait or landscape
+    AddGridLayoutL();
+
+    // from top to bottom 1) display pane 2) dialer
+    AddDisplayPaneL();
+    AddDialerL();
+    
+    //AddEffectLayout();
+    }
+
+// ---------------------------------------------------------------------------
+// Creates layouts and visual for portrait layout
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::SetupLandscapeModeL()
+    {
+    // resolve layout: portrait or landscape
+    AddGridLayoutL();
+
+    // from left to right 1) dialer 2) display pane
+    AddDialerL();
+    AddDisplayPaneL();
+    
+    //AddEffectLayout();
+    }
+
+
+// ---------------------------------------------------------------------------
+// Creates grid layout and returns it
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::AddGridLayoutL()
+    {
+      // Create a grid layout to act as the root layout visual. Not owned
+    if (!iRootLayout)
+        {
+        iRootLayout = CAlfGridLayout::AddNewL(*this, 
+                                            KRowsAndColumnsOfGrid[iLayoutMode][EColumn], 
+                                            KRowsAndColumnsOfGrid[iLayoutMode][ERow]);
+        iRootLayout->SetTagL(_L8(KTagArrayTheRest[ETagAnalogDialerMain]));   
+        // Brushed must enabled before they can be used
+        iRootLayout->EnableBrushesL();      
+
+        // Background image is implemented using image brush
+        CAlfTexture& backgroundTexture = Env().TextureManager().LoadTextureL( 
+                                            KImageAnalogDialerBackground,
+                                            EAlfTextureFlagDefault, 
+                                            KAlfAutoGeneratedTextureId);        
+        // Default scale mode CAlfImageVisual::EScaleFit is OK
+        CAlfImageBrush* brush = CAlfImageBrush::NewLC(Env(), TAlfImage(backgroundTexture));
+        // sets background image behind the visual
+        brush->SetLayer(EAlfBrushLayerBackground);
+        iRootLayout->Brushes()->AppendL(brush, EAlfHasOwnership);
+        CleanupStack::Pop(brush);
+        }
+    else
+        {
+        // Reset current dimensions
+        // There is only one dimension
+        for(TInt i=0; i<KDimensionsOfGrid; i++)
+            {
+            // resetting non existing weights causes Leave
+            TRAP_IGNORE(iRootLayout->RemoveWeightL(EAlfGridColumn, i));
+            TRAP_IGNORE(iRootLayout->RemoveWeightL(EAlfGridRow, i));
+            }
+        // now set new dimension
+        iRootLayout->SetColumnsL(KRowsAndColumnsOfGrid[iLayoutMode][EColumn]);
+        iRootLayout->SetRowsL(KRowsAndColumnsOfGrid[iLayoutMode][ERow]);
+        }
+
+    // Sets weights of grid
+    SetWeightsOfGridL(*iRootLayout,
+                      iLayoutMode,
+                      iSquareSide,
+                      iLongerSide,
+                      iPlateTopOffset);
+                             
+    // Set the padding of the root layout
+    
+    // TODO: Padding disabled for now. This seems to mess the angle calculations as we the calculations do not consider
+    // the effect of padding.
+
+    /*
+    TRect displayRect = Env().PrimaryDisplay().VisibleArea();
+    TInt pad = displayRect.Height();
+    if ( iLayoutMode == ELayoutAnalogDialerLandscape )
+        {
+        pad = displayRect.Width();
+        }   
+    layout->SetInnerPadding(TPoint( 
+    		pad * KPaddingExtents[iLayoutMode][EColumn],
+    		pad * KPaddingExtents[iLayoutMode][ERow]));
+    layout->SetPadding(pad * KPaddingPercentage);*/
+    }
+
+
+// ---------------------------------------------------------------------------
+// Handles pointer down events
+// ---------------------------------------------------------------------------
+//
+TBool CAlfExAnalogDialerControl::HandlePointerDownEventL(const TAlfEvent& aEvent)
+	{
+	CAlfVisual* onVisual = aEvent.Visual();
+	// Dragging may start only on top of image
+	if (onVisual == iStopper)
+	    {      
+	    // Is plate rotating starting?
+        if (IsPointerEventFollowingNumbersArcPath(aEvent))
+            {
+            // Plate rotation is starting
+    	    // Register to receive dragging events
+    	    Display()->Roster().AddPointerEventObserver(EAlfPointerEventReportDrag, *this);   
+    		ResetDraggingData();
+
+            // Start dragging
+    	    iFlags |= EAnalogDialerControlDragging;
+            }
+        // Is clear key pressed?
+        else if (IsPointerEventOnClearKey(aEvent))
+            {
+    		ResetClearKeyData();
+    	        
+    	    // Register for long tap events
+            if (!(iFlags & EAnalogDialerControlFlagLongTapRegistered))
+                {
+                // Clear key handling needs long tap events
+                Display()->Roster().AddPointerEventObserver(EAlfPointerEventReportLongTap, *this);   
+                iFlags |= EAnalogDialerControlFlagLongTapRegistered;
+                }
+            // Start clear key event
+    	    iFlags |= EAnalogDialerControlClearKeyEvent;
+            }
+	    }
+	return ETrue;
+	}
+
+// ---------------------------------------------------------------------------
+// Handles events while dragging
+// ---------------------------------------------------------------------------
+//
+TBool CAlfExAnalogDialerControl::HandleDraggingEventL(const TAlfEvent& aEvent)
+	{
+    if (iFlags & EAnalogDialerControlDragging)
+        {
+    	TPoint plateCentricPoint;
+    	ConvertEventToPlateCentricPosition(aEvent,
+    	                                   iPlateTopOffset,
+    	                                   iSquareSide,
+    	                                   plateCentricPoint);
+    	TInt plateRadius = iSquareSide / 2;
+    	if (!IsPointerEventOnArcPath(plateCentricPoint,
+    	                             plateRadius,
+    	                             plateRadius * KPlateClearRadius / 100))
+    		{
+    		FinishDragging();
+    		}
+        else
+            {
+            // Pointer event is following path
+            // Get angle of pointer event and do further calculation based on it
+            TInt degrees = Angle(plateCentricPoint.iX, plateCentricPoint.iY);
+
+            // Save the angle of first dragging pointer event.
+            // It is used to resolve selected number.
+        	if (iDraggingData.iInitialAngle == 0)
+        	    {
+        	    iDraggingData.iInitialAngle = degrees; 
+        	    iDraggingData.iPreviousAngle = degrees;
+        	    }
+        	        
+            // As dragging events occur very often, redrawing plate is optimised that
+            // it is not drawn after every dragging event. Change of KPlateDraggingDelta degrees
+            // is needed until plate is redrawn.
+            if (    degrees >= iDraggingData.iPreviousAngle + KPlateDraggingDelta 
+                ||  degrees <= iDraggingData.iPreviousAngle - KPlateDraggingDelta)
+                {
+                ResolveXAxisCrossing(degrees);                     
+                iDraggingData.iPreviousAngle = degrees;
+                            
+                if (    iDraggingData.iIsClockWiseOverZeroReached
+                    &&  degrees < KStopperAngle)
+                    {
+                    if (iDraggingData.iStopperReached)
+                        {
+                        // do not redraw as plate cannot rotate more
+                        return ETrue;
+                        }
+                    // stopper has been reached
+                    iDraggingData.iStopperReached = ETrue;
+                    }
+                else if (   !iDraggingData.iIsClockWiseOverZeroReached
+                        &&  degrees > iDraggingData.iInitialAngle)
+                    {
+                    // Rotation counter clockwise to the left of idle position is asked
+                    // Plate does not rotate counterclockwise to the left of idle position
+                    return ETrue;
+                    }
+                else if (iDraggingData.iStopperReached)
+                    {                        
+                    // user has dragged 360 degrees and and is dragging now between idle and stopper position
+                    return ETrue;
+                    }
+                 else
+                    {
+                    // rotating when angle is between idle and stopper position
+                    iDraggingData.iStopperReached = EFalse;
+                    }
+                //DebugDraggingData(degrees);
+                RotatePlate(    *iImage,
+                                iDraggingData.iInitialAngle,
+                                degrees,
+                                iDraggingData.iIsClockWiseOverZeroReached);
+                }
+            // else - delta of rotation has not reached KPlateDraggingDelta
+            }
+        }
+    return ETrue;
+	}
+
+// ---------------------------------------------------------------------------
+// Handle pointer up event
+// ---------------------------------------------------------------------------
+//
+TBool CAlfExAnalogDialerControl::HandlePointerUpEventL(const TAlfEvent& aEvent)
+	{
+	if (iFlags & EAnalogDialerControlDragging)
+		{
+		FinishDragging();
+		}
+    else if (iFlags & EAnalogDialerControlClearKeyEvent)
+        {
+        if (IsPointerEventOnClearKey(aEvent))
+            {
+            ClearNumberDisplay(iFlags&EAnalogDialerControlFlagLongTapPressed);
+            }
+        // else - lifting pointer outside Clear key area cancels clearing number
+        ResetClearKeyData();
+        }
+    return ETrue;
+	}
+
+// ---------------------------------------------------------------------------
+// Handle long tap event
+// ---------------------------------------------------------------------------
+//
+TBool CAlfExAnalogDialerControl::HandlePointerLongTapEventL(const TAlfEvent& /*aEvent*/)
+    {
+    if (iFlags & EAnalogDialerControlClearKeyEvent)
+        {
+        iFlags |= EAnalogDialerControlFlagLongTapPressed;
+        }
+    return ETrue;  
+    }
+
+// ---------------------------------------------------------------------------
+// Events from framework
+// ---------------------------------------------------------------------------
+//
+TBool CAlfExAnalogDialerControl::OfferEventL(const TAlfEvent& aEvent)
+    {
+    if (aEvent.IsPointerEvent() && aEvent.PointerDown())
+	    {
+	    return HandlePointerDownEventL(aEvent);    
+	    }
+	 
+	else if(aEvent.IsPointerEvent() && aEvent.PointerEvent().iType == TPointerEvent::EDrag )
+	    {
+	    return HandleDraggingEventL(aEvent);
+	    }
+	
+	else if(aEvent.IsPointerEvent() && aEvent.PointerUp())
+	    {
+	    return HandlePointerUpEventL(aEvent);
+	    }
+
+	else if(aEvent.IsPointerEvent() && aEvent.PointerLongTap())
+	    {
+	    return HandlePointerLongTapEventL(aEvent);
+	    }
+	    
+	return EFalse;
+	}
+
+// ---------------------------------------------------------------------------
+// AddNumberToDisplayPaneL
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::AddNumberToDisplayPaneL(TInt aNumber)
+	{	
+    TBuf<8> number;        
+    // Second parameter: number cannot be 10
+    number.Format(KNumberDisplayTemplate, (aNumber+1)%10);
+    if (iDisplayNumber.Length() + number.Length() <= KNumberDisplayBufferLength)
+    	{
+    	iDisplayNumber.Append(number);    
+    	iDisplayPane->SetTextL(iDisplayNumber);
+    	}
+	}
+	
+// ---------------------------------------------------------------------------
+// Adds content into display pane of the application
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::AddDisplayPaneL()
+    {
+    CAlfDeckLayout* displayDeck = CAlfDeckLayout::AddNewL(*this, iRootLayout);
+    // Add TextVisual for displaying text
+    iDisplayPane = CAlfTextVisual::AddNewL(*this, displayDeck);
+    iDisplayPane->SetTagL(_L8( KTagArrayTheRest[ETagAnalogDialerDisplay]));
+    iDisplayPane->EnableBrushesL();      
+    iDisplayPane->SetAlign(EAlfAlignHRight, EAlfAlignVCenter);      
+    iDisplayPane->SetFlag(EAlfVisualFlagManualLayout);
+    
+    // Decoration
+    if (iLayoutMode == ELayoutAnalogDialerPortrait)
+    	{
+    	iDisplayPane->SetCenteredPosAndSize(TPoint(180,100),TSize(300,50));
+    	}
+    else 
+    	{
+    	iDisplayPane->SetCenteredPosAndSize(TPoint(150,180),TSize(200,300));
+    	}
+    iDisplayPane->SetStyle(EAlfTextStyleTitle);
+    iDisplayPane->SetColor(KFontColor);    
+    
+    // Display rectangular 
+    CAlfShadowBorderBrush* brush = CAlfShadowBorderBrush::NewLC(Env(),6);
+    brush->SetOpacity(.25f);
+    // Attach brush and transfer its ownership to the visual.    
+    iDisplayPane->Brushes()->AppendL(brush, EAlfHasOwnership);    
+    CleanupStack::Pop(brush);    
+    }
+
+// ---------------------------------------------------------------------------
+// Adds content into dialer pane of the application
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::AddDialerL()
+    {
+    // Deck
+    CAlfDeckLayout* dialerDeck = CAlfDeckLayout::AddNewL(*this, iRootLayout);
+    
+    dialerDeck->SetTagL(_L8(KTagArrayTheRest[ETagAnalogDialerDialer]));
+    // TODO: for testing
+    dialerDeck->EnableTransformationL();
+    dialerDeck->EnableBrushesL();
+    
+	// load textures 
+	// the dialer consists of 3 pictures which are put on top of each other.
+    
+    // Bottom most is the image with the numbers
+    CAlfTexture& dialerBgTexture = Env().TextureManager().LoadTextureL( KImageAnalogDialerNumbers, 
+                                                                        EAlfTextureFlagDefault, 
+                                                                        KAlfAutoGeneratedTextureId);
+    // Default scale mode CAlfImageVisual::EScaleFit is OK
+	CAlfImageVisual* image2  = CAlfImageVisual::AddNewL(*this,dialerDeck); 
+	// attach texture to image visual
+	image2->SetImage(TAlfImage(dialerBgTexture));
+	
+	// on top of the numbers is the plate picture, which will be rotated
+	CAlfTexture& circle = Env().TextureManager().LoadTextureL(  KImageAnalogDialerPlate, 
+	                                                            EAlfTextureFlagDefault, 
+	                                                            KAlfAutoGeneratedTextureId);
+    // Default scale mode CAlfImageVisual::EScaleFit is OK
+	iImage  = CAlfImageVisual::AddNewL(*this,dialerDeck); 
+	iImage->SetImage(TAlfImage(circle));
+
+	// on top the rotating plate is image with the stopper and shadows
+	CAlfTexture& stopper = Env().TextureManager().LoadTextureL( KImageAnalogDialerStopper, 
+	                                                            EAlfTextureFlagDefault, 
+	                                                            KAlfAutoGeneratedTextureId);
+    // Default scale mode CAlfImageVisual::EScaleFit is OK
+	iStopper  = CAlfImageVisual::AddNewL(*this,dialerDeck); 
+	iStopper->SetImage(TAlfImage(stopper));
+    
+    }
+
+// ---------------------------------------------------------------------------
+// SwitchLayoutL
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::SwitchLayoutL()
+    {
+    iLayoutMode = ResolveLayout(iSquareSide,
+                            iLongerSide);
+    iLayoutMode == ELayoutAnalogDialerPortrait ? SetupPortraitModeL() : SetupLandscapeModeL();
+    if (iLayoutMode == ELayoutAnalogDialerPortrait)
+        {
+        MoveVisualToFirst(_L8(KTagArrayTheRest[ETagAnalogDialerDisplay]));
+        }
+    else
+        {
+        MoveVisualToFirst(_L8(KTagArrayTheRest[ETagAnalogDialerDialer]));
+        }
+
+    iFeedback->Start();
+
+    // expose new root layout
+    TAlfTimedValue opacity(0.0f);
+    opacity.SetTarget(255, 500);
+    iRootLayout->SetOpacity(opacity);   
+
+    }
+    
+// ---------------------------------------------------------------------------
+// Moves visual with given tag to first visual in the layout
+// ---------------------------------------------------------------------------
+// 
+void CAlfExAnalogDialerControl::MoveVisualToFirst(const TDesC8& aTag)
+    {
+    CAlfVisual* layout = FindTag(aTag);
+    if (layout)
+        {
+        // layout to move, index in the layout, transition time
+        iRootLayout->Reorder(*layout, 0, 0);
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Hides the visual
+// ---------------------------------------------------------------------------
+// 
+void CAlfExAnalogDialerControl::PrepareForLayoutSwitchL()
+    {
+    CAlfVisual* layout = FindTag(_L8(KTagArrayTheRest[ETagAnalogDialerMain]));
+    if ( layout )
+        {
+        TAlfTimedValue opacity(1.0f);
+        opacity.SetTarget( 0.0f, 500);
+        layout->SetOpacity(opacity);   
+        }
+    iFeedback->Start();
+    User::After(500000);
+    }
+
+
+// ---------------------------------------------------------------------------
+// Resolves current layout.
+// ---------------------------------------------------------------------------
+// 
+CAlfExAnalogDialerControl::TLayoutMode CAlfExAnalogDialerControl::ResolveLayout(
+                                            TInt& aShorterSide,
+                                            TInt& aLongerSide) const
+    {
+    TLayoutMode layoutMode = ELayoutAnalogDialerPortrait;
+    TRect displayRect = Env().PrimaryDisplay().VisibleArea();
+    TInt height = displayRect.Height();
+    TInt width = displayRect.Width();
+    if (width > height)
+        {
+        layoutMode = ELayoutAnalogDialerLandscape;
+        aShorterSide = height;
+        aLongerSide = width;
+        }
+    else
+        {
+        // default mode OK
+        aShorterSide = width;
+        aLongerSide = height;
+        }
+    return layoutMode;
+    }
+ 
+// ---------------------------------------------------------------------------
+// ResolveXAxisCrossing
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::ResolveXAxisCrossing(TInt aAngle)
+    {   
+    // Delta of angle change, which indicates X-axis crossing
+    const TInt KXAxisCrossingAngleDelta = 300;
+
+    TInt degreesDelta = aAngle - iDraggingData.iPreviousAngle;
+    // switch from 0 to 359?
+    if (degreesDelta > KXAxisCrossingAngleDelta)
+        {
+        iDraggingData.iIsClockWiseOverZeroReached = ETrue;
+        }
+    // switch from 359 to 0?
+    else if (   iDraggingData.iIsClockWiseOverZeroReached
+            &&  degreesDelta < (-KXAxisCrossingAngleDelta))
+        {
+        iDraggingData.iIsClockWiseOverZeroReached = EFalse;
+        }    
+    }
+
+
+// ---------------------------------------------------------------------------
+// Calculate angle of triangle, when adjacent and opposite sides are known
+// ---------------------------------------------------------------------------
+// 
+TInt CAlfExAnalogDialerControl::Angle(TReal32 aAdjacent, TReal32 aOpposite)
+	{
+	if (aAdjacent == 0)
+	    {
+	    aAdjacent = 0.01;
+	    }
+	
+	if (aOpposite == 0)
+		{
+		aOpposite = 0.01;
+		}
+
+	TReal angle;
+	Math::ATan(angle, Abs(aOpposite / aAdjacent));
+	
+	if (aAdjacent < 0 && aOpposite > 0)
+		{
+		angle =  KPi - angle;
+		}
+	else if (aAdjacent < 0 && aOpposite < 0)
+		{
+		angle = KPi + angle; 
+		}
+    else if (aAdjacent > 0 && aOpposite < 0)
+		{
+		angle = 2* KPi -  angle;
+		}
+    return RADTODEG(angle);			
+	}
+
+// ---------------------------------------------------------------------------
+// Calculate hypotenuse of triangle when length of adjacent and opposite sides are known
+// ---------------------------------------------------------------------------
+// 
+TInt CAlfExAnalogDialerControl::Hypotenuse(TInt aA, TInt aB)
+	{
+	aA *= aA;
+	aB *= aB;
+		
+	TReal hypotenuse;
+	Math::Sqrt(hypotenuse, aA + aB);
+	return hypotenuse;
+	}
+	
+
+// ---------------------------------------------------------------------------
+// Layout of portrait and landscape modes are hardwired into implementation. 
+// ---------------------------------------------------------------------------
+// 
+void CAlfExAnalogDialerControl::SetWeightsOfGridL(  CAlfGridLayout& aGridLayout,
+                                                    TLayoutMode     aLayout,
+                                                    TInt            aSquareSide,
+                                                    TInt            aLongerSide,
+                                                    TInt&           aPlateTop)
+    {
+    // Set up a variable for default value.
+    RArray<TInt> weightsDefault;
+    User::LeaveIfError(weightsDefault.Append(1));   
+
+    // sets weights of grid. Use pixels to get exact adjustment of pane sizes
+    RArray<TInt> weights;
+    if (aLayout == ELayoutAnalogDialerPortrait)
+        {
+        // top: display
+        User::LeaveIfError(weights.Append(aLongerSide-aSquareSide));
+        // bottom: dialer
+        User::LeaveIfError(weights.Append(aSquareSide));
+        aGridLayout.SetRowsL(weights);
+        aGridLayout.SetColumnsL(weightsDefault);
+        
+        aPlateTop = aLongerSide-aSquareSide;
+        }
+    else
+        {
+        // left: dialer
+        User::LeaveIfError(weights.Append(aSquareSide));
+        // right: display
+        User::LeaveIfError(weights.Append(aLongerSide-aSquareSide));
+        aGridLayout.SetRowsL(weightsDefault);
+        aGridLayout.SetColumnsL(weights);
+        
+        aPlateTop = 0;
+        }         
+    weights.Close(); 
+    weightsDefault.Close(); 
+    }
+    
+    
+// ---------------------------------------------------------------------------
+// ConvertEventToPlateCentricPosition
+// ---------------------------------------------------------------------------
+// 
+void CAlfExAnalogDialerControl::ConvertEventToPlateCentricPosition(
+                                        const TAlfEvent&    aEvent,
+	                                    TInt                aPlateTopOffset,
+	                                    TInt                aSquareSide,
+	                                    TPoint&             aPlateCentricPoint)
+    {
+    // event position is converted in a such way that centre position of the plate is (0,0)
+    // iY: value is negative, if position is above the centre position
+    // iY: value is position, if position is under the centre position
+    // iX: value is negative, if position is to the left the centre position
+    // iX: value is position, if position is to the right of the centre position
+	const TInt plateCentreY = aPlateTopOffset + aSquareSide / 2;
+	aPlateCentricPoint.iX = aEvent.PointerEvent().iParentPosition.iX - aSquareSide / 2;
+	aPlateCentricPoint.iY = plateCentreY - aEvent.PointerEvent().iParentPosition.iY ;
+    }
+    
+    
+// ---------------------------------------------------------------------------
+// Checks whether pointer event occurred between outer and inner radius
+// ---------------------------------------------------------------------------
+// 
+TBool CAlfExAnalogDialerControl::IsPointerEventOnArcPath(   TPoint& aPlateCentricPoint,
+	                                                        TInt    aOuterRadius,
+	                                                        TInt    aInnerRadius)
+    {  
+    // Checks whether position is along a path, which is between two imaginary circles.
+    // Radius of circles are given. 
+    TBool ret = ETrue;   
+	TInt distanceFromPlateCentre = Hypotenuse(aPlateCentricPoint.iX, aPlateCentricPoint.iY); 	
+	if (distanceFromPlateCentre > aOuterRadius || distanceFromPlateCentre < aInnerRadius)
+	    {
+	    ret = EFalse;
+	    }
+	return ret;
+    }
+    
+// ---------------------------------------------------------------------------
+// Dragging has been stopped. Resets dragging data
+// ---------------------------------------------------------------------------
+// 
+void CAlfExAnalogDialerControl::ResetDraggingData()
+    {
+	iFlags &= (~EAnalogDialerControlDragging);
+	iDraggingData.iInitialAngle = 0;
+	iDraggingData.iPreviousAngle = 0;
+	iDraggingData.iIsClockWiseOverZeroReached = EFalse;
+	iDraggingData.iStopperReached=EFalse;
+    }
+
+// ---------------------------------------------------------------------------
+// Dragging has been stopped. Resets dragging data
+// ---------------------------------------------------------------------------
+// 
+void CAlfExAnalogDialerControl::ResetClearKeyData()
+    {
+	iFlags &= (~EAnalogDialerControlClearKeyEvent);
+    iFlags &= (~EAnalogDialerControlFlagLongTapPressed);
+    }
+
+
+// ---------------------------------------------------------------------------
+// Turns plate image back to idle position
+// ---------------------------------------------------------------------------
+// 
+void CAlfExAnalogDialerControl::RotatePlateToIdlePosition(CAlfImageVisual&    aImage)
+    {
+	// Rotate the image. This has immediate effect.
+	TAlfTimedValue tValue;
+	tValue.SetTargetWithSpeed(0,  // position zero 
+	                          KPlateReturnSpeed);
+	aImage.SetTurnAngle(tValue);
+    }
+    
+    
+// ---------------------------------------------------------------------------
+// Rotates image
+// ---------------------------------------------------------------------------
+// 
+void CAlfExAnalogDialerControl::RotatePlate(
+                                    CAlfImageVisual&    aImage,
+                                    TInt                aInitialAngle,
+                                    TInt                aTargetAngle,
+                                    TBool               aIsClockWiseOverZeroReached)
+    {
+    // When rotates clockwise, rotation angle is negative
+    TInt rotateDelta = aTargetAngle-aInitialAngle;
+    if (aIsClockWiseOverZeroReached)
+        {
+        // Angle is big value (near to 360), which cannot be used as such
+        // Convert it to negative value
+        rotateDelta = (aTargetAngle-360)-aInitialAngle;
+        }
+    //RDebug::Printf("***AnalogDialer rotateDelta : %d",rotateDelta);
+    TAlfTimedValue tValue(rotateDelta);
+    aImage.SetTurnAngle(tValue);
+    }
+    
+// ---------------------------------------------------------------------------
+// Debugs dragging data + given angle 
+// ---------------------------------------------------------------------------
+// 
+void CAlfExAnalogDialerControl::DebugDraggingData(TInt aAngle)
+    {
+    RDebug::Printf("\n***AnalogDialer:");
+    RDebug::Printf("***AnalogDialer iFlags & EAnalogDialerControlDragging: %d",iFlags & EAnalogDialerControlDragging);
+    RDebug::Printf("***AnalogDialer iDraggingData.iInitialAngle: %d",iDraggingData.iInitialAngle);
+    RDebug::Printf("***AnalogDialer iDraggingData.iPreviousAngle: %d",iDraggingData.iPreviousAngle);
+    RDebug::Printf("***AnalogDialer iDraggingData.iIsClockWiseOverZeroReached: %d",iDraggingData.iIsClockWiseOverZeroReached);
+    RDebug::Printf("***AnalogDialer iDraggingData.iStopperReached: %d",iDraggingData.iStopperReached);
+    RDebug::Printf("***AnalogDialer aAngle: %d",aAngle);
+    RDebug::Printf("\n");
+    }
+
+
+// ---------------------------------------------------------------------------
+// Returns selected number based on rotated angle of plate 
+// ---------------------------------------------------------------------------
+// 
+TInt CAlfExAnalogDialerControl::DialedNumber(   TInt aInitialAngle,
+                                                TInt aCurrentAngle) const
+    {
+    // Default value when dragging event has not crossed zero-angle X-axis
+    TInt deltaAngle = aCurrentAngle-aInitialAngle;
+    
+    // aCurrentAngle must be an angle derived directly from ConvertEventToPlateCentricPosition
+    if (iDraggingData.iIsClockWiseOverZeroReached)
+        {
+        deltaAngle = aInitialAngle+(360-KStopperAngle);
+        }
+    
+    // subtract required minimun angle
+    deltaAngle = Abs(deltaAngle)-KPlateMinimumRotateAngle;
+    if (deltaAngle<0)
+        {
+        return KErrNotFound;
+        }
+    // TODO. These values could be made constant to use plate with other number systems as decimal
+    // e.g. binary, or hexadecimal
+    // Finally calculate dialed number based on rotated angle
+    TInt angleOfANumber(KPlateNumbersDistributionAngle/10);
+    TInt dialedNumber = deltaAngle/angleOfANumber;
+    if (dialedNumber > 9)
+        {
+        dialedNumber = 9;
+        }
+    return dialedNumber;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Checks whether pointer is on path allowed for plate rotation
+// ---------------------------------------------------------------------------
+// 
+TBool CAlfExAnalogDialerControl::IsPointerEventFollowingNumbersArcPath( const TAlfEvent& aEvent ) const
+    {
+	TPoint plateCentricPoint;
+	ConvertEventToPlateCentricPosition(aEvent,
+	                                    iPlateTopOffset,
+	                                    iSquareSide,
+	                                    plateCentricPoint);
+    TInt degrees = Angle( plateCentricPoint.iX, plateCentricPoint.iY);
+	// Third parameter: Radius of clear area belongs to clear area
+	TInt plateRadius = iSquareSide / 2;
+	if ( IsPointerEventOnArcPath( plateCentricPoint,
+	                              plateRadius,
+	                              (plateRadius*KPlateClearRadius/100)+1))
+	    {
+	    return ETrue;
+	    }
+    return EFalse;
+    }
+    
+// ---------------------------------------------------------------------------
+// Checks whether pointer is on area of clear key
+// ---------------------------------------------------------------------------
+// 
+TBool CAlfExAnalogDialerControl::IsPointerEventOnClearKey( const TAlfEvent& aEvent ) const
+    {
+	TPoint plateCentricPoint;
+	ConvertEventToPlateCentricPosition(aEvent,
+	                                    iPlateTopOffset,
+	                                    iSquareSide,
+	                                    plateCentricPoint);
+	TInt plateRadius = iSquareSide / 2;
+	if ( IsPointerEventOnArcPath( plateCentricPoint,
+	                              plateRadius*KPlateClearRadius/100,
+	                              0))
+	    {
+	    return ETrue;
+	    }
+    return EFalse;
+    }
+    
+
+// ---------------------------------------------------------------------------
+// Performs actions needed when dragging is finished
+// ---------------------------------------------------------------------------
+// 
+void CAlfExAnalogDialerControl::FinishDragging()
+    {
+	// Dragging has finished
+	// Remove pointer dragging observer, which will gain us performance
+    Display()->Roster().RemovePointerEventObserver( EAlfPointerEventReportDrag,*this );
+    DialedNumberToDisplay(iDraggingData.iInitialAngle,
+                            iDraggingData.iPreviousAngle);
+    RotatePlateToIdlePosition(*iImage); 
+    ResetDraggingData();
+    }
+    
+// ---------------------------------------------------------------------------
+// Puts dialed number into number display
+// ---------------------------------------------------------------------------
+// 
+void CAlfExAnalogDialerControl::DialedNumberToDisplay(  TInt aInitialAngle,
+                                                        TInt aCurrentAngle )
+    {
+    TInt dialedNumber = DialedNumber(   aInitialAngle,
+                                        aCurrentAngle );
+    // Filter KErrNotFound out
+    if (dialedNumber>=0)
+        {
+        TRAP_IGNORE( AddNumberToDisplayPaneL( dialedNumber ) );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Clear number display either wholly or last number
+// ---------------------------------------------------------------------------
+// 
+void CAlfExAnalogDialerControl::ClearNumberDisplay(TBool aClearWholeDisplay)
+    {
+    TInt lengthNumber = iDisplayNumber.Length();
+    if (lengthNumber == 0)
+        {
+        return;
+        }
+
+    if (aClearWholeDisplay)
+        {
+        TBuf<1> clearBuf;        
+        iDisplayNumber.Copy(clearBuf);
+        }
+    else
+        {
+        // delete one number
+        iDisplayNumber.Delete(lengthNumber-1,1);
+        }
+    TRAP_IGNORE( iDisplayPane->SetTextL(iDisplayNumber) );
+    }
+
+void CAlfExAnalogDialerControl::AddEffectLayout()
+	{
+	
+	}
+// End of File
\ No newline at end of file