diff -r 000000000000 -r 2f259fa3e83a uifw/EikStd/coctlsrc/AknButton.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uifw/EikStd/coctlsrc/AknButton.cpp Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,4491 @@ +/* +* Copyright (c) 2005-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: Button component +* +*/ + + +// INCLUDE FILES +#include + +#include // CGulIcon +#include // TResourceReader +#include +#include // StringLoader +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // for testability hooks +#include "aknresourceprovider.h" +#include "aknbitmapresourceitem.h" +#include "akncommandbuttonstate.h" + +#include +const TUint KPointerFlag = 3; // second bit + + +// CONSTANTS +enum TSkinItemIdIndex + { + KFrameId = 0, + KCenterId, + KLatchedFrameId, + KLatchedCenterId, + KDimmedFrameId, + KDimmedCenterId, + KPressedFrameId, + KPressedCenterId, + KLatchedDimmedFrameId, + KLatchedDimmedCenterId + }; + +// ATTENTION, if the values bellow are changed, make the changes in AknButton.h +const TInt KTimeoutBeforeHelpNote = 150; // in milliseconds +const TInt KTimeoutInViewHelpNote = 3000; // in milliseconds + +const TInt KKeyRepeatDelay = 500000; // 0,5 seconds +const TInt KKeyRepeatInterval = 500000; // 0,5 seconds +const TInt KLongPressInterval = 800000; // 0,8 seconds + +const TInt KDragEventSensitivity = 1; + +// Value table for 70% Transparency +const TInt KTransparency[256] = + { + 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, + 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, + 14, 14, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 19, + 19, 19, 20, 20, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23, 23, 24, 24, + 24, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29, 29, 29, + 30, 30, 30, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 34, 34, 34, 35, 35, + 35, 35, 36, 36, 36, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 40, 40, 40, + 41, 41, 41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 46, + 46, 46, 47, 47, 47, 47, 48, 48, 48, 49, 49, 49, 50, 50, 50, 50, 51, 51, + 51, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 55, 55, 55, 56, 56, 56, 56, + 57, 57, 57, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 61, 61, 61, 62, 62, + 62, 62, 63, 63, 63, 64, 64, 64, 65, 65, 65, 65, 66, 66, 66, 67, 67, 67, + 68, 68, 68, 68, 69, 69, 69, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 73, + 73, 73, 74, 74, 74, 74, 75, 75, 75, 76, 76, 76, 77, 77 + }; + +// ----------------------------------------------------------------------------- +// ResizeIcon +// Tries to resize the given icon. If the operation fails the icon is deleted. +// ----------------------------------------------------------------------------- +// +static TInt ResizeIcon( CGulIcon*& aIcon, + const TSize& aSize, + TScaleMode aScaleMode ) + { + TInt retval = KErrNotFound; + + if ( aIcon ) + { + CFbsBitmap* bmp = aIcon->Bitmap(); + + if ( bmp ) + { + retval = !( aSize == bmp->SizeInPixels() ); + } + + if ( retval != KErrNone ) + { + retval = AknIconUtils::SetSize( bmp, aSize, aScaleMode ); + } + + // Retval is checked outside of the "if ( bmp )" scope above in order + // to detect if the given icon's bitmap is NULL. This is required since + // AknIconUtils::SetSize returns KErrNone for NULL bitmaps and we want + // to delete icons that couldn't be resized. + if ( retval != KErrNone ) + { + delete aIcon; + aIcon = NULL; + } + } + + return retval; + } + +static void ReplaceIconStatic( CGulIcon*& aIcon, CGulIcon* aNewIcon, + TScaleMode aScaleMode ) + { + TSize iconSize( 0, 0 ); + + if ( aIcon && aIcon->Bitmap() ) + { + iconSize = aIcon->Bitmap()->SizeInPixels(); + } + + delete aIcon; + aIcon = aNewIcon; + + if ( iconSize != TSize( 0, 0 ) ) + { + ResizeIcon( aIcon, iconSize, aScaleMode ); + } + } + +// ----------------------------------------------------------------------------- +// CreateAndSetDimmedIconL +// Creates and sets a dimmed icon from the normal icon +// by making a partially transparent version of it. +// +// @param aIcon The original icon +// @param aDimmedIcon The dimmed icon +// @param aScaleMode The preferred ScaleMode +// ----------------------------------------------------------------------------- +static void CreateAndSetDimmedIconL( CGulIcon*& aDimmedIcon, + const CGulIcon* aIcon, + TScaleMode aScaleMode ) + { + if ( aIcon ) + { + CFbsBitmap* mask = aIcon->Mask(); + + if ( mask && mask->DisplayMode() == EGray256 ) + { + CGulIcon* newIcon = CGulIcon::NewLC(); + CFbsBitmap* newPic = new ( ELeave ) CFbsBitmap; + CleanupStack::PushL( newPic ); + + newPic->Duplicate( aIcon->Bitmap()->Handle() ); + newIcon->SetBitmap( newPic ); + + CFbsBitmap* newMask = new ( ELeave ) CFbsBitmap; + + User::LeaveIfError( newMask->Create( + newIcon->Bitmap()->SizeInPixels(), EGray256 ) ); + CleanupStack::PushL( newMask ); + + CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL( newMask ); + CleanupStack::PushL( bitmapDevice ); + + CFbsBitGc* bitGc( NULL ); + User::LeaveIfError( bitmapDevice->CreateContext( bitGc ) ); + CleanupStack::PushL( bitGc ); + + bitGc->SetPenStyle( CGraphicsContext::ESolidPen ); + bitGc->BitBlt( TPoint( 0, 0 ), mask ); + + newMask->LockHeap(); + TInt w = mask->SizeInPixels().iWidth; + TInt h = mask->SizeInPixels().iHeight; + TInt dataStride = mask->DataStride() - w; + unsigned char* address = (unsigned char *)newMask->DataAddress(); + + for ( TInt i = 0; i < h; ++i ) + { + for ( TInt j = 0; j < w; ++j ) + { + *address = KTransparency[*address]; + ++address; + } + address += dataStride; + } + + newMask->UnlockHeap(); + newIcon->SetMask( newMask ); + ReplaceIconStatic( aDimmedIcon, newIcon, aScaleMode ); + + CleanupStack::PopAndDestroy( 2 ); // bitmapDevice, bitGc + CleanupStack::Pop( 3 ); // newIcon, newPic, newMask + } + } + } +// ============================ EXTENSION CLASS ================================ + +NONSHARABLE_CLASS( CAknButtonExtension ) : public CBase, MCoeControlHitTest + { + friend class CAknButton; + +public: + // bitflags used to keep track of several button's internal features + enum TFlags + { + EUseAdditionalMask, + ECheckHitArea, + EDimmed, + ELongPressReported, + EUseDefaultIconSize, + EKeyRepeatEventReported, + EUseDefaultMargins + }; + + static CAknButtonExtension* NewL( CAknButton& aButton ); + ~CAknButtonExtension(); + + // Starts the long press timer. + void StartLongPressTimerL(); + + TBool HitRegionContains( const TPoint &aPoint, + const CCoeControl &aControl ) const; + + void HandleFeedbackAreaChange(); +private: + + CAknButtonExtension( CAknButton& aButton ); + void ConstructL(); + + // Callback method for long press timer. + static TInt ReportLongPressL( TAny* aThis ); + + // Handles long press. + void DoReportLongPressL(); + + // Deletes pressed down bitmaps + void DeletePressedBmps(); + + // Fetches bitmaps from resource provider (if one exists) + TBool FetchProviderPressedBmpsL(); + + // Sets bitmaps to resource provider (if one exists) + void SetProviderPressedBmpsL(); + +private: // Data + + CAknButton& iButton; + CAknButton::TTooltipPosition iTooltipPosition; + CAknPictographInterface* iPictographInterface; // not owned + CPeriodic* iLongPressTimer; + TInt iLongPressInterval; + TFontUnderline iUnderlineStyle; + RArray iFrameAndCenterIds; + CAknButton::TAlignment iVerticalIconAlignment; + CAknButton::TAlignment iHorizontalIconAlignment; + TMargins8 iMargins; + TSize iIconSize; + CAknButton::TTextAndIconAlignment iTextAndIconAlignment; + TBitFlags iFlags; + MTouchFeedback* iFeedback; + CFbsBitmap* iPressedDownBmp; + CFbsBitmap* iPressedDownBmpMask; + CAknResourceProvider* iResourceProvider; + }; + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CAknButtonExtension::CAknButtonExtension +// C++ default constructor. +// ----------------------------------------------------------------------------- +// +CAknButtonExtension::CAknButtonExtension( CAknButton& aButton ) + : iButton( aButton ), + iTooltipPosition( CAknButton::EPositionTop ), + iLongPressTimer( NULL ), + iLongPressInterval( KLongPressInterval ), + iUnderlineStyle( EUnderlineOff ), + iFrameAndCenterIds( 2 ), + iVerticalIconAlignment( CAknButton::ECenter ), + iHorizontalIconAlignment( CAknButton::ECenter ), + iTextAndIconAlignment( CAknButton::EIconBeforeText ), + iResourceProvider( 0 ) + { + // default margins, these are applied to both text and icon + iMargins.SetAllValuesTo( + AknLayoutScalable_Avkon::aid_value_unit2().LayoutLine().iW / 10 ); + + // default icon size + TRect rect( TSize( 100, 100 ) ); + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( rect, + AknLayoutScalable_Avkon::toolbar_button_pane_g10().LayoutLine() ); + iIconSize = layoutRect.Rect().Size(); + iFlags.Set( EUseDefaultIconSize ); + iFlags.Set( EUseDefaultMargins ); + } + +// ----------------------------------------------------------------------------- +// CAknButtonExtension::~CAknButtonExtension +// Destructor. +// ----------------------------------------------------------------------------- +// +CAknButtonExtension::~CAknButtonExtension() + { + delete iLongPressTimer; + iPictographInterface = NULL; // not owned + iFrameAndCenterIds.Close(); + DeletePressedBmps(); + } + +// ----------------------------------------------------------------------------- +// CAknButtonExtension::NewL +// Symbian two-phased constructor. +// ----------------------------------------------------------------------------- +// +CAknButtonExtension* CAknButtonExtension::NewL( CAknButton& aButton ) + { + CAknButtonExtension* ext = new ( ELeave ) CAknButtonExtension( aButton ); + CleanupStack::PushL( ext ); + ext->ConstructL(); + CleanupStack::Pop( ext ); + return ext; + } + +// ----------------------------------------------------------------------------- +// CAknButtonExtension::ConstructL +// Symbian 2nd stage constructor. +// ----------------------------------------------------------------------------- +// +void CAknButtonExtension::ConstructL() + { + // Normal frame and center + iFrameAndCenterIds.AppendL( KAknsIIDQsnFrButtonNormal ); + iFrameAndCenterIds.AppendL( KAknsIIDQsnFrButtonCenterNormal ); + // Latched frame and center + iFrameAndCenterIds.AppendL( KAknsIIDQsnFrButtonPressed ); + iFrameAndCenterIds.AppendL( KAknsIIDQsnFrButtonCenterPressed ); + // Dimmed frame and center + iFrameAndCenterIds.AppendL( KAknsIIDQsnFrButtonInactive ); + iFrameAndCenterIds.AppendL( KAknsIIDQsnFrButtonCenterInactive ); + // Pressed frame and center + iFrameAndCenterIds.AppendL( KAknsIIDQsnFrButtonPressed ); + iFrameAndCenterIds.AppendL( KAknsIIDQsnFrButtonCenterPressed ); + // Latched dimmed frame and center + iFrameAndCenterIds.AppendL( KAknsIIDQsnFrButtonInactive ); + iFrameAndCenterIds.AppendL( KAknsIIDQsnFrButtonCenterInactive ); + } + +// ----------------------------------------------------------------------------- +// CAknButtonExtension::StartLongPressTimerL +// Starts the long press timer. The timer is constructed when used for the +// first time. +// ----------------------------------------------------------------------------- +// +void CAknButtonExtension::StartLongPressTimerL() + { + if ( !iLongPressTimer ) + { + iLongPressTimer = CPeriodic::NewL( CActive::EPriorityStandard ); + } + else if ( iLongPressTimer->IsActive() ) + { + iLongPressTimer->Cancel(); + } + + if ( iLongPressInterval > 0 ) + { + iLongPressTimer->Start( iLongPressInterval, iLongPressInterval, + TCallBack( ReportLongPressL, this ) ); + } + } + +// ----------------------------------------------------------------------------- +// CAknButtonExtension::ReportLongPressL +// ----------------------------------------------------------------------------- +// +TInt CAknButtonExtension::ReportLongPressL( TAny* aThis ) + { + static_cast( aThis )->DoReportLongPressL(); + return 0; + } + +// ----------------------------------------------------------------------------- +// CAknButtonExtension::DoReportLongPressL +// ----------------------------------------------------------------------------- +// +void CAknButtonExtension::DoReportLongPressL() + { + if ( iLongPressTimer && iLongPressTimer->IsActive() ) + { + iLongPressTimer->Cancel(); + } + + if ( iButton.Observer() ) + { + iButton.Observer()->HandleControlEventL( &iButton, + static_cast( + CAknButton::ELongPressEvent ) ); + + iFlags.Set( ELongPressReported ); + } + } + + +// ----------------------------------------------------------------------------- +// CAknButtonExtension::DeletePressedBmps +// Deletes pressed down bitmaps +// ----------------------------------------------------------------------------- +// +void CAknButtonExtension::DeletePressedBmps() + { + delete iPressedDownBmp; + delete iPressedDownBmpMask; + iPressedDownBmp = 0; + iPressedDownBmpMask = 0; + } + + +// ----------------------------------------------------------------------------- +// CAknButtonExtension::FetchProviderPressedBmpsL +// Fetches bitmaps from provider (if one exists). Returns ETrue if bitmaps were +// found. +// ----------------------------------------------------------------------------- +// +TBool CAknButtonExtension::FetchProviderPressedBmpsL() + { + TBool bmpsFetched = EFalse; + if ( iResourceProvider ) + { + MAknResourceItem* resourceItem = 0; + + // Check if resource provider has item for KPressedFrameId + if ( iResourceProvider->GetResourceL( + KPressedFrameId, resourceItem ) != KErrNotFound + && resourceItem ) + { + DeletePressedBmps(); + static_cast( resourceItem )->GetBitmaps( + iPressedDownBmp, iPressedDownBmpMask ); + delete resourceItem; + + // Check if found bitmap size matches with button size + if ( iPressedDownBmp + && iPressedDownBmpMask + && iPressedDownBmp->SizeInPixels() == iButton.Size() ) + { + bmpsFetched = ETrue; + } + // If not, delete the fetched bitmaps + else + { + DeletePressedBmps(); + } + } + } + return bmpsFetched; + } + + +// ----------------------------------------------------------------------------- +// CAknButtonExtension::SetProviderPressedBmpsL +// Sets bitmaps to provider (if one exists). +// ----------------------------------------------------------------------------- +// +void CAknButtonExtension::SetProviderPressedBmpsL() + { + if ( iResourceProvider ) + { + CAknBitmapResourceItem* resourceItem = + CAknBitmapResourceItem::NewL( KPressedFrameId ); + resourceItem->SetBitmapsL( iPressedDownBmp, iPressedDownBmpMask ); + iResourceProvider->SetResourceL( + KPressedFrameId, + static_cast( resourceItem ) ); + } + } + + + +// +TBool CAknButtonExtension::HitRegionContains( const TPoint &aPoint, + const CCoeControl& /*aControl*/ ) const + { + TBool retval = EFalse; + + TRAP_IGNORE( retval = iButton.HitAreaContainsL( aPoint, iFlags.IsSet( ECheckHitArea ) ) ); + + return retval; + } + +void CAknButtonExtension::HandleFeedbackAreaChange() + { + // it is possible that feedback does not exist, eg. while booting. + // try getting one, and give up if that fails. + if ( !iFeedback ) + { + iFeedback = MTouchFeedback::Instance(); + } + if ( !iFeedback ) + { + return; + } + + if ( iButton.ButtonFlags() & KAknButtonHitTest ) + { + // no registry feedback if shaped buttons are used + iFeedback->RemoveFeedbackArea( &iButton, 0 ); + } + else + { + CFeedbackSpec* spec = CFeedbackSpec::New(); + if (spec) + { + spec->AddFeedback( ETouchEventStylusDown, + ETouchFeedbackBasicButton ); + spec->AddFeedback( ETouchEventStylusUp, + ETouchFeedbackBasicButton, + ETouchFeedbackVibra ); + iFeedback->SetFeedbackArea( &iButton, 0, iButton.Rect(), spec ); + delete spec; + } + } + } + +// ============================ EXTENSION CLASS ================================ + +NONSHARABLE_CLASS( CAknButtonStateExtension ) : public CBase + { + friend class CAknButtonState; + +public: + static CAknButtonStateExtension* NewL(); + ~CAknButtonStateExtension(); + + void ConfigureExtensionFromResourceL( const TInt aResourceId ); + void ConfigureExtensionFromResourceL( TResourceReader& aReader ); + +private: + CAknButtonStateExtension(); + void ConstructL(); + +private: // Data + TBool iGeneratedDimmedIcon; + HBufC* iFilePath; + TInt iBmpId; + TInt iMaskId; + TInt iDimmedBmpId; + TInt iDimmedMaskId; + TInt iPressedBmpId; + TInt iPressedMaskId; + TInt iHoverBmpId; + TInt iHoverMaskId; + TAknsItemID iId; + TAknsItemID iDimmedId; + TAknsItemID iPressedId; + TAknsItemID iHoverId; + TScaleMode iScaleMode; + }; + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CAknButtonStateExtension::CAknButtonStateExtension +// C++ default constructor. +// ----------------------------------------------------------------------------- +// +CAknButtonStateExtension::CAknButtonStateExtension() + : iGeneratedDimmedIcon ( EFalse ), iBmpId( -1 ), iMaskId( -1 ), + iDimmedBmpId( -1 ), iDimmedMaskId( -1 ), iPressedBmpId( -1 ), + iPressedMaskId( -1 ), iHoverBmpId( -1 ), iHoverMaskId( -1 ), + iId( KAknsIIDNone ), iDimmedId( KAknsIIDNone ), + iPressedId( KAknsIIDNone ), iHoverId( KAknsIIDNone ), + iScaleMode( EAspectRatioNotPreserved ) + { + } + +// ----------------------------------------------------------------------------- +// CAknButtonStateExtension::~CAknButtonStateExtension +// Destructor. +// ----------------------------------------------------------------------------- +// +CAknButtonStateExtension::~CAknButtonStateExtension() + { + delete iFilePath; + } + +// ----------------------------------------------------------------------------- +// CAknButtonStateExtension::NewL +// Symbian two-phased constructor. +// ----------------------------------------------------------------------------- +// +CAknButtonStateExtension* CAknButtonStateExtension::NewL() + { + CAknButtonStateExtension* ext = new ( ELeave ) CAknButtonStateExtension; + CleanupStack::PushL( ext ); + ext->ConstructL(); + CleanupStack::Pop( ext ); + return ext; + } + +// ----------------------------------------------------------------------------- +// CAknButtonStateExtension::ConstructL +// Symbian 2nd stage constructor. +// ----------------------------------------------------------------------------- +// +void CAknButtonStateExtension::ConstructL() + { + } //lint !e1762 function cannot be made const + +// ----------------------------------------------------------------------------- +// CAknButtonStateExtension::ConfigureExtensionFromResourceL +// ----------------------------------------------------------------------------- +// +void CAknButtonStateExtension::ConfigureExtensionFromResourceL( + const TInt aResourceId ) + { + + if ( aResourceId ) + { + TResourceReader reader; + CCoeEnv::Static()->CreateResourceReaderLC( reader, aResourceId ); + ConfigureExtensionFromResourceL( reader ); + CleanupStack::PopAndDestroy(); + } + } + +// ----------------------------------------------------------------------------- +// CAknButtonStateExtension::ConfigureExtensionFromResourceL +// ----------------------------------------------------------------------------- +// +void CAknButtonStateExtension::ConfigureExtensionFromResourceL( + TResourceReader& aReader ) + { + TInt version = aReader.ReadInt8(); + + // bmp ids + TInt major = aReader.ReadInt32(); + TInt minor = aReader.ReadInt32(); + + if ( major != 0 && minor != 0 ) + { + iId.Set( major, minor ); + } + + // dimmed ids + major = aReader.ReadInt32(); + minor = aReader.ReadInt32(); + + if ( major != 0 && minor != 0 ) + { + iDimmedId.Set( major, minor ); + } + + // pressed ids + major = aReader.ReadInt32(); + minor = aReader.ReadInt32(); + + if ( major != 0 && minor != 0 ) + { + iPressedId.Set( major, minor ); + } + + // hover ids + major = aReader.ReadInt32(); + minor = aReader.ReadInt32(); + + if ( major != 0 && minor != 0 ) + { + iHoverId.Set( major, minor ); + } + } + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CAknButtonState::CAknButtonState +// Constructor +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButtonState::CAknButtonState( const TInt aFlags ) : + iFlags( aFlags ) + { + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::~CAknButtonState +// Destructor +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButtonState::~CAknButtonState() + { + delete iIcon; + delete iDimmedIcon; + delete iPressedIcon; + delete iHoverIcon; + delete iText; + delete iHelpText; + delete iExtension; + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::ConstructFromResourceL +// Constructs the button state from the resources +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButtonState::ConstructFromResourceL( TResourceReader& aReader ) + { + if ( !iExtension ) + { + iExtension = CAknButtonStateExtension::NewL(); + } + + // flags + iFlags = aReader.ReadInt16(); + + // txt + TPtrC txt = aReader.ReadTPtrC(); + SetTextL( txt ); + + // helptxt + TPtrC helpTxt = aReader.ReadTPtrC(); + SetHelpTextL( helpTxt ); + + if ( iExtension->iFilePath ) + { + delete iExtension->iFilePath; + iExtension->iFilePath = NULL; + } + + // bmpfile + iExtension->iFilePath = aReader.ReadTPtrC().AllocL(); + + // bmpid & bmpmask + iExtension->iBmpId = aReader.ReadInt16(); + iExtension->iMaskId = aReader.ReadInt16(); + + // dim_bmpid & dim_bmpmask + iExtension->iDimmedBmpId = aReader.ReadInt16(); + iExtension->iDimmedMaskId = aReader.ReadInt16(); + + // press_bmpid & press_bmpmask + iExtension->iPressedBmpId = aReader.ReadInt16(); + iExtension->iPressedMaskId = aReader.ReadInt16(); + + // hover_bmpid & hover_bmpmask + iExtension->iHoverBmpId = aReader.ReadInt16(); + iExtension->iHoverMaskId = aReader.ReadInt16(); + + // extension + TInt extensionLink = aReader.ReadInt32(); + + if ( extensionLink != 0 ) + { + iExtension->ConfigureExtensionFromResourceL( extensionLink ); + } + + LoadButtonIcon( iIcon ); + LoadButtonIcon( iDimmedIcon ); + LoadButtonIcon( iPressedIcon ); + LoadButtonIcon( iHoverIcon ); + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::ConstructL +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButtonState::ConstructL( CGulIcon* aIcon, + CGulIcon* aDimmedIcon, + CGulIcon* aPressedIcon, + CGulIcon* aHoverIcon, + const TDesC& aText, + const TDesC& aHelpText ) + { + if ( !iExtension ) + { + iExtension = CAknButtonStateExtension::NewL(); + } + + SetIcon( aIcon ); + SetDimmedIcon( aDimmedIcon ); + SetPressedIcon( aPressedIcon ); + SetHoverIcon( aHoverIcon ); + SetTextL( aText ); + SetHelpTextL( aHelpText ); + } + +// ----------------------------------------------------------------------------- +// CAknButtonState:: +// Symbian 2nd phase constructor. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButtonState::ConstructL( const TDesC& aFilePath, + const TInt aBmpId, + const TInt aMaskId, + const TInt aDimmedBmpId, + const TInt aDimmedMaskId, + const TInt aPressedBmpId, + const TInt aPressedMaskId, + const TInt aHoverBmpId, + const TInt aHoverMaskId, + const TDesC& aText, + const TDesC& aHelpText, + const TAknsItemID& aId, + const TAknsItemID& aDimmedId, + const TAknsItemID& aPressedId, + const TAknsItemID& aHoverId ) + { + UpdateIconL( aFilePath, aBmpId, aMaskId, aDimmedBmpId, aDimmedMaskId, + aPressedBmpId, aPressedMaskId, aHoverBmpId, aHoverMaskId, aId, aDimmedId, + aPressedId, aHoverId ); + + SetTextL( aText ); + SetHelpTextL( aHelpText ); + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::Icon +// Returns the icon for the normal state. +// ----------------------------------------------------------------------------- +// +EXPORT_C const CGulIcon* CAknButtonState::Icon() const + { + return iIcon; + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::DimmedIcon +// Returns the icon for the dimmed state +// ----------------------------------------------------------------------------- +// +EXPORT_C const CGulIcon* CAknButtonState::DimmedIcon() const + { + return iDimmedIcon; + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::PressedIcon +// Returns the icon for the pressed but not released state. +// ----------------------------------------------------------------------------- +// +EXPORT_C const CGulIcon* CAknButtonState::PressedIcon() const + { + return iPressedIcon; + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::HoverIcon +// Returns the icon for the hover state. +// ----------------------------------------------------------------------------- +// +EXPORT_C const CGulIcon* CAknButtonState::HoverIcon() const + { + return iHoverIcon; + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::Text +// Returns the text inside the button. +// ----------------------------------------------------------------------------- +// +EXPORT_C const TDesC& CAknButtonState::Text() const + { + if ( iText ) + { + return *iText; + } + else + { + return KNullDesC(); + } + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::HelpText +// Returns the text inside the help note. +// ----------------------------------------------------------------------------- +// +EXPORT_C const TDesC& CAknButtonState::HelpText() const + { + if ( iHelpText ) + { + return *iHelpText; + } + else + { + return KNullDesC(); + } + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::Flags +// Returns the state flags. +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt CAknButtonState::Flags() const + { + return iFlags; + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::SetIcon +// Sets the icon for the normal state. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButtonState::SetIcon( CGulIcon* aIcon ) + { + ReplaceIcon( iIcon, aIcon ); + + if ( iExtension->iGeneratedDimmedIcon ) + { + TRAP_IGNORE( CreateAndSetDimmedIconL( iDimmedIcon, iIcon, + iExtension->iScaleMode ) ); + } + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::SetDimmedIcon +// Sets the icon for the dimmed state. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButtonState::SetDimmedIcon( CGulIcon* aDimmedIcon ) + { + ReplaceIcon( iDimmedIcon, aDimmedIcon ); + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::SetPressedIcon +// Sets the icon for the pressed but not released state. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButtonState::SetPressedIcon( CGulIcon* aPressedIcon ) + { + ReplaceIcon( iPressedIcon, aPressedIcon ); + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::SetHoverIcon +// Sets the icon for the hover state. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButtonState::SetHoverIcon( CGulIcon* aHoverIcon ) + { + ReplaceIcon( iHoverIcon, aHoverIcon ); + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::ReplaceIcon +// Replaces the given icon with a new one. If the original icon had its size set +// then the new icon is scaled to that size. +// ----------------------------------------------------------------------------- +// +void CAknButtonState::ReplaceIcon( CGulIcon*& aIcon, CGulIcon* aNewIcon ) + { + ReplaceIconStatic( aIcon, aNewIcon, iExtension->iScaleMode ); + } + + +// ----------------------------------------------------------------------------- +// CAknButtonState::SetTextL +// Sets the text inside the button +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButtonState::SetTextL( const TDesC& aText ) + { + delete iText; + iText = NULL; + + iText = aText.AllocL(); + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::SetHelpTextL +// Sets the text inside the help note +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButtonState::SetHelpTextL( const TDesC& aHelpText ) + { + delete iHelpText; + iHelpText = NULL; + + iHelpText = aHelpText.AllocL(); + } + +// ----------------------------------------------------------------------------- +// CAknButtonState:: +// Sets state flags. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButtonState::SetFlags( const TInt aFlags ) + { + iFlags = aFlags; + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::UpdateIconL +// Updates button icons. +// ----------------------------------------------------------------------------- +void CAknButtonState::UpdateIconL( const TDesC& aFilePath, + const TInt aBmpId, + const TInt aMaskId, + const TInt aDimmedBmpId, + const TInt aDimmedMaskId, + const TInt aPressedBmpId, + const TInt aPressedMaskId, + const TInt aHoverBmpId, + const TInt aHoverMaskId, + const TAknsItemID& aId, + const TAknsItemID& aDimmedId, + const TAknsItemID& aPressedId, + const TAknsItemID& aHoverId ) + + { + if ( !iExtension ) + { + iExtension = CAknButtonStateExtension::NewL(); + } + + if ( iExtension->iFilePath ) + { + delete iExtension->iFilePath; + iExtension->iFilePath = NULL; + } + + // try to save some ram by defaulting to avkon bitmap file + if ( aFilePath != KAvkonBitmapFile ) + { + iExtension->iFilePath = aFilePath.AllocL(); + } + + iExtension->iBmpId = aBmpId; + iExtension->iMaskId = aMaskId; + iExtension->iDimmedBmpId = aDimmedBmpId; + iExtension->iDimmedMaskId = aDimmedMaskId; + iExtension->iPressedBmpId = aPressedBmpId; + iExtension->iPressedMaskId = aPressedMaskId; + iExtension->iHoverBmpId = aHoverBmpId; + iExtension->iHoverMaskId = aHoverMaskId; + iExtension->iId = aId; + iExtension->iDimmedId = aDimmedId; + iExtension->iPressedId = aPressedId; + iExtension->iHoverId = aHoverId; + + LoadButtonIcon( iIcon ); + LoadButtonIcon( iDimmedIcon ); + LoadButtonIcon( iPressedIcon ); + LoadButtonIcon( iHoverIcon ); + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::SizeChanged +// Scales function graphics to the given size +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButtonState::SizeChanged( const TRect& aRect, + TScaleMode aScaleMode ) + { + ScaleIcons( aRect.Size(), aScaleMode ); + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::HasText +// Returns ETrue if the text inside button is not empty or space. +// ----------------------------------------------------------------------------- +// +EXPORT_C TBool CAknButtonState::HasText() const + { + if ( !iText ) + return EFalse; + + TBool ret = EFalse; + for ( TInt i = 0; i < iText->Des().Length(); i++ ) + { + TChar c ( (iText->Des())[i]); + +// TChar::TCategory cat = c.GetCategory(); + if ( !c.IsSpace() /*&& cat != TChar::ECoCategory*/ ) + { + // not space and not private use char + ret = ETrue; + break; + } + } + + return ret; + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::HasHelp +// Returns ETrue if the text inside the help note is not empty or space. +// ----------------------------------------------------------------------------- +// +EXPORT_C TBool CAknButtonState::HasHelp() const + { + if ( !iHelpText ) + return EFalse; + + TBool ret = EFalse; + for ( TInt i = 0; i < iHelpText->Des().Length(); i++ ) + { + TChar c( ( *iHelpText )[i] ); + +// TChar::TCategory cat = c.GetCategory(); + if ( !c.IsSpace() /*&& cat != TChar::ECoCategory*/ ) + { + // not space and not private use char + ret = ETrue; + break; + } + } + + return ret; + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::HandleResourceChange +// Handles changes in state's environment. +// ----------------------------------------------------------------------------- +// +void CAknButtonState::HandleResourceChange( TInt aType ) + { + // Update icons if skin is changed. KEikDynamicLayoutVariantSwitch event is + // handled via SizeChanged. + if ( aType == KAknsMessageSkinChange ) + { + LoadButtonIcon( iIcon ); + LoadButtonIcon( iDimmedIcon ); + LoadButtonIcon( iPressedIcon ); + LoadButtonIcon( iHoverIcon ); + + // generated dimmed state icon has to be regenerated + if ( iExtension->iGeneratedDimmedIcon ) + { + TRAP_IGNORE( CreateAndSetDimmedIconL( iDimmedIcon, iIcon, + iExtension->iScaleMode ) ); + } + } + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::SetIconScaleMode +// Sets default scaling mode. +// ----------------------------------------------------------------------------- +// +void CAknButtonState::SetIconScaleMode( const TScaleMode aScaleMode ) + { + iExtension->iScaleMode = aScaleMode; + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::CreateButtonIconL +// Creates one of the icons +// ----------------------------------------------------------------------------- +// +void CAknButtonState::CreateButtonIconL( CGulIcon*& aIcon, + const TDesC& aFilePath, + TInt aBmpId, + TInt aMaskId, + const TAknsItemID& aId ) const + { + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + + if ( aIcon ) + { + if ( ( aId != KAknsIIDNone && skin ) || aBmpId != -1 ) + { + delete aIcon; + aIcon = NULL; + } + } + + if ( aFilePath == KNullDesC || aBmpId == -1 ) + { + if ( aId != KAknsIIDNone && skin ) + { + aIcon = AknsUtils::CreateGulIconL( skin, aId, EFalse ); + } + } + else + { + if ( aId != KAknsIIDNone && skin ) + { + aIcon = AknsUtils::CreateGulIconL( skin, aId, aFilePath, aBmpId, + aMaskId); + } + else + { + CFbsBitmap* bmp; + CFbsBitmap* mask; + AknIconUtils::CreateIconLC( bmp, mask, aFilePath, aBmpId, aMaskId); + aIcon = CGulIcon::NewL( bmp, mask ); // ownership passed + CleanupStack::Pop( 2 ); + } + } + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::LoadButtonIcon +// Reloads one button icon. +// ----------------------------------------------------------------------------- +// +void CAknButtonState::LoadButtonIcon( CGulIcon*& aIcon ) const + { + TSize iconSize( 0, 0 ); + + if ( aIcon && aIcon->Bitmap() ) + { + iconSize = aIcon->Bitmap()->SizeInPixels(); + } + + TInt bmpId = -1; + TInt maskId = -1; + TAknsItemID skinId = KAknsIIDNone; + + if ( &aIcon == &iIcon ) + { + bmpId = iExtension->iBmpId; + maskId = iExtension->iMaskId; + skinId = iExtension->iId; + } + else if ( &aIcon == &iPressedIcon ) + { + bmpId = iExtension->iPressedBmpId; + maskId = iExtension->iPressedMaskId; + skinId = iExtension->iPressedId; + } + else if ( &aIcon == &iDimmedIcon ) + { + bmpId = iExtension->iDimmedBmpId; + maskId = iExtension->iDimmedMaskId; + skinId = iExtension->iDimmedId; + } + else if ( &aIcon == &iHoverIcon ) + { + bmpId = iExtension->iHoverBmpId; + maskId = iExtension->iHoverMaskId; + skinId = iExtension->iHoverId; + } + + TPtrC16 bitmapFile; + + if ( iExtension->iFilePath ) + { + bitmapFile.Set( *iExtension->iFilePath ); + } + else + { + bitmapFile.Set( KAvkonBitmapFile ); + } + + // aIcon is set to NULL if the next call fails + TRAP_IGNORE( CreateButtonIconL( aIcon, bitmapFile, bmpId, maskId, skinId ) ); + + if ( aIcon && iconSize != TSize( 0, 0 ) ) + { + ResizeIcon( aIcon, iconSize, iExtension->iScaleMode ); + } + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::ScaleIcons +// Sets the size for bitmap and mask +// ----------------------------------------------------------------------------- +// +TInt CAknButtonState::ScaleIcons( const TSize& aSize, TScaleMode aScaleMode ) + { + TInt retval = ResizeIcon( iIcon, aSize, aScaleMode ); + retval = Min( retval, ResizeIcon( iPressedIcon, aSize, aScaleMode ) ); + + // Generated dimmed state icon has to be regenerated + if ( iExtension->iGeneratedDimmedIcon ) + { + TRAP_IGNORE ( CreateAndSetDimmedIconL( iDimmedIcon, iIcon, aScaleMode ) ); + } + else + { + retval = Min( retval, ResizeIcon( iDimmedIcon, aSize, aScaleMode ) ); + } + + return retval; + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::ScaleMode +// Getter for the current scalemode of the state +// ----------------------------------------------------------------------------- +TScaleMode CAknButtonState::ScaleMode() const + { + return iExtension->iScaleMode; + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::SetGeneratedDimmedIcon +// Whether the dimmed icon of the state is created by owning Button +// ----------------------------------------------------------------------------- +void CAknButtonState::SetGeneratedDimmedIcon( TBool aDimmedIconCreatedByButton ) + { + iExtension->iGeneratedDimmedIcon = aDimmedIconCreatedByButton; + } + +// ----------------------------------------------------------------------------- +// CAknButtonState::Extension +// ----------------------------------------------------------------------------- +// +CAknButtonStateExtension* CAknButtonState::Extension() const + { + return iExtension; + } + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CAknButton::NewL +// Two-phased constructor. +// Constructs an empty button +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButton* CAknButton::NewL() + { + CAknButton* self = NewLC(); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CAknButton::NewLC +// Two-phased constructor. +// Constructs an empty button +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButton* CAknButton::NewLC() + { + CAknButton* self = new (ELeave) CAknButton( 0 ); + CleanupStack::PushL( self ); + self->ConstructL(); + AKNTASHOOK_ADDL( self, "CAknButton" ); + return self; + } + +// ----------------------------------------------------------------------------- +// CAknButton::NewL +// Two-phased constructor. +// Constructs the button from resources. +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButton* CAknButton::NewL( TResourceReader& aReader ) + { + CAknButton* self = NewLC( aReader ); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CAknButton::NewLC +// Two-phased constructor. +// Constructs the button from resources. +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButton* CAknButton::NewLC( TResourceReader& aReader ) + { + CAknButton* self = new( ELeave ) CAknButton( 0 ); + CleanupStack::PushL( self ); + self->ConstructL(); + self->ConstructFromResourceL( aReader ); + AKNTASHOOK_ADDL( self, "CAknButton" ); + return self; + } + +// ----------------------------------------------------------------------------- +// CAknButton::NewL +// Two-phased constructor. +// Constructs the button from resources. +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButton* CAknButton::NewL( const TInt aResourceId ) + { + CAknButton* self = NewLC( aResourceId ); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CAknButton::NewLC +// Two-phased constructor. +// Constructs the button from resources. +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButton* CAknButton::NewLC( const TInt aResourceId ) + { + CAknButton* self = new (ELeave) CAknButton( 0 ); + CleanupStack::PushL( self ); + self->ConstructL(); + self->ConstructFromResourceL( aResourceId ); + AKNTASHOOK_ADDL( self, "CAknButton" ); + return self; + } + +// ----------------------------------------------------------------------------- +// CAknButton::NewL +// Two-phased constructor. +// Constructs one state button. +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButton* CAknButton::NewL( CGulIcon* aIcon, + CGulIcon* aDimmedIcon, + CGulIcon* aPressedIcon, + CGulIcon* aHoverIcon, + const TDesC& aText, + const TDesC& aHelpText, + const TInt aButtonFlags, + const TInt aStateFlags ) + { + CAknButton* self = NewLC( aIcon, aDimmedIcon, aPressedIcon, aHoverIcon, + aText, aHelpText, aButtonFlags, aStateFlags ); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CAknButton::NewLC +// Two-phased constructor. +// Constructs one state button. +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButton* CAknButton::NewLC( CGulIcon* aIcon, + CGulIcon* aDimmedIcon, + CGulIcon* aPressedIcon, + CGulIcon* aHoverIcon, + const TDesC& aText, + const TDesC& aHelpText, + const TInt aButtonFlags, + const TInt aStateFlags ) + { + CAknButton* self = new (ELeave) CAknButton( aButtonFlags ); + CleanupStack::PushL( self ); + self->ConstructL( aIcon, aDimmedIcon, aPressedIcon, aHoverIcon, aText, + aHelpText, aStateFlags ); + AKNTASHOOK_ADDL( self, "CAknButton" ); + return self; + } + +// ----------------------------------------------------------------------------- +// CAknButton::NewL +// Two-phased constructor. +// Constructs one state button. +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButton* CAknButton::NewL( const TDesC& aFilePath, + const TInt aBmpId, + const TInt aMaskId, + const TInt aDimmedBmpId, + const TInt aDimmedMaskId, + const TInt aPressedBmpId, + const TInt aPressedMaskId, + const TInt aHoverBmpId, + const TInt aHoverMaskId, + const TDesC& aText, + const TDesC& aHelpText, + const TInt aButtonFlags, + const TInt aStateFlags, + const TAknsItemID& aId, + const TAknsItemID& aDimmedId, + const TAknsItemID& aPressedId, + const TAknsItemID& aHoverId ) + { + CAknButton* self = NewLC( aFilePath, aBmpId, aMaskId, aDimmedBmpId, + aDimmedMaskId, aPressedBmpId, aPressedMaskId, aHoverBmpId, aHoverMaskId, + aText, aHelpText, aButtonFlags, aStateFlags, aId, aDimmedId, aPressedId, + aHoverId ); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CAknButton::NewLC +// Two-phased constructor. +// Constructs one state button. +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButton* CAknButton::NewLC( const TDesC& aFilePath, + const TInt aBmpId, + const TInt aMaskId, + const TInt aDimmedBmpId, + const TInt aDimmedMaskId, + const TInt aPressedBmpId, + const TInt aPressedMaskId, + const TInt aHoverBmpId, + const TInt aHoverMaskId, + const TDesC& aText, + const TDesC& aHelpText, + const TInt aButtonFlags, + const TInt aStateFlags, + const TAknsItemID& aId, + const TAknsItemID& aDimmedId, + const TAknsItemID& aPressedId, + const TAknsItemID& aHoverId ) + { + CAknButton* self = new (ELeave) CAknButton( aButtonFlags ); + CleanupStack::PushL( self ); + self->ConstructL( aFilePath, aBmpId, aMaskId, aDimmedBmpId, aDimmedMaskId, + aPressedBmpId, aPressedMaskId, aHoverBmpId, aHoverMaskId, + aText, aHelpText, aStateFlags, aId, aDimmedId, aPressedId, aHoverId ); + AKNTASHOOK_ADDL( self, "CAknButton" ); + return self; + } + +// ----------------------------------------------------------------------------- +// CAknButton::CAknButton +// C++ constructor. +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButton::CAknButton( const TInt aFlags ) + : iFlags( aFlags ), + iVerticalAlignment( ECenter ), + iHorizontalAlignment( CGraphicsContext::ECenter ), + iTextColorTableId( KAknsIIDQsnTextColors ), // TODO + iTextColorIndex( EAknsCIQsnTextColorsCG80 ), // TODO + iScaleMode( EAspectRatioNotPreserved ), + iHelpNoteWaitInterval( KTimeoutBeforeHelpNote ), + iHelpNoteInViewInterval( KTimeoutInViewHelpNote ), + iKeyRepeatDelay( KKeyRepeatDelay ), + iKeyRepeatInterval( KKeyRepeatInterval ) + { + } + +// ----------------------------------------------------------------------------- +// CAknButton::ConstructL +// Symbian 2nd phase constructor. +// Constructor for the empty button. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::ConstructL() + { + TRgb textColor; + + if ( AknsUtils::GetCachedColor( AknsUtils::SkinInstance(), textColor, + iTextColorTableId, iTextColorIndex ) == KErrNone ) + { + OverrideColorL( EColorButtonText, textColor ); + } + + if ( !iStates ) + { + iStates = new ( ELeave ) CArrayPtrFlat( 2 ); + } + + if ( !iBgContext ) + { + iBgContext = CAknsFrameBackgroundControlContext::NewL( + KAknsIIDNone, TRect(), TRect(), EFalse ); + } + + if ( !iExtension ) + { + iExtension = CAknButtonExtension::NewL( *this ); + } + + if ( iFlags & KAknButtonHitTest ) + { + SetHitTest( iExtension ); + } + + if ( iFlags & KAknButtonNoFrame ) + { + iExtension->iMargins.SetAllValuesTo( 0 ); + } + + if ( iFlags & KAknButtonTextLeft ) + { + iHorizontalAlignment = CGraphicsContext::ELeft; + } + iExtension->HandleFeedbackAreaChange(); + } + +// ----------------------------------------------------------------------------- +// CAknButton::ConstructL +// Symbian 2nd phase constructor for 1 state button. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::ConstructL( CGulIcon* aIcon, + CGulIcon* aDimmedIcon, + CGulIcon* aPressedIcon, + CGulIcon* aHoverIcon, + const TDesC& aText, + const TDesC& aHelpText, + const TInt aStateFlags ) + { + ConstructL(); + AddStateL( aIcon, aDimmedIcon, aPressedIcon, aHoverIcon, aText, aHelpText, + aStateFlags); + } + +// ----------------------------------------------------------------------------- +// CAknButton::ConstructL +// Symbian 2nd phase constructor for 1 state button +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::ConstructL( const TDesC& aFilePath, + const TInt aBmpId, + const TInt aMaskId, + const TInt aDimmedBmpId, + const TInt aDimmedMaskId, + const TInt aPressedBmpId, + const TInt aPressedMaskId, + const TInt aHoverBmpId, + const TInt aHoverMaskId, + const TDesC& aText, + const TDesC& aHelpText, + const TInt aStateFlags, + const TAknsItemID& aId, + const TAknsItemID& aDimmedId, + const TAknsItemID& aPressedId, + const TAknsItemID& aHoverId ) + { + ConstructL(); + AddStateL( aFilePath, aBmpId, aMaskId, aDimmedBmpId, aDimmedMaskId, + aPressedBmpId, aPressedMaskId, aHoverBmpId, aHoverMaskId, + aText, aHelpText, aStateFlags, aId, aDimmedId, aPressedId, aHoverId ); + } + +// ----------------------------------------------------------------------------- +// Destructor +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButton::~CAknButton() + { + AKNTASHOOK_REMOVE(); + if ( iStates ) + { + iStates->ResetAndDestroy(); + delete iStates; + } + + // MTouchFeedback instance lives in AknAppUi. AppUi might be + // destroyed when this destructor is running. If there is no + // MTouchFeedback instance there is no need to remove any areas + // either, as these are ( naturally ) destroyed with + // MTouchFeedback instance. + MTouchFeedback* fb = MTouchFeedback::Instance(); + if ( fb ) + { + fb->RemoveFeedbackForControl( this ); + } + + delete iBgContext; + delete iDimmedHelpText; + delete iHelpNote; + delete iKeyRepeatTimer; + delete iExtension; + iFont = NULL; + } + +// ----------------------------------------------------------------------------- +// CAknButton::ActivateL +// Sets control as ready to be drawn. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::ActivateL() + { + // request for drag events outside the button + SetAllowStrayPointers(); + // Requesting pointer drag events + EnableDragEvents(); + + CAknControl::ActivateL(); + } + +// ----------------------------------------------------------------------------- +// CAknButton::ConstructFromResourceL +// Constructs controls from a resource file. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::ConstructFromResourceL( TResourceReader& aReader ) + { + if ( !iExtension ) + { + iExtension = CAknButtonExtension::NewL( *this ); + } + + // flags + iFlags = aReader.ReadInt16(); + + // state index + SetStateIndexL( aReader.ReadInt16() ); + + // read states + const TInt stateCount = aReader.ReadInt16(); + for ( TInt ii = 0; ii < stateCount; ii++ ) + { + CAknButtonState* state = new (ELeave) CAknButtonState( 0 ); + CleanupStack::PushL( state ); + state->ConstructFromResourceL( aReader ); + iStates->AppendL( state ); + CleanupStack::Pop( state ); + } + + aReader.ReadInt32(); // extension link, not used currently + + if ( iFlags & KAknButtonHitTest ) + { + SetHitTest( iExtension ); + } + + if ( iFlags & KAknButtonNoFrame ) + { + iExtension->iMargins.SetAllValuesTo( 0 ); + } + + if ( iFlags & KAknButtonTextLeft ) + { + iHorizontalAlignment = CGraphicsContext::ELeft; + } + iExtension->HandleFeedbackAreaChange(); + } + +// ----------------------------------------------------------------------------- +// CAknButton::HandleResourceChange +// Handles a change to the control's resources. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::HandleResourceChange( TInt aType ) + { + // No need to call base class implementation since CountComponentControls + // is always zero. + + if ( aType == KAknsMessageSkinChange || aType == KEikDynamicLayoutVariantSwitch ) + { + if ( iButtonPressed ) + { + ResetState(); + DrawDeferred(); + } + } + + // UIFW informs control about lost focus when moved to background. + // Rest of pointer events are no longer forvarded to control. + if ( aType == KAknMessageFocusLost || aType == KEikMessageFadeAllWindows ) + { + if (iHelpNote) + { + iHelpNote->HideInfoPopupNote(); + } + + if (iButtonPressed) + { + ResetState(); + DrawDeferred(); + } + return; + } + + if ( iStates ) + { + for ( TInt i = 0; i < iStates->Count(); ++i ) + { + CAknButtonState* state = iStates->At( i ); + + if ( state ) + { + state->HandleResourceChange( aType ); + } + } + } + + if ( aType == KAknsMessageSkinChange ) + { + TRgb textColor; + + if ( AknsUtils::GetCachedColor( AknsUtils::SkinInstance(), textColor, + iTextColorTableId, iTextColorIndex ) == KErrNone ) + { + TRAP_IGNORE( OverrideColorL( EColorButtonText, textColor ) ); + } + + // generated pressed frame has to be regenerated + if ( iFlags & KAknButtonNoFrame && iFlags & KAknButtonPressedDownFrame ) + { + iExtension->DeletePressedBmps(); + TRAP_IGNORE( CreatePressedDownFrameL() ); + } + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::MinimumSize +// Returns the control's minimum required size. This doesn't include highlight +// area. +// ----------------------------------------------------------------------------- +// +EXPORT_C TSize CAknButton::MinimumSize() + { + // by default, margins decide the absolute minimum size... + TInt width = iExtension->iMargins.iLeft + iExtension->iMargins.iRight; + TInt height = iExtension->iMargins.iTop + iExtension->iMargins.iBottom; + + // ...but possible frames may enlarge the required area... + if ( !( iFlags & KAknButtonNoFrame ) ) + { + TAknLayoutRect tl; + tl.LayoutRect( Rect(), + AknLayoutScalable_Avkon::toolbar_button_pane_g2().LayoutLine() ); + + TAknLayoutRect br; + br.LayoutRect( Rect(), + AknLayoutScalable_Avkon::toolbar_button_pane_g5().LayoutLine() ); + + TInt frameWidth = tl.Rect().Width() + br.Rect().Width(); + TInt frameHeight = tl.Rect().Height() + br.Rect().Height(); + + if ( !( iFlags & KAknButtonTextInsideFrame ) ) + { + width = Max( width, frameWidth ); + height = Max( height, frameHeight ); + } + else + { + width = frameWidth; + height = frameHeight; + } + } + + // ...as well as evil flags + if ( iStates && ( iFlags & KAknButtonSizeFitText ) ) + { + if ( !iFont ) + { + iFont = iCoeEnv->NormalFont(); + } + + height += iFont->FontMaxHeight(); + + TInt textWidth = 0; + + // choose the longest one + for ( TInt ii = 0; ii < iStates->Count(); ii++ ) + { + CAknButtonState* state = iStates->At( ii ); + if ( state && state->HasText() ) + { + TInt tempWidth = iFont->TextWidthInPixels( state->Text() ); + textWidth = Max( textWidth, tempWidth ); + } + } + + width += textWidth; + } + + return TSize( width, height ); + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetDimmed +// Sets button dimmed. Doesn't redraw. +// Button needs to get pointer events even if it is dimmed to be able to show +// help text in dimmed state. So, the CCoeControl::SetDimmed(TBool) cannot be +// used to set button dimmed if the help text is used. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetDimmed( TBool aDimmed ) + { + if ( aDimmed ) + { + StopKeyRepeatTimer(); + StopLongPressTimer(); + HideHelp(); + iButtonPressed = EFalse; + } + + if ( aDimmed ) + { + iExtension->iFlags.Set( CAknButtonExtension::EDimmed ); + } + else + { + iExtension->iFlags.Clear( CAknButtonExtension::EDimmed ); + } + if ( iExtension->iFeedback ) + { + if ( aDimmed ) + { + iExtension->iFeedback->MoveFeedbackAreaToFirstPriority( this, 0 ); + } + iExtension->iFeedback->EnableFeedbackForControl( this, !aDimmed && IsVisible() ); + } + + TBool hasHelp ( EFalse ); + + for ( TInt i = 0; i < iStates->Count(); ++i ) + { + CAknButtonState* state = iStates->At( i ); + + if ( state ) + { + if ( !state->iDimmedIcon ) + { + TRAP_IGNORE ( CreateAndSetDimmedIconL( state->iDimmedIcon, + state->iIcon, state->ScaleMode() ) ); + state->SetGeneratedDimmedIcon( ETrue ); + } + + if ( state->HasHelp() ) + { + hasHelp = ETrue; + } + } + } + // None of states has help text, CCoeControl::SetDimmed can be used + if ( !hasHelp ) + { + CCoeControl::SetDimmed( aDimmed ); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::OfferKeyEventL +// Handles key events. +// ----------------------------------------------------------------------------- +// +EXPORT_C TKeyResponse CAknButton::OfferKeyEventL( const TKeyEvent& aKeyEvent, + TEventCode aType ) + { + if ( IsDimmed() ) + return EKeyWasNotConsumed; + + if ( aType == EEventKeyDown && IsVisible() ) + { + HideHelp(); // hides help text as soon as the first key event comes. + } + + if ( aKeyEvent.iScanCode == EStdKeyDevice3 || + aKeyEvent.iScanCode == EStdKeyEnter ) + { + if ( aType == EEventKeyDown ) + { + iKeyDownReported = ETrue; + + if ( !iButtonPressed ) + { + // show press changes + iButtonPressed = ETrue; + if ( NeedsRedrawWhenPressed() ) + { + DrawNow(); + } + } + + if ( iFlags & KAknButtonReportOnKeyDown ) + { + ChangeState( ETrue ); + if ( Observer() ) + { + Observer()->HandleControlEventL( this, + MCoeControlObserver::EEventStateChanged ); + } + } + + if ( iFlags & KAknButtonKeyRepeat ) + { + iExtension->iFlags.Clear( CAknButtonExtension::EKeyRepeatEventReported ); + StartKeyRepeatTimerL(); + } + + if ( iFlags & KAknButtonReportOnLongPress ) + { + iExtension->iFlags.Clear( CAknButtonExtension::ELongPressReported ); + iExtension->StartLongPressTimerL(); + } + } + + else if ( aType == EEventKeyUp ) + { + if ( iButtonPressed ) + { + iButtonPressed = EFalse; + + if ( NeedsRedrawWhenPressed() ) + { + DrawNow(); + } + } + + StopKeyRepeatTimer(); + StopLongPressTimer(); + + // The state is not changed, if it is already changed on key + // down event, or if a long press or a key repeat event is + // already reported to the observer. + if ( !( iFlags & KAknButtonReportOnKeyDown ) && + !( iExtension->iFlags.IsSet( CAknButtonExtension::ELongPressReported ) ) && + !( iExtension->iFlags.IsSet( CAknButtonExtension::EKeyRepeatEventReported ) ) && + iKeyDownReported ) + { + ChangeState( ETrue ); + if ( Observer() ) + { + Observer()->HandleControlEventL( this, + MCoeControlObserver::EEventStateChanged ); + } + } + else + { + if ( iExtension->iFlags.IsSet( CAknButtonExtension::ELongPressReported ) && iKeyDownReported ) + { + Observer()->HandleControlEventL( this, + static_cast( + CAknButton::ELongPressEndedEvent ) ); + } + iExtension->iFlags.Clear( CAknButtonExtension::ELongPressReported ); + iExtension->iFlags.Clear( CAknButtonExtension::EKeyRepeatEventReported ); + } + + if ( iKeyDownReported && RequestExit() && Observer() ) + { + Observer()->HandleControlEventL( this, + MCoeControlObserver::EEventRequestExit ); + } + + iKeyDownReported = EFalse; + } + // we don't want aKeyEvent to go somewhere else :) + return EKeyWasConsumed; + } + + return EKeyWasNotConsumed; + } + +// ----------------------------------------------------------------------------- +// CAknButton::MakeVisible +// Sets this control as visible or invisible. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::MakeVisible( TBool aVisible ) + { + if ( aVisible != IsVisible() ) + { + CAknControl::MakeVisible( aVisible ); + if ( iExtension->iFeedback ) + { + if ( aVisible ) + { + iExtension->iFeedback->MoveFeedbackAreaToFirstPriority( this, + 0 ); + } + iExtension->iFeedback->EnableFeedbackForControl( + this, + aVisible && !IsDimmed() ); + } + + CAknButtonState* state = State(); + if ( !aVisible && state && state->HasHelp() ) + { + HideHelp(); + } + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::PrepareForFocusLossL +// This function is called by the dialog framework immediately before it removes +// keyboard focus from a control within a dialog. +// Currently has empty implementation. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::PrepareForFocusLossL() + { + CAknControl::PrepareForFocusLossL(); // empty but it can be changed... :) + } + +// ----------------------------------------------------------------------------- +// CAknButton::PrepareForFocusGainL +// Prepares the control for gaining focus. +// Must be used before calling SetFocus() function in case when help note +// should be shown. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::PrepareForFocusGainL() + { + CAknControl::PrepareForFocusGainL(); // empty but it can be changed... :) + + CAknButtonState* state = State(); + if ( state && state->HasHelp() && IsVisible() && !IsFocused() ) + { + iShowHelp = ETrue; + } + else + { + iShowHelp = EFalse; + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::SizeChanged +// Responds to size changes to sets the size and position of the contents of +// this control. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SizeChanged() + { + // If default icon size from LAF is used re-request that, otherwise trust + // that size will be updated by the utilising application. + if ( iExtension->iFlags.IsSet( CAknButtonExtension::EUseDefaultIconSize ) ) + { + if ( iFlags & KAknButtonNoFrame && !State()->HasText() ) + { + iExtension->iIconSize = Size(); + } + else + { + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( Rect(), + AknLayoutScalable_Avkon::toolbar_button_pane_g10().LayoutLine() ); + iExtension->iIconSize = layoutRect.Rect().Size(); + } + } + + // Update margins from LAF if default values are used. This also refreshes + // icon size in case it overlaps margins. + CalculateDefaultMargins(); + + // scale all icons + ScaleIcons(); + + // Pressed down frame has to be regenerated + if ( iFlags & KAknButtonNoFrame && iFlags & KAknButtonPressedDownFrame ) + { + TRAP_IGNORE( CreatePressedDownFrameL() ); + } + + iExtension->HandleFeedbackAreaChange(); + } + +// ----------------------------------------------------------------------------- +// CAknButton::HandlePointerEventL +// Handles pointer events. +// @param aPointerEvent is the pointer event. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::HandlePointerEventL( const TPointerEvent& aPointerEvent ) + { + if ( AknLayoutUtils::PenEnabled() ) + { + if ( !IsVisible() ) + { + if ( iButtonPressed ) + { + ResetState(); + } + return; + } + TBool buttonEvent( TouchArea().Contains( aPointerEvent.iPosition ) ); + CAknButtonState* state = State(); + if ( !state ) + { + return; + } + + if ( ( iFlags & KAknButtonHitTest ) && + !HitAreaContainsL( aPointerEvent.iPosition, EFalse ) ) + { + buttonEvent = EFalse; + } + + TBool redrawNeeded(EFalse); + switch ( aPointerEvent.iType ) + { + case TPointerEvent::EButton1Down: + { + if ( buttonEvent && IsDimmed() ) + { + ShowHelpL(); + } + else if ( buttonEvent ) + { + if ( !iButtonPressed ) + { + iButtonPressed = ETrue; + // feedback/basic on down event, if hit test is + // used. Area registry is used for rectangular + // buttons + if ( ( iFlags & KAknButtonHitTest ) + && !IsDimmed() + && iExtension->iFeedback ) + { + iExtension->iFeedback->InstantFeedback( + this, + ETouchFeedbackBasicButton, + aPointerEvent ); + } + + // make a mark so that we can later test that the button press comes from pointer event + iButtonPressed |= KPointerFlag; + + // Redraw button, if needed + if ( NeedsRedrawWhenPressed() ) + { + redrawNeeded = ETrue; + } + + ShowHelpL(); + } + + if ( iFlags & KAknButtonReportOnKeyDown ) + { + // State is changed on button down event + ChangeState( EFalse ); + redrawNeeded = EFalse; + DrawNow(); //Redraw before noticing the observer for observer might open dialog + if ( Observer() ) + { + Observer()->HandleControlEventL( this, + MCoeControlObserver::EEventStateChanged ); + } + } + + if ( iFlags & KAknButtonKeyRepeat ) + { + // Key repeat + iExtension->iFlags.Clear( CAknButtonExtension::EKeyRepeatEventReported ); + StartKeyRepeatTimerL(); + } + + if ( iFlags & KAknButtonReportOnLongPress ) + { + iExtension->iFlags.Clear( CAknButtonExtension::ELongPressReported ); + iExtension->StartLongPressTimerL(); + } + } + break; + } + + case TPointerEvent::EDrag: + { + iNumberOfDragEvents++; + if ( iNumberOfDragEvents >= KDragEventSensitivity ) + { + iNumberOfDragEvents = 0; + + // Pointer is dragged out of the button area + if ( !buttonEvent && iButtonPressed ) + { + // Redraw button, if needed + if ( NeedsRedrawWhenPressed() ) + { + iButtonPressed = EFalse; + redrawNeeded = ETrue; + } + iButtonPressed = EFalse; + + StopKeyRepeatTimer(); + StopLongPressTimer(); + + if ( !IsFocused() ) + { + HideHelp(); + } + if ( iExtension->iFlags.IsSet( CAknButtonExtension::ELongPressReported ) && Observer() ) + { + Observer()->HandleControlEventL( this, + static_cast( + CAknButton::ELongPressEndedEvent ) ); + } + iExtension->iFlags.Clear( CAknButtonExtension::ELongPressReported ); + } + + // Pointer is dragged back into button area + else if ( buttonEvent && !iButtonPressed && !IsDimmed() ) + { + iButtonPressed = ETrue; + + // Redraw button, if needed + if ( NeedsRedrawWhenPressed() ) + { + redrawNeeded = ETrue; + } + + if ( iFlags & KAknButtonKeyRepeat ) + { + // Continue key repeat + StartKeyRepeatTimerL(); + } + + if ( ( iFlags & KAknButtonReportOnLongPress ) && + !( iExtension->iFlags.IsSet( CAknButtonExtension::ELongPressReported ) ) ) + { + // Restart long press timer + StartLongPressTimerL(); + } + } + } + break; + } + + case TPointerEvent::EButton1Up: + { + iNumberOfDragEvents = 0; + HideHelp(); + + StopKeyRepeatTimer(); + StopLongPressTimer(); + + if ( iButtonPressed ) + { + // Redraw button, if needed + if ( NeedsRedrawWhenPressed() ) + { + iButtonPressed = EFalse; + if ( ! ( buttonEvent && iStates->Count() > 1 ) ) + { + redrawNeeded = ETrue; + } + } + iButtonPressed = EFalse; + } + + TBool hasDrawn( EFalse ); + if ( buttonEvent && !IsDimmed() ) + { + // feedback/BasicButton on up event, if hit test is + // used. Area registry is used for rectangular + // buttons + if ( ( iFlags & KAknButtonHitTest ) + && iExtension->iFeedback ) + { + iExtension->iFeedback->InstantFeedback( + this, + ETouchFeedbackBasicButton, + ETouchFeedbackVibra, + aPointerEvent ); + } + // The state is not changed, if it is already changed on key + // down event, or if a long press or a key repeat event is + // already reported to the observer. + if ( !( iFlags & KAknButtonReportOnKeyDown ) && + !( iExtension->iFlags.IsSet( CAknButtonExtension::ELongPressReported ) ) && + !( iExtension->iFlags.IsSet( CAknButtonExtension::EKeyRepeatEventReported ) ) ) + { + ChangeState( EFalse ); + if ( !hasDrawn ) + { + DrawNow(); + hasDrawn = ETrue; + } + + if ( Observer() ) + { + Observer()->HandleControlEventL( this, + MCoeControlObserver::EEventStateChanged ); + } + } + else + { + if ( iExtension->iFlags.IsSet( CAknButtonExtension::ELongPressReported ) && Observer() ) + { + if ( redrawNeeded && !hasDrawn ) + { + DrawNow(); + hasDrawn = ETrue; + } + Observer()->HandleControlEventL( this, + static_cast( + CAknButton::ELongPressEndedEvent ) ); + } + iExtension->iFlags.Clear( CAknButtonExtension::ELongPressReported ); + iExtension->iFlags.Clear( CAknButtonExtension::EKeyRepeatEventReported ); + } + + if ( RequestExit() && Observer() ) + { + if ( redrawNeeded && !hasDrawn ) + { + DrawNow(); + hasDrawn = ETrue; + } + Observer()->HandleControlEventL( this, + MCoeControlObserver::EEventRequestExit ); + } + } + + if ( !buttonEvent && !IsDimmed() && Observer() ) + { + if ( redrawNeeded && !hasDrawn ) + { + DrawNow(); + hasDrawn = ETrue; + } + Observer()->HandleControlEventL( this, + MCoeControlObserver::EEventRequestCancel ); + + if ( iExtension->iFlags.IsSet( CAknButtonExtension::ELongPressReported ) ) + { + Observer()->HandleControlEventL( this, + static_cast( + CAknButton::ELongPressEndedEvent ) ); + iExtension->iFlags.Clear( CAknButtonExtension::ELongPressReported ); + iExtension->iFlags.Clear( CAknButtonExtension::EKeyRepeatEventReported ); + } + } + if ( hasDrawn ) + { + redrawNeeded = EFalse; + } + break; + } + + default: + break; + } + if (redrawNeeded) + { + DrawNow(); + } + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::PositionChanged +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::PositionChanged() + { + if ( iExtension ) iExtension->HandleFeedbackAreaChange(); + CAknControl::PositionChanged(); + } + +// ----------------------------------------------------------------------------- +// CAknButton::FocusChanged +// This function is called whenever a control gains or loses focus. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::FocusChanged( TDrawNow aDrawNow ) + { + if ( !IsFocused() && iButtonPressed ) + { + iButtonPressed = EFalse; + iKeyDownReported = EFalse; + } + if ( IsVisible() ) + { + + if ( IsFocused() && iShowHelp ) + { + TRAP_IGNORE( ShowHelpL() ); + } + else + { + HideHelp(); + + // Stop the timers if active + StopLongPressTimer(); + StopKeyRepeatTimer(); + } + if ( !IsBackedUp() && aDrawNow ) + { + DrawNow(); + } + } + + iShowHelp = EFalse; + } + +// ----------------------------------------------------------------------------- +// CAknButton::ExtensionInterface +// For future extensions +// ----------------------------------------------------------------------------- +// +EXPORT_C void* CAknButton::ExtensionInterface( TUid /*aInterface*/ ) + { + return NULL; + } + +// ----------------------------------------------------------------------------- +// CAknButton::Draw +// Draw a control called by window server. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::Draw( const TRect& /*aRect*/ ) const + { + TRect rect( Rect() ); + TAknLayoutRect centerLayout; + centerLayout.LayoutRect( rect, + AknLayoutScalable_Avkon::toolbar_button_pane_g1().LayoutLine() ); + TRect innerRect( centerLayout.Rect() ); + TRect highlightRect( HighlightRect() ); + CWindowGc& gc = SystemGc(); + CAknButtonState* state = State(); + + // Skin ids are determined here (a bit too early than necessary) so that + // we can avoid doing the same thing in DrawMaskedL. + if ( !( iFlags & KAknButtonNoFrame ) ) + { + TInt frameIdIndex = KFrameId; + + if ( iButtonPressed ) + { + frameIdIndex = KPressedFrameId; + } + else if ( state && state->Flags() & KAknButtonStateHasLatchedFrame ) + { + if ( IsDimmed() ) + { + // dimmed latched frame + frameIdIndex = KLatchedDimmedFrameId; + } + else + { + // latched down + frameIdIndex = KLatchedFrameId; + } + } + else if ( IsDimmed()) + { + // dimmed frame + frameIdIndex = KDimmedFrameId; + } + + if ( SkinIID( frameIdIndex ) != KAknsIIDNone ) + { + iBgContext->SetFrame( SkinIID( frameIdIndex ) ); + iBgContext->SetCenter( SkinIID( ++frameIdIndex ) ); + iBgContext->SetFrameRects( rect, innerRect ); + } + } + + if ( !iExtension->iFlags.IsSet( CAknButtonExtension::EUseAdditionalMask ) ) + { + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + MAknsControlContext* cc = AknsDrawUtils::ControlContext( this ); + + if ( !( iFlags & KAknButtonNoFrame ) ) + { + // frame graphics + if ( !AknsDrawUtils::Background( skin, iBgContext, NULL, gc, + rect, KAknsDrawParamNoClearUnderImage ) ) + { + gc.SetBrushColor( KRgbRed ); + gc.SetBrushStyle( CGraphicsContext::ESolidBrush ); + gc.DrawRect( rect ); + } + + + if ( IsFocused() && !highlightRect.IsEmpty() ) + { + iBgContext->SetFrame( KAknsIIDQsnFrButtonHighlight ); + iBgContext->SetCenter( KAknsIIDQsnFrButtonHighlightCenter ); + iBgContext->SetFrameRects( rect, innerRect ); + + // frame graphics + if ( !AknsDrawUtils::Background( skin, iBgContext, NULL, gc, + rect, KAknsDrawParamNoClearUnderImage ) ) + { + gc.SetBrushColor( KRgbRed ); + gc.SetBrushStyle( CGraphicsContext::ESolidBrush ); + gc.DrawRect( rect ); + } + } + } + else if ( ( iFlags & KAknButtonNoFrame && iFlags & KAknButtonPressedDownFrame ) && + ( iButtonPressed || + ( state && state->Flags() & KAknButtonStateHasLatchedFrame && + !IsDimmed() ) ) ) + { + gc.BitBltMasked( Rect().iTl, iExtension->iPressedDownBmp, + TRect( TPoint(0,0), Size() ), + iExtension->iPressedDownBmpMask, EFalse ); + } + } + else if ( !( iFlags & KAknButtonNoFrame ) ) + { + if ( AknsUtils::SkinInstance() ) + { + AknsDrawUtils::Background( AknsUtils::SkinInstance(), iBgContext, this, gc, + rect, KAknsDrawParamNoClearUnderImage ); + } + } + + TBool hasIcon = ( GetCurrentIcon() != NULL ); + TBool hasText = state && state->HasText(); + + if ( hasIcon && hasText ) + { + DrawTextAndIconButton( gc ); + } + else if ( hasText ) + { + DrawTextButton( gc ); + } + else if ( hasIcon ) + { + DrawIconButton( gc ); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::ConstructFromResourceL +// Constructs controls from a resource file. +// @param aResourceId is the ID for this component's resource +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::ConstructFromResourceL( const TInt aResourceId ) + { + if ( aResourceId ) + { + TResourceReader reader; + iCoeEnv->CreateResourceReaderLC( reader, aResourceId ); + ConstructFromResourceL( reader ); + CleanupStack::PopAndDestroy(); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetCurrentState +// Sets active button state index +// @param aStateIndex is the index inside state array +// @param aDrawNow should be ETrue for the button to be redrawn +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetCurrentState( const TInt aStateIndex, + const TBool aDrawNow ) + { + TInt newIndex = -1; + if ( iStates && iStates->Count() ) + { + newIndex = aStateIndex % iStates->Count(); + } + + TRAP_IGNORE( SetStateIndexL( newIndex ) ); + if ( aDrawNow ) + { + DrawNow(); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::AddStateL +// Adds one more state for the button to the end of state array. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::AddStateL( CGulIcon* aIcon, + CGulIcon* aDimmedIcon, + CGulIcon* aPressedIcon, + CGulIcon* aHoverIcon, + const TDesC& aText, + const TDesC& aHelpText, + const TInt aStateFlags ) + { + CAknButtonState* state = new (ELeave) CAknButtonState( aStateFlags ); + CleanupStack::PushL( state ); + state->ConstructL( aIcon, aDimmedIcon, aPressedIcon, aHoverIcon, aText, + aHelpText ); + iStates->AppendL( state ); + CleanupStack::Pop( state ); + } + +// ----------------------------------------------------------------------------- +// CAknButton::AddStateL +// Adds one more state for the button to the end of state array. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::AddStateL( const TDesC& aFilePath, + const TInt aBmpId, + const TInt aMaskId, + const TInt aDimmedBmpId, + const TInt aDimmedMaskId, + const TInt aPressedBmpId, + const TInt aPressedMaskId, + const TInt aHoverBmpId, + const TInt aHoverMaskId, + const TDesC& aText, + const TDesC& aHelpText, + const TInt aStateFlags, + const TAknsItemID& aId, + const TAknsItemID& aDimmedId, + const TAknsItemID& aPressedId, + const TAknsItemID& aHoverId ) + { + CAknButtonState* state = new (ELeave) CAknButtonState( aStateFlags ); + CleanupStack::PushL( state ); + state->ConstructL( aFilePath, aBmpId, aMaskId, aDimmedBmpId, aDimmedMaskId, + aPressedBmpId, aPressedMaskId, aHoverBmpId, aHoverMaskId, + aText, aHelpText, aId, aDimmedId, aPressedId, aHoverId ); + iStates->AppendL( state ); + CleanupStack::Pop( state ); + } + + +// ----------------------------------------------------------------------------- +// CAknButton::AddStateL +// Adds one more state for the button to the end of state array. +// ----------------------------------------------------------------------------- +// +void CAknButton::AddStateL( CGulIcon* aIcon, + CGulIcon* aDimmedIcon, + CGulIcon* aPressedIcon, + CGulIcon* aHoverIcon, + const TDesC& aText, + const TDesC& aHelpText, + const TInt aStateFlags, + const TInt aCommandId ) + { + CAknCommandButtonState* state = + new (ELeave) CAknCommandButtonState( aStateFlags, aCommandId ); + CleanupStack::PushL( state ); + state->ConstructL( aIcon, aDimmedIcon, aPressedIcon, aHoverIcon, aText, + aHelpText ); + iStates->AppendL( state ); + CleanupStack::Pop( state ); + } + + +// ----------------------------------------------------------------------------- +// CAknButton::SetFlags +// Sets the button flags +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetButtonFlags( const TInt aFlags ) + { + if ( !(iFlags & KAknButtonNoFrame ) && aFlags & KAknButtonNoFrame ) + { + iExtension->iMargins.SetAllValuesTo( 0 ); + } + if ( aFlags & KAknButtonHitTest ) + { + SetHitTest( iExtension ); + iExtension->HandleFeedbackAreaChange(); + } + if ( aFlags & KAknButtonNoFrame && aFlags & KAknButtonPressedDownFrame ) + { + TRAP_IGNORE ( CreatePressedDownFrameL() ); + } + iFlags = aFlags; + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetFrameAndCenterIds +// Sets specified frame IDs. Can be used when default frame is not suitable. +// Use KAknsIIDNone value in case when some frame or center drawing is not +// needed or KAknsIIDDefault when the default button frame should be used. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetFrameAndCenterIds( + const TAknsItemID& aFrameId, + const TAknsItemID& aCenterId, + const TAknsItemID& aLatchedFrameId, + const TAknsItemID& aLatchedCenterId, + const TAknsItemID& aDimmedFrameId, + const TAknsItemID& aDimmedCenterId, + const TAknsItemID& aPressedFrameId, + const TAknsItemID& aPressedCenterId, + const TAknsItemID& aLatchedDimmedFrameId, + const TAknsItemID& aLatchedDimmedCenterId ) + { + RArray& skinIds = iExtension->iFrameAndCenterIds; + + if ( aFrameId != KAknsIIDDefault ) + { + skinIds[KFrameId] = aFrameId; + } + if ( aCenterId != KAknsIIDDefault ) + { + skinIds[KCenterId] = aCenterId; + } + if ( aLatchedFrameId != KAknsIIDDefault ) + { + skinIds[KLatchedFrameId] = aLatchedFrameId; + } + if ( aLatchedCenterId != KAknsIIDDefault ) + { + skinIds[KLatchedCenterId] = aLatchedCenterId; + } + if ( aDimmedFrameId != KAknsIIDDefault ) + { + skinIds[KDimmedFrameId] = aDimmedFrameId; + } + if ( aDimmedCenterId != KAknsIIDDefault ) + { + skinIds[KDimmedCenterId] = aDimmedCenterId; + } + if ( aPressedFrameId != KAknsIIDDefault ) + { + skinIds[KPressedFrameId] = aPressedFrameId; + } + if ( aPressedCenterId != KAknsIIDDefault ) + { + skinIds[KPressedCenterId] = aPressedCenterId; + } + if ( aLatchedDimmedFrameId != KAknsIIDDefault ) + { + skinIds[KLatchedDimmedFrameId] = aLatchedDimmedFrameId; + } + if ( aLatchedDimmedCenterId != KAknsIIDDefault ) + { + skinIds[KLatchedDimmedCenterId] = aLatchedDimmedCenterId; + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetBackgroundIds +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetBackgroundIds( + const TAknsItemID& aBackgroundId, + const TAknsItemID& aLatchedBackgroundId, + const TAknsItemID& aDimmedBackgroundId, + const TAknsItemID& aPressedBackgroundId, + const TAknsItemID& aLatchedDimmedBackgroundId ) + { + CAknButton::SetFrameAndCenterIds( aBackgroundId, aBackgroundId, + aLatchedBackgroundId, + aLatchedBackgroundId, + aDimmedBackgroundId, aDimmedBackgroundId, + aPressedBackgroundId, + aPressedBackgroundId, + aLatchedDimmedBackgroundId, + aLatchedDimmedBackgroundId ); + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetTextFont +// Sets some specific text font. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetTextFont( const CFont* aFont ) + { + iFont = aFont; + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetTextColorIds +// Sets the color table and color index for the button text. +// It will be used on button drawing if color of the text shouldn't be taken +// from text layout. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetTextColorIds( const TAknsItemID& aTextColorTableId, + const TInt aTextColorIndex ) + { + iTextColorTableId = aTextColorTableId; + iTextColorIndex = aTextColorIndex; + + TRgb textColor; + + if ( AknsUtils::GetCachedColor( AknsUtils::SkinInstance(), textColor, + iTextColorTableId, iTextColorIndex ) == KErrNone ) + { + TRAP_IGNORE( OverrideColorL( EColorButtonText, textColor ) ); + DrawDeferred(); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetTextHorizontalAlignment +// Sets the horizontal alignment for the text inside the button. It will be used +// if alignment shouldn't be taken from text layout. By default it will be +// centered. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetTextHorizontalAlignment( + const CGraphicsContext::TTextAlign aHorizontalAlignment ) + { + iHorizontalAlignment = aHorizontalAlignment; + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetTextVerticalAlignment +// Sets the vertical alignment for the text inside the button. It will be used +// if alignment shouldn't be taken from text layout. By default it will be +// centered. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetTextVerticalAlignment( + const CAknButton::TAlignment aVerticalAlignment ) + { + iVerticalAlignment = aVerticalAlignment; + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetTextUnderlineStyle +// Sets the text underline style for the text inside the button. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetTextUnderlineStyle( TFontUnderline aUnderlineStyle ) + { + iExtension->iUnderlineStyle = aUnderlineStyle; + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetIconScaleMode +// Sets the scale mode for the icon inside the button. The default is +// EAspectRatioNotPreserved. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetIconScaleMode( const TScaleMode aScaleMode ) + { + iScaleMode = aScaleMode; + + for ( TInt i = 0; i < iStates->Count(); ++i ) + { + CAknButtonState* state = iStates->At( i ); + + if ( state ) + { + state->SetIconScaleMode( aScaleMode ); + } + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetIconHorizontalAlignment +// Sets the horizontal alignment for the icon inside the button. +// The default is ECenter +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetIconHorizontalAlignment( + const CAknButton::TAlignment aHorizontalAlignment ) + { + iExtension->iHorizontalIconAlignment = aHorizontalAlignment; + } +// ----------------------------------------------------------------------------- +// CAknButton::SetIconVerticalAlignment +// Sets the vertical alignment for the icon inside the button. +// The default is ECenter +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetIconVerticalAlignment( + const CAknButton::TAlignment aVerticalAlignment ) + { + iExtension->iVerticalIconAlignment = aVerticalAlignment; + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetTextAndIconAlignment +// Sets the icon and text alignment for the button having both +// The default is EIconBeforeText +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetTextAndIconAlignment ( + const CAknButton::TTextAndIconAlignment aAlignment ) + { + iExtension->iTextAndIconAlignment = aAlignment; + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetHelpNoteTimeouts +// Sets the delay before the help text is shown and also specifies the time for +// how long help text is visible. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetHelpNoteTimeouts( const TInt aBeforeTimeout, + const TInt aInViewTimeout ) + { + if ( aBeforeTimeout >= 0 ) + { + iHelpNoteWaitInterval = aBeforeTimeout; + } + if ( aInViewTimeout >= 0 ) + { + iHelpNoteInViewInterval = aInViewTimeout; + } + + if(iHelpNote) + { + iHelpNote->SetTimeDelayBeforeShow( iHelpNoteWaitInterval ); + iHelpNote->SetTimePopupInView( iHelpNoteInViewInterval ); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetKeyRepeatInterval +// Sets the interval for the key repeat. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetKeyRepeatInterval( const TInt aKeyRepeatDelay, + const TInt aKeyRepeatInterval ) + { + // Convert time intervals to microseconds + iKeyRepeatDelay = aKeyRepeatDelay * 1000; + iKeyRepeatInterval = aKeyRepeatInterval * 1000; + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetLongPressInterval +// Sets the interval for the long presses. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetLongPressInterval( const TInt aLongPressInterval ) + { + iExtension->iLongPressInterval = aLongPressInterval * 1000; + } + +// ----------------------------------------------------------------------------- +// CAknButton::StateIndex +// Returns the index of the current button state. +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt CAknButton::StateIndex() const + { + return iStateIndex; + } + +// ----------------------------------------------------------------------------- +// CAknButton::EnablePictographsL +// Enables pictograph drawing in the button text. +// Only effective in Japanese variant. +// By default, it is disabled. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::EnablePictographsL( CAknPictographInterface& aInterface ) + { + iExtension->iPictographInterface = &aInterface; + } + +// ----------------------------------------------------------------------------- +// CAknButton::DisablePictographs +// Disables pictograph drawing in the button text. +// Only effective in Japanese variant. +// By default, it is disabled. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::DisablePictographs() + { + iExtension->iPictographInterface = NULL; + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetHighlightRect +// It will change the default highlight rectangular around +// the focused button +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetHighlightRect( const TRect& aRect ) + { + iHighlightRect = aRect; + } + +// ----------------------------------------------------------------------------- +// CAknButton::HighlightRect +// Returns highlight rectangular around button +// ----------------------------------------------------------------------------- +// +EXPORT_C TRect CAknButton::HighlightRect() const + { + if ( IsNonFocusing() ) + { + return TRect(); + } + else + { + return iHighlightRect; + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetTooltipPosition +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetTooltipPosition( const TTooltipPosition aPosition ) + { + iExtension->iTooltipPosition = aPosition; + } + +// ----------------------------------------------------------------------------- +// CAknButton::RequestExit +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetRequestExit( const TBool aRequestExit ) + { + if (aRequestExit) + { + iFlags |= KAknButtonRequestExitOnButtonUpEvent; + } + else + { + iFlags &= ~KAknButtonRequestExitOnButtonUpEvent; + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::IsDimmed +// ----------------------------------------------------------------------------- +// +EXPORT_C TBool CAknButton::IsDimmed() const + { + return iExtension->iFlags.IsSet( CAknButtonExtension::EDimmed ); + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetHelpTextL +// Sets the help text for dimmed button +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetDimmedHelpTextL( const TDesC& aHelpText ) + { + delete iDimmedHelpText; + iDimmedHelpText = NULL; + + iDimmedHelpText = aHelpText.AllocL(); + } + +// ----------------------------------------------------------------------------- +// CAknButton::ChangeState +// Changes the state of the button +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt CAknButton::ChangeState( TBool aDrawNow ) + { + if ( !iStates || !iStates->Count() ) + { + return -1; + } + + TInt newIndex( iStateIndex + 1 ); + + if ( iStateIndex == iStates->Count() - 1 ) + { + newIndex = 0; + } + + TRAP_IGNORE( SetStateIndexL( newIndex ) ); + + if ( aDrawNow ) + { + DrawNow(); + } + + return iStateIndex; + } + +// ----------------------------------------------------------------------------- +// CAknButton::GetCurrentText +// Returns the texts which will be displayed inside the button for the current +// state. +// ----------------------------------------------------------------------------- +// +EXPORT_C const TDesC& CAknButton::GetCurrentText() const + { + CAknButtonState* state = State(); + if ( state ) + { + return state->Text(); + } + else + { + return KNullDesC(); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::GetCurrentIcon +// Returns the right icon for the current state +// ----------------------------------------------------------------------------- +// +EXPORT_C const CGulIcon* CAknButton::GetCurrentIcon() const + { + CAknButtonState* state = State(); + const CGulIcon* icon = NULL; + if ( state ) + { + if ( iButtonPressed && state->PressedIcon() ) + { + icon = state->PressedIcon(); + } + else if ( IsDimmed() && state->DimmedIcon() ) + { + icon = state->DimmedIcon(); + } + else + { + icon = state->Icon(); + } + } + return icon; + } + +// ----------------------------------------------------------------------------- +// CAknButton::ShowHelpL +// Shows help text for a certain period of time. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::ShowHelpL() + { + if ( !IsVisible() ) + { + return; + } + if ( !iHelpNote ) + { + iHelpNote = CAknInfoPopupNoteController::NewL(); + + iHelpNote->SetTimeDelayBeforeShow( iHelpNoteWaitInterval ); + iHelpNote->SetTimePopupInView( iHelpNoteInViewInterval ); + iHelpNote->SetTooltipModeL( ETrue ); + } + + if ( IsDimmed() && iDimmedHelpText ) + { + iHelpNote->SetTextL( *iDimmedHelpText ); + } + else + { + CAknButtonState* state = State(); + if ( state && state->HasHelp() ) + { + iHelpNote->SetTextL( state->HelpText() ); + } + else + { + return; + } + } + + UpdateTooltipPosition(); + iHelpNote->ShowInfoPopupNote(); + } + +// ----------------------------------------------------------------------------- +// CAknButton::HideHelp +// Hides help text after certain interval. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::HideHelp() + { + if(iHelpNote) + { + iHelpNote->HideInfoPopupNote(); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::State +// Returns current state. +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButtonState* CAknButton::State() const + { + return State( iStateIndex ); + } + +// ----------------------------------------------------------------------------- +// CAknButton::State +// Returns the state under the specified index. +// ----------------------------------------------------------------------------- +// +EXPORT_C CAknButtonState* CAknButton::State( const TInt aStateIndex ) const + { + CAknButtonState* state = NULL; + if ( iStates && aStateIndex >= 0 && aStateIndex < iStates->Count() ) + { + state = iStates->At( aStateIndex ); + } + return state; + } + +// ----------------------------------------------------------------------------- +// CAknButton::Flags +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt CAknButton::ButtonFlags() const + { + return iFlags; + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetMargins +// Sets button's marginals. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::SetMargins( const TMargins8& aMargins ) + { + iExtension->iFlags.Clear( CAknButtonExtension::EUseDefaultMargins ); + iExtension->iMargins = aMargins; + SizeChanged(); + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetIconSize +// Sets button's icon size. +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt CAknButton::SetIconSize( const TSize& aSize ) + { + iExtension->iFlags.Clear( CAknButtonExtension::EUseDefaultIconSize ); + iExtension->iIconSize = aSize; + + return ScaleIcons(); + } + +// ----------------------------------------------------------------------------- +// CAknButton::ResetState +// Sets button to unpressed state. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CAknButton::ResetState( ) + { + StopKeyRepeatTimer(); + StopLongPressTimer(); + iButtonPressed = EFalse; + HideHelp(); + if ( iExtension ) + { + if ( iExtension->iFlags.IsSet( CAknButtonExtension::ELongPressReported ) && Observer() ) + { + TRAP_IGNORE( Observer()->HandleControlEventL( this, + static_cast( CAknButton::ELongPressEndedEvent ) ) ); + } + + iExtension->iFlags.Clear( CAknButtonExtension::ELongPressReported ); + iExtension->iFlags.Clear( CAknButtonExtension::EKeyRepeatEventReported ); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::CalculateDefaultMargins +// Calculates default margins. +// ----------------------------------------------------------------------------- +// +void CAknButton::CalculateDefaultMargins() + { + if ( iExtension->iFlags.IsSet( CAknButtonExtension::EUseDefaultMargins ) ) + { + if ( !( iFlags & KAknButtonNoFrame ) ) + { + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( Rect(), + AknLayoutScalable_Avkon::aid_value_unit2().LayoutLine() ); + iExtension->iMargins.SetAllValuesTo( + layoutRect.Rect().Size().iWidth / 10 ); // always square + } + } + + if ( iExtension->iFlags.IsSet( CAknButtonExtension::EUseDefaultIconSize ) ) + { + // ensure that icon size never exceeds the space inside margins + TRect rectInsideMargins( iExtension->iMargins.InnerRect( Rect() ) ); + + if ( rectInsideMargins.Size().iWidth < iExtension->iIconSize.iWidth ) + { + iExtension->iIconSize.iWidth = + Max( 0, rectInsideMargins.Size().iWidth ); + } + + if ( rectInsideMargins.Size().iHeight < iExtension->iIconSize.iHeight ) + { + iExtension->iIconSize.iHeight = + Max( 0, rectInsideMargins.Size().iHeight ); + } + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::ScaleIcons +// Scales all icons. +// ----------------------------------------------------------------------------- +// +TInt CAknButton::ScaleIcons() + { + TInt retval = KErrNone; + + for ( TInt i = 0; i < iStates->Count(); ++i ) + { + CAknButtonState* state = iStates->At( i ); + + if ( state ) + { + retval = Min( retval, state->ScaleIcons( iExtension->iIconSize, + iScaleMode ) ); + if ( iExtension->iFlags.IsSet( CAknButtonExtension::EDimmed ) && + !state->iDimmedIcon && + state->iIcon ) + { + TRAP_IGNORE( CreateAndSetDimmedIconL( state->iDimmedIcon, + state->iIcon, state->ScaleMode() ) ); + } + } + } + + return retval; + } + +// ----------------------------------------------------------------------------- +// CAknButton::DrawTextButton +// Continues drawing of the button which has only text +// ----------------------------------------------------------------------------- +// +void CAknButton::DrawTextButton( CWindowGc& aGc ) const + { + CAknButtonState* state = State(); + if ( !state || !state->HasText() ) + return; + + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + + TRect textRect = iExtension->iMargins.InnerRect( Rect() ); + + if ( !( iFlags & KAknButtonNoFrame ) && + ( iFlags & KAknButtonTextInsideFrame ) ) + { + TAknLayoutRect center; + center.LayoutRect( Rect(), + AknLayoutScalable_Avkon::toolbar_button_pane_g1().LayoutLine() ); + + textRect = center.Rect(); + } + + aGc.SetBrushStyle( CGraphicsContext::ENullBrush ); + + TRgb penColor; + TRgb brushColor; + GetTextColors( penColor, brushColor ); + aGc.SetPenColor( penColor ); + aGc.SetBrushColor( brushColor ); + + const CFont* font = iFont; + if ( !font ) + { + font = iCoeEnv->NormalFont(); + } + aGc.UseFont( font ); + + aGc.SetUnderlineStyle( iExtension->iUnderlineStyle ); + + // buffer for visually ordered text + TBuf<255 + KAknBidiExtraSpacePerLine> visualText; + TInt clipWidth = textRect.Width(); + + // bidi processing - using AknBidiTextUtils. + AknBidiTextUtils::ConvertToVisualAndClip( + state->Text(), + visualText, + *font, + clipWidth, + clipWidth ); + + TInt baselineOffset = 0; + switch ( iVerticalAlignment ) + { + case ETop: + baselineOffset = font->AscentInPixels(); + break; + + case EBottom: + baselineOffset = textRect.Height(); + break; + + default: // centered + baselineOffset = font->AscentInPixels() + + ( textRect.Height() - font->AscentInPixels() ) / 2; + } + + CGraphicsContext::TTextAlign horAlignment = iHorizontalAlignment; + + aGc.DrawText( visualText, textRect, baselineOffset, horAlignment ); + if ( iExtension->iPictographInterface ) + { + // For Japanese variant only + iExtension->iPictographInterface->Interface()->DrawPictographsInText( + aGc, *font, visualText, textRect, baselineOffset, horAlignment ); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::DrawIconButton +// Continues drawing of the button which has only an icon in it +// ----------------------------------------------------------------------------- +// +void CAknButton::DrawIconButton( CWindowGc& aGc ) const + { + TRect iconRect( iExtension->iMargins.InnerRect( Rect() ) ); + + aGc.SetBrushStyle( CGraphicsContext::ENullBrush ); + + const CGulIcon* icon = GetCurrentIcon(); + if ( !icon ) + return; + + CFbsBitmap* buttonBmp = icon->Bitmap(); + CFbsBitmap* buttonMask = icon->Mask(); + + TPoint iconPoint; + TSize iconSize ( buttonBmp->SizeInPixels()); + + switch ( iExtension->iHorizontalIconAlignment ) + { + case ERight: + { + iconPoint.iX = iconRect.iBr.iX - iconSize.iWidth; + } + break; + + case ECenter: + { + iconPoint.iX = iconRect.iTl.iX + + (iconRect.Width() / 2 - iconSize.iWidth / 2 ); + } + break; + + case ELeft: + { + iconPoint.iX = iconRect.iTl.iX; + } + break; + + default: + // Should never come here + break; + } + + switch ( iExtension->iVerticalIconAlignment ) + { + case ETop: + { + iconPoint.iY = iconRect.iTl.iY; + } + break; + + case ECenter: + { + iconPoint.iY = iconRect.iTl.iY + + ( iconRect.Height() / 2 - iconSize.iHeight / 2 ); + } + break; + + case EBottom: + { + iconPoint.iY = iconRect.iBr.iY - iconSize.iHeight; + } + break; + + default: + // Should never come here + break; + } + + if( buttonBmp && buttonMask ) + { + aGc.BitBltMasked( iconPoint, buttonBmp, + iconRect.Size(), buttonMask, ETrue ); + } + else if ( buttonBmp ) + { + aGc.BitBlt( iconPoint, buttonBmp, iconRect.Size() ); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::DrawTextAndIconButton +// Continues drawing of the button which has both text and icon +// ----------------------------------------------------------------------------- +// +void CAknButton::DrawTextAndIconButton( CWindowGc& aGc ) const + { + CAknButtonState* state = State(); + if ( !state || !state->HasText() ) + { + return; + } + + const CGulIcon* icon = GetCurrentIcon(); + if ( !icon ) + { + return; + } + + TRect rect = iExtension->iMargins.InnerRect( Rect() ); + TRect iconRect; + TRect textRect; + + if ( !( iFlags & KAknButtonNoFrame ) && + ( iFlags & KAknButtonTextInsideFrame )) + { + TAknLayoutRect centerLayout; + centerLayout.LayoutRect( rect, + AknLayoutScalable_Avkon::toolbar_button_pane_g1().LayoutLine() ); + rect = centerLayout.Rect(); + } + + CFbsBitmap* buttonBmp = icon->Bitmap(); + CFbsBitmap* buttonMask = icon->Mask(); + TSize iconSize ( buttonBmp->SizeInPixels()); + + // Set rects for icon and text according to their positioning + // First icon rect according to icon size - rest is for text + + switch ( iExtension->iTextAndIconAlignment ) + { + case EIconBeforeText: + if ( AknLayoutUtils::LayoutMirrored() ) + { + textRect.SetRect( rect.iTl.iX, rect.iTl.iY, + rect.iBr.iX - iconSize.iWidth, rect.iBr.iY); + iconRect.SetRect( rect.iTl.iX + + rect.Width() -iconSize.iWidth, + rect.iTl.iY, rect.iBr.iX, rect.iBr.iY ); + } + else + { + iconRect.SetRect( rect.iTl.iX, rect.iTl.iY, + rect.iTl.iX + iconSize.iWidth, rect.iBr.iY); + textRect.SetRect( rect.iTl.iX + iconSize.iWidth, + rect.iTl.iY, rect.iBr.iX, rect.iBr.iY ); + } + + break; + + case EIconAfterText: + if ( AknLayoutUtils::LayoutMirrored() ) + { + iconRect.SetRect( rect.iTl.iX, rect.iTl.iY, + rect.iTl.iX + iconSize.iWidth, rect.iBr.iY); + textRect.SetRect( rect.iTl.iX + iconSize.iWidth, + rect.iTl.iY, rect.iBr.iX, rect.iBr.iY ); + } + else + { + textRect.SetRect( rect.iTl.iX, rect.iTl.iY, + rect.iBr.iX - iconSize.iWidth, rect.iBr.iY); + iconRect.SetRect( rect.iTl.iX + + rect.Width() -iconSize.iWidth, + rect.iTl.iY, rect.iBr.iX, rect.iBr.iY ); + } + break; + + case EIconOverText: + iconRect.SetRect( rect.iTl.iX, rect.iTl.iY, + rect.iBr.iX, rect.iTl.iY + iconSize.iHeight ); + textRect.SetRect( rect.iTl.iX, rect.iTl.iY + iconSize.iHeight, + rect.iBr.iX, rect.iBr.iY ); + break; + + case EIconUnderText: + textRect.SetRect( rect.iTl.iX, rect.iTl.iY, + rect.iBr.iX, rect.iBr.iY - iconSize.iHeight ); + iconRect.SetRect( rect.iTl.iX, rect.iBr.iY - iconSize.iHeight, + rect.iBr.iX, rect.iBr.iY ); + break; + + case EOverlay: + { + textRect = rect; + iconRect = rect; + } + break; + + default: + return; + } + + // Draw icon + TPoint iconPoint; + switch ( iExtension->iHorizontalIconAlignment ) + { + case ERight: + { + iconPoint.iX = iconRect.iBr.iX - iconSize.iWidth; + } + break; + + case ECenter: + { + iconPoint.iX = iconRect.iTl.iX + + (iconRect.Width() / 2 - iconSize.iWidth / 2 ); + } + break; + + case ELeft: + { + iconPoint.iX = iconRect.iTl.iX; + } + break; + + default: + // Should never come here + break; + } + + switch ( iExtension->iVerticalIconAlignment ) + { + case ETop: + { + iconPoint.iY = iconRect.iTl.iY; + } + break; + + case ECenter: + { + iconPoint.iY = iconRect.iTl.iY + + ( iconRect.Height() / 2 - iconSize.iHeight / 2 ); + } + break; + + case EBottom: + { + iconPoint.iY = iconRect.iBr.iY - iconSize.iHeight; + } + break; + + default: + // Should never come here + break; + } + + if( buttonBmp && buttonMask ) + { + aGc.BitBltMasked( iconPoint, buttonBmp, + iconRect.Size(), buttonMask, ETrue ); + } + else if ( buttonBmp ) + { + aGc.BitBlt( iconPoint, buttonBmp, iconRect.Size() ); + } + + const CFont* font = iFont; + if ( !font ) + { + font = iCoeEnv->NormalFont(); + } + aGc.UseFont( font ); + + TRgb penColor; + TRgb brushColor; + GetTextColors( penColor, brushColor ); + aGc.SetPenColor( penColor ); + aGc.SetBrushColor( brushColor ); + + aGc.SetUnderlineStyle( iExtension->iUnderlineStyle ); + + TBuf<255 + KAknBidiExtraSpacePerLine> visualText; // buffer for visually ordered text + TInt clipWidth = textRect.Width(); + + // bidi processing - using AknBidiTextUtils. + AknBidiTextUtils::ConvertToVisualAndClip( + state->Text(), + visualText, + *font, + clipWidth, + clipWidth ); + + TInt baselineOffset = 0; + switch ( iVerticalAlignment ) + { + case ETop: + baselineOffset = font->AscentInPixels(); + break; + + case EBottom: + baselineOffset = textRect.Height(); + break; + + default: // centered + baselineOffset = font->AscentInPixels() + + ( textRect.Height() - font->AscentInPixels() ) / 2; + } + + CGraphicsContext::TTextAlign horAlignment = iHorizontalAlignment; + + aGc.DrawText( visualText, textRect, baselineOffset, horAlignment ); + if ( iExtension->iPictographInterface ) + { + // For Japanese variant only + iExtension->iPictographInterface->Interface()->DrawPictographsInText( + aGc, *font, visualText, textRect, baselineOffset, horAlignment ); + } + } + +// ----------------------------------------------------------------------------- +// Starts the long press timer. +// ----------------------------------------------------------------------------- +// +void CAknButton::StartLongPressTimerL() + { + if ( iExtension ) + { + iExtension->StartLongPressTimerL(); + } + } + +// ----------------------------------------------------------------------------- +// Stops the long press timer. +// ----------------------------------------------------------------------------- +// +void CAknButton::StopLongPressTimer() + { + if ( iExtension && iExtension->iLongPressTimer && + iExtension->iLongPressTimer->IsActive() ) + { + iExtension->iLongPressTimer->Cancel(); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::StartKeyRepeatTimerL +// Starts the timer for the long presses. The timer is constructed when used +// for the first time. +// ----------------------------------------------------------------------------- +// +void CAknButton::StartKeyRepeatTimerL() + { + if ( !iKeyRepeatTimer ) + { + iKeyRepeatTimer = CPeriodic::NewL( CActive::EPriorityStandard ); + } + else if ( iKeyRepeatTimer->IsActive() ) + { + iKeyRepeatTimer->Cancel(); + } + + if ( iKeyRepeatInterval > 0 ) + { + iKeyRepeatTimer->Start( iKeyRepeatDelay, iKeyRepeatInterval, + TCallBack( ReportKeyRepeatL, this ) ); + } + } + +// ----------------------------------------------------------------------------- +// Stops the key repeat timer. +// ----------------------------------------------------------------------------- +// +void CAknButton::StopKeyRepeatTimer() + { + if ( iKeyRepeatTimer && iKeyRepeatTimer->IsActive() ) + { + iKeyRepeatTimer->Cancel(); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::ReportKeyRepeatL +// Cancel the timer. +// ----------------------------------------------------------------------------- +// +TInt CAknButton::ReportKeyRepeatL( TAny* aThis ) + { + // Fixes TSW error AJUA-7CEF8H + User::ResetInactivityTime(); + CAknButton* self = reinterpret_cast< CAknButton* >( aThis ); + + if ( self->IsVisible() && + !self->iExtension->iFlags.IsSet( CAknButtonExtension::EDimmed ) ) + { + if ( self->iStates->Count() > 1 ) + { + self->ChangeState( ETrue ); + } + + if ( self->Observer() ) + { + self->Observer()->HandleControlEventL( self, + MCoeControlObserver::EEventStateChanged ); + } + + TBool feedbackNeeded = (self->iStates->Count() > 1) || (self->Observer()); + TBool pointerRepeat = (self->iButtonPressed & KPointerFlag); // it was caused by pointer event + if ( self->iExtension->iFeedback && feedbackNeeded && pointerRepeat) + { + self->iExtension->iFeedback->InstantFeedback( self, ETouchFeedbackSensitiveButton ); + } + + self->iExtension->iFlags.Set( CAknButtonExtension::EKeyRepeatEventReported ); + } + else if ( self->iKeyRepeatTimer && self->iKeyRepeatTimer->IsActive() ) + { + self->iKeyRepeatTimer->Cancel(); + } + + return 1; // CPeriodic ignores return value + } + +// ----------------------------------------------------------------------------- +// CAknButton::Extension +// ----------------------------------------------------------------------------- +// +CAknButtonExtension* CAknButton::Extension() const + { + return iExtension; + } + +// ----------------------------------------------------------------------------- +// CAknButton::UpdateTooltipPosition +// ----------------------------------------------------------------------------- +// +void CAknButton::UpdateTooltipPosition() + { + TPoint position; + + if ( AknsUtils::GetControlPosition( this, position ) != KErrNone ) + { + position = PositionRelativeToScreen(); + } + TRect rect( position, Size() ); + + TPoint center = rect.Center(); + + switch ( iExtension->iTooltipPosition ) + { + case EPositionTop: + { + iHelpNote->SetPositionAndAlignment( + TPoint( center.iX, rect.iTl.iY ), EHCenterVBottom ); + break; + } + case EPositionBottom: + { + iHelpNote->SetPositionAndAlignment( + TPoint( center.iX, rect.iBr.iY ), EHCenterVTop ); + break; + } + case EPositionLeft: + { + iHelpNote->SetPositionAndAlignment( + TPoint( rect.iTl.iX, center.iY ), EHRightVCenter ); + break; + } + case EPositionRight: + { + iHelpNote->SetPositionAndAlignment( + TPoint( rect.iBr.iX, center.iY ), EHLeftVCenter ); + break; + } + default: + { + return; + } + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::RequestExit +// Returns whether button should send EEventRequestExit to command observer +// on button up events. +// ----------------------------------------------------------------------------- +// +TBool CAknButton::RequestExit() const + { + if ( iFlags & KAknButtonRequestExitOnButtonUpEvent ) + { + return ETrue; + } + else + { + return EFalse; + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::ContentRect +// Returns the the rectangle reserved for frame center, or the rect for text and +// icon, if the button has no frames (controls rect for now). +// ----------------------------------------------------------------------------- +// +TRect CAknButton::ContentRect() const + { + TRect rect( Size() ); + if ( !( iFlags & KAknButtonNoFrame ) && + ( iFlags & KAknButtonTextInsideFrame ) ) + { + TAknLayoutRect centerLayout; + centerLayout.LayoutRect( rect, + AknLayoutScalable_Avkon::toolbar_button_pane_g1().LayoutLine() ); + rect = centerLayout.Rect(); + } + return rect; + } + +// ----------------------------------------------------------------------------- +// CAknButton::NeedsRedrawWhenPressed +// Returns boolean value indicating whether button needs redraw when it is +// pressed or released without changes in its state. +// ----------------------------------------------------------------------------- +// +TBool CAknButton::NeedsRedrawWhenPressed() const + { + CAknButtonState* state = State(); + if ( !iButtonPressed && iStates->Count() > 1 ) + { + return EFalse; + } + + if ( iButtonPressed && iFlags & KAknButtonPressedDownFrame ) + { + return ETrue; + } + + return ( state && state->PressedIcon() || + ( !( iFlags & KAknButtonNoFrame ) && + !( iFlags & KAknButtonNoFramePressEvent ) && + !( state && state->Flags() & KAknButtonStateHasLatchedFrame && + SkinIID( KPressedFrameId ) == SkinIID( KLatchedFrameId ) ) ) ); + } + +// ----------------------------------------------------------------------------- +// CAknButton::SkinIID +// ----------------------------------------------------------------------------- +// +TAknsItemID CAknButton::SkinIID( const TInt aIndex ) const + { + if ( iExtension && aIndex >= 0 && + aIndex < iExtension->iFrameAndCenterIds.Count() ) + { + return iExtension->iFrameAndCenterIds[aIndex]; + } + else + { + return KAknsIIDNone; + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::HitAreaContainsL +// Checks if a button icon's non-transparent area was tapped. +// ----------------------------------------------------------------------------- +// +TBool CAknButton::HitAreaContainsL( const TPoint& aPoint, TBool aCheckHitArea ) const + { + TBool buttonEvent( ETrue ); + + if ( aCheckHitArea ) + { + if ( TouchArea().Contains( aPoint ) ) + { + return ETrue; + } + else + { + return EFalse; + } + } + else if ( iFlags & KAknButtonHitTest ) + { + TRect rect( Size() ); + TRect contentRect( ContentRect() ); + + CFbsBitmap* bitmap = new (ELeave) CFbsBitmap; + CleanupStack::PushL( bitmap ); + + User::LeaveIfError( bitmap->Create( rect.Size(), EGray256 ) ); + + CFbsBitmapDevice* device = CFbsBitmapDevice::NewL( bitmap ); + + CleanupStack::PushL( device ); + CFbsBitGc* gc = CFbsBitGc::NewL(); + gc->Activate( device ); + gc->SetBrushStyle( CGraphicsContext::ENullBrush ); + + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + MAknsControlContext* cc = AknsDrawUtils::ControlContext( this ); + + if ( !(iFlags & KAknButtonNoFrame ) ) + { + CAknButtonState* state = State(); + + TInt frameIdIndex = KFrameId; + if ( iButtonPressed ) + { + frameIdIndex = KPressedFrameId; + } + else if ( state && state->Flags() & KAknButtonStateHasLatchedFrame ) + { + if ( IsDimmed() ) + { + // dimmed latched frame + frameIdIndex = KLatchedDimmedFrameId; + } + else + { + // latched down + frameIdIndex = KLatchedFrameId; + } + } + else if ( IsDimmed()) + { + // dimmed frame + frameIdIndex = KDimmedFrameId; + } + + if ( SkinIID( frameIdIndex ) != KAknsIIDNone ) + { + TAknsItemID frameId = SkinIID( frameIdIndex ); + TAknsItemID centerId = SkinIID( frameIdIndex + 1 ); + + gc->SetBrushColor( KRgbWhite ); + + if ( !AknsDrawUtils::DrawFrame( skin, *gc, rect, + contentRect, frameId, centerId, KAknsSDMAlphaOnly ) ) + { + gc->DrawRect( rect ); + } + gc->DrawRect( contentRect ); + } + } + else if ( GetCurrentIcon() ) + { + // if button has (only) icon, then mark other parts transparent + gc->SetBrushColor( KRgbBlack ); + gc->Clear(); + CFbsBitmap* mask = GetCurrentIcon()->Mask(); + if ( mask ) + { + gc->BitBlt( contentRect.iTl, mask, mask->SizeInPixels() ); + } + } + else if ( GetCurrentText() != KNullDesC ) + { + gc->SetBrushColor( KRgbWhite ); + gc->Clear( contentRect ); + } + else + { + // if this happens.. make the whole button transparent! + gc->SetBrushColor( KRgbBlack ); + gc->Clear( contentRect ); + } + + TRgb pixel; + TPoint point( aPoint - Rect().iTl ); + bitmap->GetPixel( pixel, point ); + + delete gc; + CleanupStack::PopAndDestroy( 2 ); // bitmap, device + + if ( pixel == KRgbBlack ) + { + buttonEvent = EFalse; + } + } // iFlags & KAknButtonHitTest + return buttonEvent; + } + +// ----------------------------------------------------------------------------- +// CAknButton::UsesDefaultMargins +// Checks if the button uses default margins. +// ----------------------------------------------------------------------------- +// +TBool CAknButton::UsesDefaultMargins() const + { + return iExtension->iFlags.IsSet( CAknButtonExtension::EUseDefaultMargins ); + } + +// ----------------------------------------------------------------------------- +// CAknButton::TextColor +// Gets the correct text color. +// ----------------------------------------------------------------------------- +// +TRgb CAknButton::TextColor() const + { + TRgb color; + + if ( IsDimmed() ) + { + color = iEikonEnv->ControlColor( EColorButtonText, *this ); + color.SetAlpha( 77 ); + } + else if ( iButtonPressed ) + { + color = iEikonEnv->ControlColor( EColorButtonTextPressed, *this ); + } + else + { + color = iEikonEnv->ControlColor( EColorButtonText, *this ); + } + + return color; + } + +// ----------------------------------------------------------------------------- +// CAknButton::CreatePressedDownFrameL +// Generates a pressed down mask +// ----------------------------------------------------------------------------- +// +void CAknButton::CreatePressedDownFrameL() + { + + // Fetch frames from frame provider if one exists + if ( iExtension->FetchProviderPressedBmpsL() ) + { + return; + } + + if ( iExtension->iPressedDownBmp && + iExtension->iPressedDownBmp->SizeInPixels() == Size() ) + { + iExtension->SetProviderPressedBmpsL(); + return; + } + + iExtension->DeletePressedBmps(); + + // Fetch preffered display mode for icon type images + AknIconConfig::TPreferredDisplayMode displayMode; + AknIconConfig::PreferredDisplayMode( + displayMode, AknIconConfig::EImageTypeIcon ); + + iExtension->iPressedDownBmp = new ( ELeave ) CFbsBitmap; + User::LeaveIfError( iExtension->iPressedDownBmp->Create( Size(), + displayMode.iBitmapMode) ); + iExtension->iPressedDownBmpMask = new ( ELeave ) CFbsBitmap; + User::LeaveIfError( iExtension->iPressedDownBmpMask->Create( Size(), + displayMode.iMaskMode ) ); + + CFbsBitmapDevice* bmpDevice = CFbsBitmapDevice::NewL( + iExtension->iPressedDownBmp ); + CleanupStack::PushL( bmpDevice ); + + CFbsBitGc* bmpGc (NULL ); + User::LeaveIfError( bmpDevice->CreateContext( bmpGc ) ); + CleanupStack::PushL( bmpGc ); + + CFbsBitmapDevice* bmpMaskDevice = CFbsBitmapDevice::NewL( + iExtension->iPressedDownBmpMask ); + CleanupStack::PushL( bmpMaskDevice ); + + CFbsBitGc* bmpMaskGc( NULL ); + User::LeaveIfError( bmpMaskDevice->CreateContext( bmpMaskGc ) ); + CleanupStack::PushL( bmpMaskGc ); + + TRect rect ( Size() ); + TAknLayoutRect centerLayout; + centerLayout.LayoutRect( rect, + AknLayoutScalable_Avkon::toolbar_button_pane_g1().LayoutLine() ); + TRect innerRect( centerLayout.Rect() ); + + TAknWindowLineLayout unit = AknLayoutScalable_Avkon::aid_value_unit2().LayoutLine(); + innerRect.Shrink( unit.iW/10, unit.iH/10 ); + + AknsDrawUtils::DrawFrame( AknsUtils::SkinInstance(), + *bmpGc, rect, innerRect, + SkinIID( KPressedFrameId ), KAknsIIDDefault, + KAknsDrawParamRGBOnly ); + + AknsDrawUtils::DrawFrame( AknsUtils::SkinInstance(), + *bmpMaskGc, rect, innerRect, + SkinIID( KPressedFrameId ), KAknsIIDDefault, + KAknsSDMAlphaOnly ); + + // Modify mask 50% transparent + iExtension->iPressedDownBmpMask->LockHeap(); + + TInt w = iExtension->iPressedDownBmpMask->SizeInPixels().iWidth; + TInt h = iExtension->iPressedDownBmpMask->SizeInPixels().iHeight; + TInt dataStride = iExtension->iPressedDownBmpMask->DataStride() - w; + unsigned char* address = (unsigned char *)iExtension->iPressedDownBmpMask->DataAddress(); + + + for ( TInt i = 0; i < h; ++i ) + { + for ( TInt j = 0; j < w; ++j ) + { + *address >>= 1; + ++address; + } + address += dataStride; + } + + iExtension->iPressedDownBmpMask->UnlockHeap(); + + // Set created frames to frame provider if one exists + iExtension->SetProviderPressedBmpsL(); + + CleanupStack::PopAndDestroy( 4 ); // bmpDevice, bmpGc, bmpMaskDevice, bmpMaskGc + } + + +// ----------------------------------------------------------------------------- +// CAknButton::HideTooltipWhenAppFaded +// Sets tooltip to show or hide itself when background faded. By default tooltip +// is not shown when background faded. +// ----------------------------------------------------------------------------- +// +void CAknButton::HideTooltipWhenAppFaded( TBool aHide ) + { + if(iHelpNote) + { + iHelpNote->HideWhenAppFaded( aHide ); + } + } + + +// ----------------------------------------------------------------------------- +// CAknButton::CheckHitArea +// This checks hit area for fixed toolbar buttons. +// ----------------------------------------------------------------------------- +// +void CAknButton::CheckHitArea( ) + { + iExtension->iFlags.Set( CAknButtonExtension::ECheckHitArea ); + SetHitTest( iExtension ); + iExtension->HandleFeedbackAreaChange(); + } + +// ----------------------------------------------------------------------------- +// CAknButton::UseAdditionalMask +// Sets button to use additional masks during drawing. +// ----------------------------------------------------------------------------- +// +void CAknButton::UseMaskedDraw( TBool aMaskedDraw ) + { + if ( aMaskedDraw ) + { + iExtension->iFlags.Set( CAknButtonExtension:: EUseAdditionalMask ); + } + else + { + iExtension->iFlags.Clear( CAknButtonExtension:: EUseAdditionalMask ); + } + } + + +// ----------------------------------------------------------------------------- +// Registers resource provider. +// ----------------------------------------------------------------------------- +// +void CAknButton::RegisterResourceProvider( CAknResourceProvider* aProvider ) + { + iExtension->iResourceProvider = aProvider; + } + + +// ----------------------------------------------------------------------------- +// Unregisters resource provider. +// ----------------------------------------------------------------------------- +// +void CAknButton::UnregisterResourceProvider() + { + iExtension->iResourceProvider = 0; + } + + +CAknsFrameBackgroundControlContext* CAknButton::BgContext() + { + return iBgContext; + } + + +// ----------------------------------------------------------------------------- +// CAknButton::RemoveCurrentState +// Removes the current state. +// ----------------------------------------------------------------------------- +// +void CAknButton::RemoveCurrentState() + { + // Can't remove the state if it's the only one left. + if ( iStates->Count() > 1 ) + { + CAknButtonState* state = iStates->At( iStateIndex ); + delete state; + state = NULL; + iStates->Delete( iStateIndex ); + + iStateIndex <= 0 ? iStateIndex = 0 : iStateIndex--; + DrawNow(); + } + } + + +// ----------------------------------------------------------------------------- +// CAknButton::CalculateLuminance +// Calculates color's luminance value. +// ----------------------------------------------------------------------------- +// +TInt CAknButton::CalculateLuminance( const TRgb& aColor ) const + { + TInt R = aColor.Red(); + TInt G = aColor.Green(); + TInt B = aColor.Blue(); + // Should be scaled to 0-255? + TInt Y = (((66 * R) + (129 * G) + (25 * B) + 128) >> 8) + 16; + return Y; + } + + +// ----------------------------------------------------------------------------- +// CAknButton::ConvertColorsForOutlineEffect +// Converts the outline color to be white or black if the fill color is +// too similar to outline color. +// ----------------------------------------------------------------------------- +// +void CAknButton::ConvertColorsForOutlineEffect( TRgb& aFillColor, TRgb& aOutlineColor ) const + { + // @todo maybe there is already some conversion utility in multimedia image library? + TInt innerLum = CalculateLuminance(aFillColor); + TInt outerLum = CalculateLuminance(aOutlineColor); + + // if the defined colours are the same, then change the outline color so that + // it's either black or white, contrasting according to the font label text color's brightness + TInt difference = outerLum - innerLum; + difference = Abs(difference); + TInt half = (0xff / 2); // @todo figure out hlsMax somehow + TInt threshold = (0xff / 3); // @todo figure out hlsMax somehow, and decide on the threshold! + if(difference < threshold) + { + // if inner luminance is low, the outer luminance should be high, i.e. white + aOutlineColor = (innerLum < half) ? KRgbWhite : KRgbBlack; + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::GetTextColors +// Gets correct text colors +// ----------------------------------------------------------------------------- +// +void CAknButton::GetTextColors( TRgb& aPenColor, TRgb& aBrushColor ) const + { + TBool outlineEffectOn = EFalse; + const CAknLayoutFont* layoutFont = CAknLayoutFont::AsCAknLayoutFontOrNull( iFont ); + if ( layoutFont ) + { + outlineEffectOn = layoutFont->FontSpecification().IsOutlineEffectOn(); + } + + if ( IsDimmed() ) + { + aPenColor = TextColor(); + aBrushColor = iEikonEnv->ControlColor( EColorControlDimmedBackground,*this ); + } + else + { + aPenColor = TextColor(); + aBrushColor = iEikonEnv->ControlColor( EColorControlBackground,*this ); + } + if ( outlineEffectOn ) + { + ConvertColorsForOutlineEffect( aBrushColor, aPenColor ); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::SetStateIndexL +// Sets new state index +// ----------------------------------------------------------------------------- +// +void CAknButton::SetStateIndexL( TInt aNewIndex ) + { + if ( iStateIndex != aNewIndex ) + { + iStateIndex = aNewIndex; + // Create new popup note controller every time state changes + // (text is not updated properly in help note if this is not done) + if ( iHelpNote ) + { + delete iHelpNote; + iHelpNote = 0; + } + iHelpNote = CAknInfoPopupNoteController::NewL(); + iHelpNote->SetTimeDelayBeforeShow( iHelpNoteWaitInterval ); + iHelpNote->SetTimePopupInView( iHelpNoteInViewInterval ); + iHelpNote->SetTooltipModeL( ETrue ); + } + } + +// ----------------------------------------------------------------------------- +// CAknButton::TouchArea +// Returns the button touchable area. +// ----------------------------------------------------------------------------- +// +TRect CAknButton::TouchArea() const + { + TRect touchRect( Rect() ); + if ( iExtension->iFlags.IsSet( CAknButtonExtension::ECheckHitArea ) ) + { + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( Rect(), + AknLayoutScalable_Avkon::aid_touch_sctrl_middle( + !Layout_Meta_Data::IsLandscapeOrientation() ).LayoutLine() ); + touchRect = layoutRect.Rect(); + } + return touchRect; + } +// end of file