--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/exampleapps/alfexanalogdialer/src/alfexanalogdialercontrol.cpp Tue Feb 02 07:56:43 2010 +0200
@@ -0,0 +1,1081 @@
+/*
+* 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)
+
+// font color
+const TRgb KFontColor = TRgb(192,192,192);
+
+// dimension of grid
+const TInt KDimensionsOfGrid = 2;
+
+// Tags for visuals which have always same appearance.
+// TTagAnalogDialerVisual is used for indexing
+const char* KTagArray[] =
+ {
+ "root-layout",
+ "display-deck",
+ "display-visual",
+ "plate-deck",
+ "numbers-visual",
+ "plate-visaul",
+ "stopper-visual"
+ };
+
+// Dimensions of grid. iLayoutMode is used for indexing
+const TInt KRowsAndColumnsOfGrid[][KDimensionsOfGrid] =
+ {
+ { 1, 2 }, // columns, rows
+ { 2, 1 }
+ };
+
+// Template 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. Degrees per second.
+const TInt KPlateReturnSpeed = 65;
+
+// As dragging events occur very often, redrawing plate is optimised that
+// it is not drawn after every dragging event.
+// Plate is redrawn when angle of the plate has changed KPlateDraggingDelta clockwise.
+const TInt KPlateDraggingDelta = 2;
+
+// position of stopper in degrees. Angle is 43 clockwise down from the X-axis
+const TInt KStopperAngle = 360-43;
+
+// angle of arch on which numbers (or holes) are distributed
+const TInt KPlateNumbersDistributionAngle = 290;
+
+// minimum rotation of plate that a number becomes selected. If plate has been dialed
+// less than or equal to KPlateMinimumRotateAngle degrees, number is not selected.
+const TInt KPlateMinimumRotateAngle=43;
+
+// ---------------------------------------------------------------------------
+// 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()
+ {
+ // Remove observer is still there
+ 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. Id is needed in appui to retrieve control from control group
+ SetId(KAlfExAnalogDialerControlId);
+
+ // resolve layout: portrait or landscape
+ iLayoutMode = ResolveLayout(iSquareSide, iLongerSide);
+
+ // setup visuals accroding to layout
+ (iLayoutMode == ELayoutAnalogDialerPortrait) ? SetupPortraitModeL() : SetupLandscapeModeL();
+
+ // set up vibra system
+ iFeedback = CAlfExAnalogDialerFeedback::NewL();
+ }
+
+
+
+// ---------------------------------------------------------------------------
+// Creates layouts and visual for portrait layout
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::SetupPortraitModeL()
+ {
+ // Setup grid (root layout)
+ AddGridLayoutL();
+
+ // from top to bottom 1) display pane 2) dialer
+ AddDisplayPaneL();
+ AddDialerL();
+
+ //AddEffectLayout();
+ }
+
+// ---------------------------------------------------------------------------
+// Creates layouts and visual for portrait layout
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::SetupLandscapeModeL()
+ {
+ // Setup grid (root layout)
+ AddGridLayoutL();
+
+ // from left to right 1) dialer 2) display pane
+ AddDialerL();
+ AddDisplayPaneL();
+
+ //AddEffectLayout();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Creates grid layout or modify existing one after layout change
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::AddGridLayoutL()
+ {
+ if (!iRootLayout)
+ {
+ // Fresh start of the application. Create a grid layout to act as the root layout visual.
+ iRootLayout = CAlfGridLayout::AddNewL(*this,
+ KRowsAndColumnsOfGrid[iLayoutMode][EAlfGridColumn],
+ KRowsAndColumnsOfGrid[iLayoutMode][EAlfGridRow]);
+ // Tag is not really needed, because root layout assigned to member variable
+ iRootLayout->SetTagL(_L8(KTagArray[ETagAnalogDialerRootLayout]));
+
+ // 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);
+
+ // Append brush to the layout and transfer its ownership to the visual.
+ iRootLayout->Brushes()->AppendL(brush, EAlfHasOwnership);
+ CleanupStack::Pop(brush);
+ }
+ else
+ {
+ // Layout change has taken place. Modify dimensions and weights
+ // Reset current 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 up new dimension
+ iRootLayout->SetColumnsL(KRowsAndColumnsOfGrid[iLayoutMode][EAlfGridColumn]);
+ iRootLayout->SetRowsL(KRowsAndColumnsOfGrid[iLayoutMode][EAlfGridRow]);
+ }
+
+ // 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][EAlfGridColumn],
+ pad * KPaddingExtents[iLayoutMode][EAlfGridRow]));
+ layout->SetPadding(pad * KPaddingPercentage);*/
+ }
+
+
+// ---------------------------------------------------------------------------
+// Adds content into display pane of the application
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::AddDisplayPaneL()
+ {
+ CAlfDeckLayout* displayDeck = CAlfDeckLayout::AddNewL(*this, iRootLayout);
+ displayDeck->SetTagL(_L8( KTagArray[ETagAnalogDialerDisplayDeck]));
+
+ // Add TextVisual number display
+ iDisplayPane = CAlfTextVisual::AddNewL(*this, displayDeck );
+ // Tag is not really needed
+ iDisplayPane->SetTagL(_L8( KTagArray[ETagAnalogDialerDisplayVisual]));
+ 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);
+
+
+ // Enable brushed for borders etc
+ iDisplayPane->EnableBrushesL();
+
+ // Display rectangular
+ CAlfShadowBorderBrush* brush = CAlfShadowBorderBrush::NewLC(Env(),6);
+ brush->SetOpacity(.25f);
+
+ // Append brush to the visual 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()
+ {
+ // Dialer consists of three images on top of each other. Deck is needed to manage them
+ // Parent layout is grid
+ CAlfDeckLayout* dialerDeck = CAlfDeckLayout::AddNewL(*this, iRootLayout);
+ dialerDeck->SetTagL(_L8(KTagArray[ETagAnalogDialerPlateDeck]));
+
+ // Load images:
+ // 1) Image with the numbers
+ CAlfTexture& numbersTexture = Env().TextureManager().LoadTextureL( KImageAnalogDialerNumbers,
+ EAlfTextureFlagDefault,
+ KAlfAutoGeneratedTextureId);
+
+ // Parent layout is deck
+ CAlfImageVisual* numbers = CAlfImageVisual::AddNewL(*this,dialerDeck);
+ // Default scale mode CAlfImageVisual::EScaleFit is OK
+ // attach texture to image visual
+ numbers->SetImage(TAlfImage(numbersTexture));
+
+ // 2) plate with holes
+ CAlfTexture& plateTexture = Env().TextureManager().LoadTextureL( KImageAnalogDialerPlate,
+ EAlfTextureFlagDefault,
+ KAlfAutoGeneratedTextureId);
+ // Parent layout is deck
+ iPlate = CAlfImageVisual::AddNewL(*this,dialerDeck);
+ // Default scale mode CAlfImageVisual::EScaleFit is OK
+ iPlate->SetImage(TAlfImage(plateTexture));
+
+ // 2) stopper
+ CAlfTexture& stopper = Env().TextureManager().LoadTextureL( KImageAnalogDialerStopper,
+ EAlfTextureFlagDefault,
+ KAlfAutoGeneratedTextureId);
+ // Parent layout is deck
+ iStopper = CAlfImageVisual::AddNewL(*this,dialerDeck);
+ // Default scale mode CAlfImageVisual::EScaleFit is OK
+ iStopper->SetImage(TAlfImage(stopper));
+
+ }
+
+// ---------------------------------------------------------------------------
+// Events from framework
+// ---------------------------------------------------------------------------
+//
+TBool CAlfExAnalogDialerControl::OfferEventL(const TAlfEvent& aEvent)
+ {
+ // Ignore other events except pointer events
+ 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;
+ }
+
+// ---------------------------------------------------------------------------
+// Handles pointer down events
+// ---------------------------------------------------------------------------
+//
+TBool CAlfExAnalogDialerControl::HandlePointerDownEventL(const TAlfEvent& aEvent)
+ {
+ // Topmost image i.e. stopper image visual gets the pointer event
+ CAlfVisual* onVisual = aEvent.Visual();
+ if (onVisual == iStopper)
+ {
+ // Is plate rotating starting?
+ if (IsPointerEventFollowingNumbersArcPath(aEvent))
+ {
+ ResetDraggingData();
+
+ // Plate rotation is starting
+ // Register to receive dragging events
+ Display()->Roster().AddPointerEventObserver(EAlfPointerEventReportDrag, *this);
+
+ // Dragging has started
+ iFlags |= EAnalogDialerControlDragging;
+ }
+ // Is clear key pressed?
+ else if (IsPointerEventOnClearKey(aEvent))
+ {
+ ResetClearKeyData();
+
+ if (!(iFlags & EAnalogDialerControlFlagLongTapRegistered))
+ {
+ // Clear key handling needs long tap events
+ // Register for long tap events
+ Display()->Roster().AddPointerEventObserver(EAlfPointerEventReportLongTap, *this);
+ iFlags |= EAnalogDialerControlFlagLongTapRegistered;
+ }
+ // Clear key event has started
+ iFlags |= EAnalogDialerControlClearKeyEvent;
+ }
+ }
+ return ETrue;
+ }
+
+// ---------------------------------------------------------------------------
+// Handles dragging events
+// ---------------------------------------------------------------------------
+//
+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 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( *iPlate,
+ iDraggingData.iInitialAngle,
+ degrees,
+ iDraggingData.iIsClockWiseOverZeroReached);
+ }
+ // else - delta of rotation has not reached KPlateDraggingDelta
+ }
+ }
+ // else - it is permitted that clear key event is dragged outside clear key area. What matters is where
+ // the pointer event up takes place
+ return ETrue;
+ }
+
+// ---------------------------------------------------------------------------
+// Handle pointer up event
+// ---------------------------------------------------------------------------
+//
+TBool CAlfExAnalogDialerControl::HandlePointerUpEventL(const TAlfEvent& aEvent)
+ {
+ if (iFlags & EAnalogDialerControlDragging)
+ {
+ // Plate rotating has ended. Process result.
+ FinishDragging();
+ }
+ else if (iFlags & EAnalogDialerControlClearKeyEvent)
+ {
+ // clear key event has ended
+ 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;
+ }
+
+// ---------------------------------------------------------------------------
+// AddNumberToDisplayPaneL
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::AddNumberToDisplayPaneL(TInt aNumber)
+ {
+ if ( aNumber > 9 )
+ {
+ return;
+ }
+ TBuf<8> number;
+
+ // aNumber is 0...9
+ // Second parameter: number 10 must be changed to 0
+ number.Format(KNumberDisplayTemplate, (aNumber+1)%10);
+ if (iDisplayNumber.Length() + number.Length() <= KNumberDisplayBufferLength)
+ {
+ iDisplayNumber.Append(number);
+ iDisplayPane->SetTextL(iDisplayNumber);
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// SwitchLayoutL
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::SwitchLayoutL()
+ {
+ // Get access to first leafs (visuals) of grid layout
+ CAlfVisual* displayDeck = FindTag(_L8( KTagArray[ETagAnalogDialerDisplayDeck]));
+ CAlfVisual* dialerDeck = FindTag(_L8( KTagArray[ETagAnalogDialerPlateDeck]));
+
+ if (displayDeck && dialerDeck)
+ {
+ // remove visuals from grid layout
+ iRootLayout->Remove(displayDeck);
+ iRootLayout->Remove(dialerDeck);
+
+ // resolve new layout
+ iLayoutMode = ResolveLayout(iSquareSide,
+ iLongerSide);
+
+ // modify grid layout
+ AddGridLayoutL();
+
+ // put visuals back to layout
+ if (iLayoutMode == ELayoutAnalogDialerPortrait)
+ {
+ User::LeaveIfError(iRootLayout->Append(displayDeck));
+ User::LeaveIfError(iRootLayout->Append(dialerDeck));
+ }
+ else
+ {
+ User::LeaveIfError(iRootLayout->Append(dialerDeck));
+ User::LeaveIfError(iRootLayout->Append(displayDeck));
+ }
+
+ // Notify Alf about layout change
+ Env().NotifyLayoutChangedL();
+ }
+ // else - better not to do anything
+
+ iFeedback->Start();
+
+ // expose new root layout
+ /*TAlfTimedValue opacity(0.0f);
+ opacity.SetTarget(255, 500);
+ iRootLayout->SetOpacity(opacity); */
+
+ }
+
+// ---------------------------------------------------------------------------
+// Hides the visual
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::PrepareForLayoutSwitchL()
+ {
+ /*CAlfVisual* layout = FindTag(_L8(KTagArray[ETagAnalogDialerRootLayout]));
+ 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
+ {
+ // Resolve whether application is now running in portrait or landscape mode
+ // Function must also return the shorter extent of the application
+ // to be used as side length of the square of dialer plate.
+ // Longer side is returned also to be used in grid weights.
+ 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 is 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(const TPoint& aPosition)
+ {
+ TInt sideLength = aPosition.iX * aPosition.iX;
+ TInt oppositeLength = aPosition.iY * aPosition.iY;
+
+ TReal hypotenuse;
+ Math::Sqrt(hypotenuse, sideLength + oppositeLength);
+ return hypotenuse;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Order of function calls fix the layout of grid in portrait and landscape modes.
+// ---------------------------------------------------------------------------
+//
+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 pizels of application window size to get exact adjustment of pane sizes
+ RArray<TInt> weights;
+ if (aLayout == ELayoutAnalogDialerPortrait)
+ {
+ // top: display; take rest what dialer plate leaves for number display
+ User::LeaveIfError(weights.Append(aLongerSide-aSquareSide));
+
+ // bottom: dialer, which must be square
+ User::LeaveIfError(weights.Append(aSquareSide));
+ aGridLayout.SetRowsL(weights);
+
+ // default weight for dimension, which is 1. Needed, because weights are reset
+ aGridLayout.SetColumnsL(weightsDefault);
+
+ // Offset to the plate in Y-dimension is height of number display
+ aPlateTop = aLongerSide-aSquareSide;
+ }
+ else
+ {
+ // left: dialer, which must be square
+ User::LeaveIfError(weights.Append(aSquareSide));
+ // right: display; take rest what dialer plate leaves for number display
+ User::LeaveIfError(weights.Append(aLongerSide-aSquareSide));
+
+ // default weight for dimension, which is 1. Needed, because weights are reset
+ 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 below the centre position
+ // iY: value is position, if position is above 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
+
+ // aSquare side is length of whole square side
+ 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 radii.
+ // Event may be exactly on distance of radii
+ TBool ret = ETrue;
+ TInt distanceFromPlateCentre = Hypotenuse(aPlateCentricPoint);
+ if (distanceFromPlateCentre > aOuterRadius || distanceFromPlateCentre < aInnerRadius)
+ {
+ ret = EFalse;
+ }
+ return ret;
+ }
+
+// ---------------------------------------------------------------------------
+// Dragging has finished. Resets dragging data
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::ResetDraggingData()
+ {
+ iFlags &= (~EAnalogDialerControlDragging);
+ iDraggingData.iInitialAngle = 0;
+ iDraggingData.iPreviousAngle = 0;
+ iDraggingData.iIsClockWiseOverZeroReached = EFalse;
+ iDraggingData.iStopperReached=EFalse;
+ }
+
+// ---------------------------------------------------------------------------
+// Clear key event has finished. Resets dragging data
+// ---------------------------------------------------------------------------
+//
+void CAlfExAnalogDialerControl::ResetClearKeyData()
+ {
+ iFlags &= (~EAnalogDialerControlClearKeyEvent);
+ iFlags &= (~EAnalogDialerControlFlagLongTapPressed);
+ }
+
+
+// ---------------------------------------------------------------------------
+// Turns plate back to idle position i.e. counter clokcwise
+// ---------------------------------------------------------------------------
+//
+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 clockwise
+// ---------------------------------------------------------------------------
+//
+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);
+ }
+
+// ---------------------------------------------------------------------------
+// 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
+ // aCurrentAngle is really current pointer position. KStopper value must be used instead
+ if (iDraggingData.iIsClockWiseOverZeroReached)
+ {
+ deltaAngle = aInitialAngle+(360-KStopperAngle);
+ }
+
+ // Subtract required minimun angle.
+ deltaAngle = Abs(deltaAngle)-KPlateMinimumRotateAngle;
+ if (deltaAngle<0)
+ {
+ // plate has not been rotated enough to select any number
+ 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
+// The path is between edges of plate and clear key area
+// ---------------------------------------------------------------------------
+//
+TBool CAlfExAnalogDialerControl::IsPointerEventFollowingNumbersArcPath( const TAlfEvent& aEvent ) const
+ {
+ TPoint plateCentricPoint;
+ ConvertEventToPlateCentricPosition(aEvent,
+ iPlateTopOffset,
+ iSquareSide,
+ plateCentricPoint);
+ // Third parameter: Radius of clear area belongs to clear area. Eliminate it.
+ 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;
+ // Third parameter: The 'bull eye' of the plate
+ 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(*iPlate);
+ 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)
+ {
+ // nothing to clear
+ return;
+ }
+
+ if (aClearWholeDisplay)
+ {
+ // clear whole buf
+ iDisplayNumber.Zero();
+ }
+ else
+ {
+ // delete one number
+ iDisplayNumber.Delete(lengthNumber-1,1);
+ }
+ // changed number to the screen
+ TRAP_IGNORE(iDisplayPane->SetTextL(iDisplayNumber));
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+/*void CAlfExAnalogDialerControl::AddEffectLayout()
+ {
+
+ }*/
+
+
+// ---------------------------------------------------------------------------
+// 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");
+ }
+