diff -r 072a5fa0c63b -r c6bafb5162d8 voicerecorder/RecViewSrc/CVRButtonPanel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/voicerecorder/RecViewSrc/CVRButtonPanel.cpp Wed Sep 01 12:29:14 2010 +0100 @@ -0,0 +1,857 @@ +/* +* Copyright (c) 2002 - 2006 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: +* A compound control class. It is responsible for drawing and updating +* a set of buttons. Button selections are also handled and forwarded +* as commands to the AppUi. +* +*/ + + +// INCLUDE FILES + +#include +#include +#include +#include +#include +#include +#include // TResourceReader +#include +#include // New button highlight +#include // Timer +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "CVRButtonPanel.h" +#include "MVRButtonPanelModel.h" +#include "voicerecorder.hrh" +#include "VRConsts.h" + +// CONSTANTS + +// Timer delays +const TInt KVRFastForwStartDelay( 500000 ); +const TInt KVRFastForwUpdateDelay( 170000 ); + +const TInt KVRButtonCount( 5 ); // Total number of buttons +const TInt KVRAmountOfFocusShrink( 5 ); + + +// ================= MEMBER FUNCTIONS ======================================== + +// --------------------------------------------------------------------------- +// CVRButtonPanel::CVRButtonPanel +// +// --------------------------------------------------------------------------- +// +CVRButtonPanel::CVRButtonPanel( MVRButtonPanelModel* aModel ) + : iModel( aModel ), + iVRButtons( KVRButtonCount ) + { + __ASSERT_DEBUG( iModel, User::Panic( KVRPanic, KErrNotFound ) ); + iModel->SetButtonPanelObserver( this ); + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::CVRButtonPanel +// +// --------------------------------------------------------------------------- +// +CVRButtonPanel::CVRButtonPanel( MVRButtonPanelModel* aModel, + TUid aParentViewUid ) + : iModel( aModel ), + iParentViewUid( aParentViewUid ), + iVRButtons( KVRButtonCount ) + { + __ASSERT_DEBUG( iModel, User::Panic( KVRPanic, KErrNotFound ) ); + iModel->SetButtonPanelObserver( this ); + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::~CVRButtonPanel +// Destructor +// --------------------------------------------------------------------------- +// +CVRButtonPanel::~CVRButtonPanel() + { + if ( iModel ) + { + iModel->SetButtonPanelObserver( NULL ); + } + + iVRButtons.ResetAndDestroy(); + delete iTimer; + iModel = NULL; + iSkin = NULL; + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::ConstructL +// +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::ConstructL() + { + iSkin = AknsUtils::SkinInstance(); + + // Create buttons from resources + CreateButtonsFromResourcesL( R_VR_BUTTON_PANEL_BUTTONS ); + UpdateButtons(); + + // Has to be done to get the buttons' background shown correctly + for ( TInt i = 0; i < iVRButtons.Count(); i++ ) + { + iVRButtons.At( i )->SetBackground( this ); + } + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::CreateButtonsFromResourcesL +// Creates buttons from resources +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::CreateButtonsFromResourcesL( TInt aButtonsResourceId ) + { + TResourceReader reader; + iEikonEnv->CreateResourceReaderLC( reader, aButtonsResourceId ); + + TInt numButtons( reader.ReadInt16() ); + + // Create buttons + for (TInt i = 0; i < numButtons; i++ ) + { + CAknButton* aknButton = CAknButton::NewL(); + CleanupStack::PushL( aknButton ); + + aknButton->SetContainerWindowL( *this ); + aknButton->SetMopParent( this ); + aknButton->ConstructFromResourceL( reader ); + aknButton->SetObserver( this ); + + // Set ready to be drawn and add it to array + aknButton->ActivateL(); + iVRButtons.AppendL( aknButton ); + + CleanupStack::Pop( aknButton ); // aknButton + } + + CleanupStack::PopAndDestroy(); // reader; + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::Update +// This method can be called via MVRObserver class when Button Panel needs +// to be updated. +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::Update( TVRUpdateCommand aCommand ) + { + + TBool drawNow( ETrue ); + + // Recorder calls this after each tick, we have to check if button reset + // is needed. Redraw is needed also after 1 secs playback to enable + // rewind button. + switch( aCommand ) + { + case EVRUpdate1Second: + case EVRUpdate: + case EVRUpdateStateChange: + { + // Redraw + drawNow = ETrue; + break; + } + case EVRUpdatePositionChange: + { + // Skip redraw + drawNow = EFalse; + break; + } + default: + { + // Skip redraw + drawNow = EFalse; + return; + } + } + + if ( iModel->ResetNeeded() ) + { + iFocusedButton = iModel->InitialFocusButtonId(); + } + + UpdateButtons(); + + // Change focus if focused button is dimmed + TuneButtonFocus(); + + if ( drawNow ) + { + DrawNow(); + } + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::SizeChanged +// Called when Button Panel layout needs to be updated +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::SizeChanged() + { + TInt count( iModel->ButtonCount() ); + + TSize size; // Size of the bitmap + + for ( TInt i( 0 ); i < count; i++ ) + { + // Layout button. + TAknWindowLineLayout cell = AppLayout::cell_vorec_pane( i ); + + TAknLayoutRect buttonLayout; + buttonLayout.LayoutRect( Rect(), cell ); + TRect buttonRect = buttonLayout.Rect(); + TInt newSize = (TInt)(buttonRect.Width() * 0.1); // used to reduce the size of button + buttonRect.Shrink( TSize(newSize,newSize) ); + iVRButtons.At( i )->SetRect( buttonRect ); + } + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::OfferKeyEventL +// Key event handling +// --------------------------------------------------------------------------- +// +TKeyResponse CVRButtonPanel::OfferKeyEventL( const TKeyEvent& aKeyEvent, + TEventCode aType ) + { + if ( aType != EEventKey ) + { + if( aType == EEventKeyDown ) + { + // Rocker key pressed + if ( aKeyEvent.iScanCode == EStdKeyDevice3 ) + { + // Start timer to get continuous timercallbacks for + // FastForwarding and FastRewinding + StartTimerL(); + } + } + else if( aType == EEventKeyUp ) + { + // Rocker key pressed + if ( aKeyEvent.iScanCode == EStdKeyDevice3 ) + { + StopTimer(); + } + } + return EKeyWasNotConsumed; + } + // EEventKey + switch ( aKeyEvent.iCode ) + { + case EKeyDownArrow: + { + MoveFocus( EFocusDown, ETrue ); + break; + } + case EKeyUpArrow: + { + MoveFocus( EFocusUp, ETrue ); + break; + } + case EKeyEnter: + case EKeyOK: + { + // This is in use as long as there are only 2 CBA buttons. When MSK + // enabled, execution goes straight to CVRRecView::HandleCommandL + FetchAndSendCommandL(); + break; + } + default: + { + return EKeyWasNotConsumed; + } + } + + return EKeyWasConsumed; + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::Draw +// Needed to get correct focus drawing with AknButtons +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::Draw( CWindowGc& /*aGc*/, const CCoeControl& /*aControl*/, + const TRect& /*aRect*/ ) const + { + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::Draw +// +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::Draw( const TRect& /*aRect*/ ) const + { + CWindowGc& gc = SystemGc(); + // Acquire the control context through the MOP-chain + MAknsControlContext* context = AknsDrawUtils::ControlContext( this ); + + // Draw the background using the control context + // Note: if there is no skin, the background is just cleared + // (which is OK for us) + AknsDrawUtils::Background( iSkin, context, this, gc, Rect() ); + + // Draw button highlight + DrawFocus( gc ); + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::CountComponentControls +// +// --------------------------------------------------------------------------- +// +TInt CVRButtonPanel::CountComponentControls() const + { + return iVRButtons.Count(); + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::ComponentControl +// +// --------------------------------------------------------------------------- +// +CCoeControl* CVRButtonPanel::ComponentControl( TInt aIndex ) const + { + return iVRButtons.At( aIndex ); + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::MoveFocus +// Moves the focus to next button up or down. aDirection tells the which. +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::MoveFocus( const TFocusChange aDirection, TBool aDrawNow ) + { + TInt buttonCount( iModel->ButtonCount() ); + TInt newButton( iFocusedButton ); + + for ( TInt i( 0 ); i < buttonCount; i++ ) + { + // calculate new button id. the modulo operator (%) handles looping + newButton = ( newButton + aDirection + buttonCount ) % buttonCount; + // dimmed buttons are skipped + if ( iModel->ButtonState( newButton ) != EDimmed ) + { + iFocusedButton = newButton; + + // Timer is used for FastForward/-Rewind. Stop that when focus is + // changed. + StopTimer(); + break; + } + } + + if ( aDrawNow ) + { + DrawNow(); + } + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::UpdateLayoutL +// +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::UpdateLayoutL( ) + { + SizeChanged(); + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::HandleResourceChangeL +// +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::HandleResourceChangeL( TInt aType ) + { + CCoeControl::HandleResourceChange( aType ); + + if ( aType == KEikDynamicLayoutVariantSwitch ) + { + UpdateLayoutL(); + } + else if ( aType == KAknsMessageSkinChange ) + { + // New skin instance is loaded + iSkin = AknsUtils::SkinInstance(); + } + + // Inform Avkon Buttons + for( TInt buttonIndex = 0; buttonIndex < iVRButtons.Count() ; + buttonIndex++ ) + { + iVRButtons.At( buttonIndex )->HandleResourceChange( aType ); + } + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::UpdateButtons +// Updates all Button Panel buttons to correct visual state. Also few +// exceptional cases are handled here (1. clip position is at the beginning +// 2. clip position is at the end) +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::UpdateButtons() + { + TUint stateId; + // Update all the buttons + for( TInt buttonIndex = 0; buttonIndex < iVRButtons.Count() ; + buttonIndex++ ) + { + stateId = iModel->VisualStateId(); + + // dim rewind button if there is nothing to rewind + if ( buttonIndex == EButtonRewind && + iModel->ButtonState( buttonIndex ) == EDimmed ) + { + iVRButtons.At( buttonIndex )->SetDimmed(ETrue); + stateId = EStateDisableButtons; + } + if ( buttonIndex == EButtonRewind && + iModel->ButtonState( buttonIndex ) != EDimmed ) + { + iVRButtons.At( buttonIndex )->SetDimmed(EFalse); + } + // dim forward button if there is nothing to forward + if( buttonIndex == EButtonForward && + iModel->ButtonState( buttonIndex ) == EDimmed ) + { + iVRButtons.At( buttonIndex )->SetDimmed(ETrue); + stateId = EStateDisableButtons; + } + if( buttonIndex == EButtonForward && + iModel->ButtonState( buttonIndex ) != EDimmed ) + { + iVRButtons.At( buttonIndex )->SetDimmed(EFalse); + } + + // ************ADDED CODE STARTS**************************** + if( buttonIndex == EButtonRecord && + iModel->ButtonState( buttonIndex ) == EDimmed ) + { + stateId = EStateDisableButtons; + } + // ************ADDED CODE ENDS****************************** + + if( iModel->ButtonState( buttonIndex ) == EDimmed ) + { + iVRButtons.At( buttonIndex )->SetDimmed(ETrue); + } + else + { + iVRButtons.At( buttonIndex )->SetDimmed(EFalse); + } + + // Change the button state, don't redraw + iVRButtons.At( buttonIndex )->SetCurrentState( stateId , EFalse ); + } + } + + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::DrawFocus() +// Draws the focus rectangle around the currently focused button +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::DrawFocus( CWindowGc& aGc ) const + { + + aGc.SetBrushStyle( CGraphicsContext::ENullBrush ); + + if ( AknLayoutUtils::ScalableLayoutInterfaceAvailable() ) + { + // From LAF-table +// TAknWindowLineLayout area = +// AknLayoutScalable_Apps::grid_highlight_pane_cp05().LayoutLine(); + +// TRect buttonRect = iVRButtons.At( iFocusedButton )->Rect(); + TAknWindowLineLayout area = AppLayout::cell_vorec_pane( iFocusedButton ); + + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( Rect(), area ); +// layoutRect.LayoutRect( buttonRect, area ); + + // The outer rectangle is calculated from the layoutRect + TRect outerRect = TRect( layoutRect.Rect().iTl, layoutRect.Rect().iBr ); + + // Inner rectangle is generated by shrinking the outer rect. + TRect innerRect = outerRect; + innerRect.Shrink( TSize( KVRAmountOfFocusShrink, + KVRAmountOfFocusShrink ) ); + + if (iModel->ButtonState( iFocusedButton ) != EDimmed ) + { + //Focus frame is drawn + aGc.SetPenStyle( CGraphicsContext::ENullPen ); + TBool highlightDrawn = AknsDrawUtils::DrawFrame( iSkin, aGc, + outerRect, innerRect, KAknsIIDQsnFrGrid, KAknsIIDNone ); + } + } + else + { + if ( iModel->ButtonState( iFocusedButton ) != EDimmed ) + { + // Old basic rectangle is drawn + aGc.SetPenStyle( CGraphicsContext::ESolidPen ); + aGc.DrawRect( iVRButtons.At( iFocusedButton )->Rect() ); + } + } + + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::FocusedButton() +// Returns the index for the currently focused button +// --------------------------------------------------------------------------- +// +TInt CVRButtonPanel::FocusedButton() const + { + return iFocusedButton; + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::StartTimerL +// Create and start a timer with initial delay of KVRFastForwStartDelay +// and with callback frequency of KVRFastForwUpdateDelay +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::StartTimerL() + { + if ( iTimer ) + { + // stop if iTimer is already running + StopTimer(); + } + + TCallBack cb( TimerCallBack, this ); + iTimer = CPeriodic::NewL( 0 ); + iTimer->Start( KVRFastForwStartDelay, KVRFastForwUpdateDelay, cb ); + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::StopTimer +// Stop the timer by deleting the CPeriodic object +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::StopTimer() + { + delete iTimer; + iTimer = NULL; + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::TimerCallBack +// Timer callback for iTimer. Time between callbacks is KVRFastForwUpdateDelay +// --------------------------------------------------------------------------- +// +TInt CVRButtonPanel::TimerCallBack( TAny* aButtonPanel ) + { + CVRButtonPanel* buttonPanel = reinterpret_cast< CVRButtonPanel* > + ( aButtonPanel ); + + buttonPanel->HandleTimerCallBack(); + + return ETrue; + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::HandleTimerCallBack +// Non-static variant of TimerCallBack (more convinient to implement) +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::HandleTimerCallBack() + { + // Callbacks are handled only if focus is on rewind or forward button + if (iFocusedButton == EButtonRewind || iFocusedButton == EButtonForward) + { + TRAPD( err, FetchAndSendCommandL() ); + + if ( err ) + { + RDebug::Print(_L("VoiceRecorder: FetchAndSendCommandL, error ID: %d"), + err); + StopTimer(); + } + } + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::FetchAndSendCommand +// Fetches the command relating to focused button from the model. Command is +// sent on to active view. +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::FetchAndSendCommandL() + { + // Don't forward the command if dimmed button was clicked or + // if model can't handle commands + if ( iModel->ButtonState( iFocusedButton ) == EDimmed || + !iModel->CanHandleCommands() ) + { + return; + } + + // Send a command id to the active view specified in the button + CAknViewAppUi* appUi = reinterpret_cast< CAknViewAppUi* >( + CEikonEnv::Static()->EikAppUi() ); + CAknView* view = appUi->View( iParentViewUid ); + view->HandleCommandL( iModel->CommandId( iFocusedButton ) ); + + Update( EVRUpdateStateChange ); + + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::TuneButtonFocus +// The special cases when button focus has to be moved are handled here +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::TuneButtonFocus() + { + + // CVRRecViewModel::ButtonState() returns EDimmed for EButtonRewind if + // the position of the clip is at the beginning + if ( iFocusedButton == EButtonRewind && + iModel->ButtonState( iFocusedButton ) == EDimmed ) + { + iVRButtons.At( iFocusedButton )->SetDimmed(ETrue); + MoveFocus( EFocusDown, EFalse ); + } + + // CVRRecViewModel::ButtonState() returns EDimmed for EButtonForward if + // the position of the clip is at the end + else if( iFocusedButton == EButtonForward && + iModel->ButtonState( iFocusedButton ) == EDimmed ) + { + iVRButtons.At( iFocusedButton )->SetDimmed(ETrue); + MoveFocus( EFocusUp, EFalse ); + } + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::HandleControlEventL +// A callback function of Avkon buttons. Handles EEventStateChanged type events +// which happen every time when some of the buttons is pressed and button state +// changes. Event comes before CAknButton::Draw method is executed. +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::HandleControlEventL( CCoeControl *aControl, + TCoeEvent aEventType ) + { + if( AknLayoutUtils::PenEnabled() ) + { + + switch( aEventType ) + { + case EEventStateChanged: + { + + TInt newFocusedButton( 0 ); + for( TInt i = 0; i < iVRButtons.Count() ; i++ ) + { + // Which of buttons was pressed + if ( aControl == iVRButtons.At( i ) ) + { + // When new state is the first state, we have to set + // new state to ENumStates to be able to se a correct + // state in SetCurrentState( stateId - 1 , EFalse ); + TInt stateId( iVRButtons.At( i )->StateIndex() ); + if( stateId == 0 ) + { + stateId = ENumStates; + } + + // CAknButton automatically changes the state to next + // one always when it's ,pressed whether we want it or + // not. To prevent this we set the previous state + // before button draws itself + iVRButtons.At( i )->SetCurrentState( stateId - 1, + EFalse ); + newFocusedButton = i; + break; + } + } + + // Focus already was on pressed button so button's command is + // executed + if ( iFocusedButton == newFocusedButton ) + { + // Don't forward the command if dimmed button was clicked + if ( iModel->ButtonState( iFocusedButton ) == EDimmed ) + { + break; + } + + // Send a command id specified in the button to an + // active view + CAknViewAppUi* appUi = reinterpret_cast< CAknViewAppUi* >( + CEikonEnv::Static()->EikAppUi() ); + CAknView* view = appUi->View( iParentViewUid ); + view->HandleCommandL( iModel->CommandId( iFocusedButton ) ); + + // To make FastForwarding/FastRewinding possible + if ( iFocusedButton == EButtonRewind || + iFocusedButton == EButtonForward ) + { + if ( iLastPointerEvent == EVRButtonDownEvent ) + { + StartTimerL(); + } + } + + Update( EVRUpdateStateChange ); + } + // Focus was not on the focused button -> + // Focus should be changed + else if ( newFocusedButton >= 0 && + newFocusedButton < iVRButtons.Count() ) + { + //draw focus + if ( iModel->ButtonState( newFocusedButton ) != EDimmed ) + { + iFocusedButton = newFocusedButton; + DrawNow(); + + // Send a command id specified in the button to an + // active view + CAknViewAppUi* appUi = reinterpret_cast< CAknViewAppUi* >( + CEikonEnv::Static()->EikAppUi() ); + CAknView* view = appUi->View( iParentViewUid ); + view->HandleCommandL( iModel->CommandId( iFocusedButton ) ); + // To make FastForwarding/FastRewinding possible + if ( iFocusedButton == EButtonRewind || + iFocusedButton == EButtonForward ) + { + if ( iLastPointerEvent == EVRButtonDownEvent ) + { + StartTimerL(); + } + } + } + // for one error about touch UI, when click a dimmed button, the dimmed + // button should not go back to umdimmed. + else + { + DrawNow(); + } + } + break; + } + default: + { + // No default behaviour + break; + } + } + + } + } + + +// --------------------------------------------------------------------------- +// CVRButtonPanel::HandlePointerEventL +// Handles Button panel pointer events. True functionality is to stop +// FastForward timer when FF should be stopped. +// --------------------------------------------------------------------------- +// +void CVRButtonPanel::HandlePointerEventL( const TPointerEvent& aPointerEvent ) + { + if( AknLayoutUtils::PenEnabled() ) + { + + + switch( aPointerEvent.iType ) + { + case TPointerEvent::EButton1Down: + { + // Don't start timer here. It's started in HandleControlEventL() + iLastPointerEvent = EVRButtonDownEvent; + break; + } + case TPointerEvent::EDrag: + { + // Don't stop timer if just dragging inside the currently + // focused button + TRect focusedButtonRect( + iVRButtons.At( iFocusedButton )->Rect() ); + if( !focusedButtonRect.Contains( aPointerEvent.iPosition ) ) + { + // Dragged outside + iLastPointerEvent = EVRButtonDragOutsideEvent; + StopTimer(); + } + break; + } + case TPointerEvent::EButton1Up: + { + // Pen up + iLastPointerEvent = EVRButtonUpEvent; + StopTimer(); + break; + } + default: + { + break; + } + } + + CCoeControl::HandlePointerEventL( aPointerEvent ); + } + } + +// End of file