uifw/EikStd/coctlsrc/AknButton.cpp
branchRCL_3
changeset 56 d48ab3b357f1
parent 55 aecbbf00d063
child 59 978afdc0236f
--- a/uifw/EikStd/coctlsrc/AknButton.cpp	Tue Aug 31 15:28:30 2010 +0300
+++ b/uifw/EikStd/coctlsrc/AknButton.cpp	Wed Sep 01 12:16:19 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2005-2008 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2005-2010 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"
@@ -264,7 +264,10 @@
 
     // Sets bitmaps to resource provider (if one exists)
     void SetProviderPressedBmpsL();
-
+    
+    //Verify new rectagle size equals to the original
+    TBool TextRectSizeChanged( TRect aNewRect );
+   
 private: // Data
 
     CAknButton& iButton;
@@ -284,6 +287,16 @@
     CFbsBitmap* iPressedDownBmp;
     CFbsBitmap* iPressedDownBmpMask;
     CAknResourceProvider* iResourceProvider;
+    
+    //Previous touch down or drag position, valid only with pressed state. 
+    TPoint iPrePointerPos;
+    CAknsFrameBackgroundControlContext* iHighlightContext;  
+    // buffer for visually ordered text
+    TBuf<255 + KAknBidiExtraSpacePerLine> iVisualText; 
+    TBool iFeedbackEnabled;
+    TAknsItemID iBackgroundSkinIID;
+    TRect iBgFrameRect;
+    TRect iTextRect;
     };
 
 // ============================ MEMBER FUNCTIONS ===============================
@@ -303,7 +316,8 @@
       iVerticalIconAlignment( CAknButton::ECenter ),
       iHorizontalIconAlignment( CAknButton::ECenter ),
       iTextAndIconAlignment( CAknButton::EIconBeforeText ),
-      iResourceProvider( 0 )
+      iResourceProvider( 0 ),
+      iFeedbackEnabled( ETrue )
     {
     // default margins, these are applied to both text and icon
     iMargins.SetAllValuesTo( 
@@ -317,6 +331,7 @@
     iIconSize = layoutRect.Rect().Size();
     iFlags.Set( EUseDefaultIconSize );
     iFlags.Set( EUseDefaultMargins );
+    iTextRect = TRect::EUninitialized;
     }
 
 // -----------------------------------------------------------------------------
@@ -330,6 +345,7 @@
     iPictographInterface = NULL; // not owned
     iFrameAndCenterIds.Close();
     DeletePressedBmps();
+    delete iHighlightContext; 
     }
 
 // -----------------------------------------------------------------------------
@@ -368,6 +384,13 @@
     // Latched dimmed frame and center
     iFrameAndCenterIds.AppendL( KAknsIIDQsnFrButtonInactive );
     iFrameAndCenterIds.AppendL( KAknsIIDQsnFrButtonCenterInactive );
+    if ( !iHighlightContext )
+        {
+        iHighlightContext = CAknsFrameBackgroundControlContext::NewL(
+            KAknsIIDNone, TRect(), TRect(), EFalse );
+        iHighlightContext->SetFrame( KAknsIIDQsnFrButtonHighlight ); 
+        iHighlightContext->SetCenter( KAknsIIDQsnFrButtonHighlightCenter ); 
+        }
     }
 
 // -----------------------------------------------------------------------------
@@ -499,6 +522,20 @@
         }
     }
     
+//Verify new rectangle size equals to the original
+TBool CAknButtonExtension::TextRectSizeChanged( TRect aNewRect )
+    {
+    TBool result( ETrue );
+    if ( !iTextRect.IsEmpty() && !aNewRect.IsEmpty() )
+        {
+        if ( iTextRect.Width() == aNewRect.Width() 
+                && iTextRect.Height() == aNewRect.Height() )
+            {
+            result = EFalse;
+            }
+        }
+    return result;
+    }
     
 
 //
@@ -514,6 +551,10 @@
 
 void CAknButtonExtension::HandleFeedbackAreaChange()
     {
+    if ( !iFeedbackEnabled )
+        {
+        return; 
+        }
     // it is possible that feedback does not exist, eg. while booting.
     // try getting one, and give up if that fails.
     if ( !iFeedback )
@@ -579,6 +620,8 @@
     TAknsItemID iPressedId;
     TAknsItemID iHoverId;
     TScaleMode iScaleMode;
+    TBool iFlagsChanged; 
+    TBool iTextChanged; 
     };
 
 // ============================ MEMBER FUNCTIONS ===============================
@@ -991,6 +1034,7 @@
     iText = NULL;
 
     iText = aText.AllocL();
+    iExtension->iTextChanged = ETrue; 
     }
 
 // -----------------------------------------------------------------------------
@@ -1013,6 +1057,11 @@
 //
 EXPORT_C void CAknButtonState::SetFlags( const TInt aFlags )
     {
+    if ( ( iFlags & KAknButtonStateHasLatchedFrame ) != 
+        ( aFlags & KAknButtonStateHasLatchedFrame ) )
+        {
+        iExtension->iFlagsChanged = ETrue; 
+        }
     iFlags = aFlags;
     }
 
@@ -1070,7 +1119,21 @@
     LoadButtonIcon( iPressedIcon );
     LoadButtonIcon( iHoverIcon );
     }
-
+// -----------------------------------------------------------------------------
+// CAknButtonState::UpdateExtensionInfoL
+// Updates extension information. 
+// -----------------------------------------------------------------------------
+void CAknButtonState::UpdateExtensionInfoL( TInt aResource )
+	{
+	if ( iExtension )
+		{
+		iExtension->ConfigureExtensionFromResourceL( aResource );
+		LoadButtonIcon( iIcon );
+	    LoadButtonIcon( iDimmedIcon );
+	    LoadButtonIcon( iPressedIcon );
+	    LoadButtonIcon( iHoverIcon );
+		}
+	}
 // -----------------------------------------------------------------------------
 // CAknButtonState::SizeChanged
 // Scales function graphics to the given size
@@ -1321,6 +1384,44 @@
     {
     iExtension->iGeneratedDimmedIcon = aDimmedIconCreatedByButton;
     }
+// -----------------------------------------------------------------------------
+// CAknButtonState::FlagsChanged
+// Returns ETrue if button state flags are changed so that 
+// KAknStateHasLatchedDownFrame is setted or cleared
+// -----------------------------------------------------------------------------    
+TBool CAknButtonState::FlagsChanged()
+    {
+    return iExtension->iFlagsChanged;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknButtonState::ResetFlagsChanged
+// Frame has been updated so boolean iFlagsChanged can be set to EFalse
+// -----------------------------------------------------------------------------
+void CAknButtonState::ResetFlagsChanged()
+    {
+    iExtension->iFlagsChanged = EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknButtonState::TextChanged
+// Returns ETrue if text is changed and button's visual text has 
+// not been updated. 
+// -----------------------------------------------------------------------------    
+TBool CAknButtonState::TextChanged()
+    {
+    return iExtension->iTextChanged;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknButtonState::ResetTextChanged
+// Visual text has been updated so boolean iTextChanged can be set to EFalse
+// -----------------------------------------------------------------------------
+void CAknButtonState::ResetTextChanged()
+    {
+    iExtension->iTextChanged = EFalse;
+    }
+
 
 // -----------------------------------------------------------------------------
 // CAknButtonState::Extension
@@ -1562,7 +1663,12 @@
         {
         OverrideColorL( EColorButtonText, textColor );
         }
-
+    
+    if ( AknsUtils::GetCachedColor( AknsUtils::SkinInstance(), textColor, 
+            iTextColorTableId, EAknsCIQsnTextColorsCG84 ) == KErrNone )
+        {
+        OverrideColorL( EColorButtonTextPressed, textColor );
+        }
     if ( !iStates )
         {
         iStates = new ( ELeave ) CArrayPtrFlat<CAknButtonState>( 2 );
@@ -1594,6 +1700,7 @@
         iHorizontalAlignment = CGraphicsContext::ELeft;
         }
     iExtension->HandleFeedbackAreaChange();
+    SetFrameIDs(); 
     }
 
 // -----------------------------------------------------------------------------
@@ -1796,6 +1903,11 @@
             TRAP_IGNORE( OverrideColorL( EColorButtonText, textColor ) );
             }
     
+        if ( AknsUtils::GetCachedColor( AknsUtils::SkinInstance(), textColor, 
+                    iTextColorTableId, EAknsCIQsnTextColorsCG84 ) == KErrNone )
+            {
+            TRAP_IGNORE( OverrideColorL( EColorButtonTextPressed, textColor ) );
+            }
         // generated pressed frame has to be regenerated
         if ( iFlags & KAknButtonNoFrame && iFlags & KAknButtonPressedDownFrame )
             {
@@ -1889,7 +2001,6 @@
         HideHelp();
         iButtonPressed = EFalse;
         }
-    
     if ( aDimmed )
         {
         iExtension->iFlags.Set( CAknButtonExtension::EDimmed );
@@ -1898,7 +2009,7 @@
         {
         iExtension->iFlags.Clear( CAknButtonExtension::EDimmed );
         }
-    if ( iExtension->iFeedback )
+    if ( iExtension->iFeedbackEnabled && iExtension->iFeedback )
         {
         if ( aDimmed )
             {
@@ -1933,6 +2044,7 @@
         {
         CCoeControl::SetDimmed( aDimmed );
         }
+    SetFrameIDs(); 
     }
 
 // -----------------------------------------------------------------------------
@@ -1962,6 +2074,9 @@
                 {
                 // show press changes
                 iButtonPressed = ETrue;
+                iExtension->iPrePointerPos.SetXY( -1, -1 );
+                
+                SetFrameIDs(); 
                 if ( NeedsRedrawWhenPressed() )
                     {
                     DrawNow();
@@ -1996,6 +2111,7 @@
             if ( iButtonPressed )
                 {
                 iButtonPressed = EFalse;
+                SetFrameIDs(); 
 
                 if ( NeedsRedrawWhenPressed() )
                     {
@@ -2032,14 +2148,14 @@
                 iExtension->iFlags.Clear( CAknButtonExtension::ELongPressReported );
                 iExtension->iFlags.Clear( CAknButtonExtension::EKeyRepeatEventReported );
                 }
-
-            if ( iKeyDownReported && RequestExit() && Observer() )
+            
+            TInt reported = iKeyDownReported;
+            iKeyDownReported = EFalse;            
+            if ( reported && RequestExit() && Observer() )
                 {
                 Observer()->HandleControlEventL( this,
                     MCoeControlObserver::EEventRequestExit );
-                }
-
-            iKeyDownReported = EFalse;
+                }            
             }
         // we don't want aKeyEvent to go somewhere else :)
         return EKeyWasConsumed;
@@ -2058,7 +2174,7 @@
     if ( aVisible != IsVisible() )
         {
         CAknControl::MakeVisible( aVisible );
-        if ( iExtension->iFeedback )
+        if ( iExtension->iFeedbackEnabled && iExtension->iFeedback )
             {
             if ( aVisible )
                 {
@@ -2071,7 +2187,11 @@
             }
 
         CAknButtonState* state = State();
-        if ( !aVisible && state && state->HasHelp() )
+        if ( !aVisible && iButtonPressed )
+            {
+            ResetState();
+            }
+        else if ( !aVisible && state && state->HasHelp() )
             {
             HideHelp();
             }
@@ -2120,6 +2240,11 @@
 //
 EXPORT_C void CAknButton::SizeChanged()
     {
+    //Reset state if observer modified the rectangel.
+    if ( iButtonPressed && !Rect().Contains( iExtension->iPrePointerPos ) )
+        {
+        ResetState();               
+        }
     // 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 ) )
@@ -2149,6 +2274,7 @@
        {
         TRAP_IGNORE( CreatePressedDownFrameL() );
         }
+    SetFrameRects(); 
 
     iExtension->HandleFeedbackAreaChange();
     }
@@ -2171,6 +2297,10 @@
                 }
             return;
             }
+        if ( iExtension )
+            {
+            iExtension->iPrePointerPos = aPointerEvent.iPosition;
+            }
         TBool buttonEvent( TouchArea().Contains( aPointerEvent.iPosition ) );
         CAknButtonState* state = State();
         if ( !state )
@@ -2198,6 +2328,7 @@
                     if ( !iButtonPressed )
                         {
                         iButtonPressed = ETrue;
+                        SetFrameIDs(); 
                         // feedback/basic on down event, if hit test is
                         // used. Area registry is used for rectangular
                         // buttons
@@ -2227,7 +2358,8 @@
                         {
                         // State is changed on button down event
                         ChangeState( EFalse );
-                        redrawNeeded = ETrue;
+                        redrawNeeded = EFalse;
+                        DrawNow();  //Redraw before noticing the observer for observer might open dialog                        
                         if ( Observer() )
                             {
                             Observer()->HandleControlEventL( this,
@@ -2264,10 +2396,10 @@
                         // Redraw button, if needed
                         if ( NeedsRedrawWhenPressed() )
                             {
-                            iButtonPressed = EFalse;
                             redrawNeeded = ETrue;
                             }
                         iButtonPressed = EFalse;
+                        SetFrameIDs(); 
 
                         StopKeyRepeatTimer();
                         StopLongPressTimer();
@@ -2289,6 +2421,7 @@
                     else if ( buttonEvent && !iButtonPressed && !IsDimmed() )
                         {
                         iButtonPressed = ETrue;
+                        SetFrameIDs(); 
 
                         // Redraw button, if needed
                         if ( NeedsRedrawWhenPressed() )
@@ -2315,6 +2448,10 @@
 
             case TPointerEvent::EButton1Up:
                 {
+                if ( iExtension )
+                    {
+                    iExtension->iPrePointerPos.SetXY( -1, -1 );
+                    }
                 iNumberOfDragEvents = 0;
                 HideHelp();
 
@@ -2333,8 +2470,10 @@
                             }
                         }
                     iButtonPressed = EFalse;
+                    SetFrameIDs(); 
                     }
 
+                TBool hasDrawn( EFalse );
                 if ( buttonEvent && !IsDimmed() )
                     {
                         // feedback/BasicButton on up event, if hit test is
@@ -2357,7 +2496,12 @@
                          !( iExtension->iFlags.IsSet( CAknButtonExtension::EKeyRepeatEventReported ) ) )
                         {
                         ChangeState( EFalse );
-                        redrawNeeded = ETrue;
+                        if ( !hasDrawn )
+                        	{
+	                        DrawNow();
+	                        hasDrawn = ETrue;
+                        	}
+                        
                         if ( Observer() )
                             {
                             Observer()->HandleControlEventL( this,
@@ -2368,6 +2512,11 @@
                         {
                         if ( iExtension->iFlags.IsSet( CAknButtonExtension::ELongPressReported ) && Observer() )
                             {
+                            if ( redrawNeeded && !hasDrawn )
+                            	{
+                            	DrawNow();
+                            	hasDrawn = ETrue;
+                            	}
                             Observer()->HandleControlEventL( this, 
                                 static_cast<MCoeControlObserver::TCoeEvent>( 
                                 CAknButton::ELongPressEndedEvent ) );
@@ -2378,6 +2527,11 @@
 
                     if ( RequestExit() && Observer() )
                         {
+                        if ( redrawNeeded && !hasDrawn )
+                        	{
+                        	DrawNow();
+                        	hasDrawn = ETrue;
+                        	}
                         Observer()->HandleControlEventL( this,
                             MCoeControlObserver::EEventRequestExit );
                         }
@@ -2385,6 +2539,11 @@
                         
                 if ( !buttonEvent && !IsDimmed() && Observer() )
                    {
+                   if ( redrawNeeded && !hasDrawn )
+                	   {
+                	   DrawNow();
+                	   hasDrawn = ETrue;
+                	   }
                    Observer()->HandleControlEventL( this,
                         MCoeControlObserver::EEventRequestCancel );
                         
@@ -2397,7 +2556,10 @@
                         iExtension->iFlags.Clear( CAknButtonExtension::EKeyRepeatEventReported );
                         }                        
                    }
-
+                if ( hasDrawn )
+                	{
+                	redrawNeeded = EFalse;
+                	}
                 break;
                 }
 
@@ -2420,6 +2582,13 @@
     {
     if ( iExtension ) iExtension->HandleFeedbackAreaChange();
     CAknControl::PositionChanged();
+    
+    //Reset state if observer moved button position.
+    if ( iButtonPressed && iExtension && !Rect().Contains( iExtension->iPrePointerPos ) )
+    	{
+    	ResetState();
+    	}
+    SetFrameRects(); 
     }
     
 // -----------------------------------------------------------------------------
@@ -2432,6 +2601,7 @@
     if ( !IsFocused() && iButtonPressed )
         {
         iButtonPressed = EFalse; 
+        SetFrameIDs(); 
         iKeyDownReported = EFalse; 
         }
     if ( IsVisible() )
@@ -2476,49 +2646,14 @@
 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 ) )
+    if ( !( iFlags & KAknButtonNoFrame ) && !iButtonPressed && state && 
+            state->FlagsChanged() )
         {
-        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 );
-            }
+        SetFrameIDs(); 
         }
 
     if ( !iExtension->iFlags.IsSet( CAknButtonExtension::EUseAdditionalMask ) )
@@ -2540,13 +2675,10 @@
 
             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 ) )
+                if ( !AknsDrawUtils::Background( skin, 
+                      iExtension->iHighlightContext, NULL, gc, rect, 
+                      KAknsDrawParamNoClearUnderImage ) )
                     {
                     gc.SetBrushColor( KRgbRed );
                     gc.SetBrushStyle( CGraphicsContext::ESolidBrush );
@@ -2624,6 +2756,7 @@
         }
 
     TRAP_IGNORE( SetStateIndexL( newIndex ) );
+    SetFrameIDs(); 
     if ( aDrawNow )
         {
         DrawNow();
@@ -2713,10 +2846,13 @@
 // -----------------------------------------------------------------------------
 //
 EXPORT_C void CAknButton::SetButtonFlags( const TInt aFlags )
-    {
-    if ( !(iFlags & KAknButtonNoFrame ) && aFlags & KAknButtonNoFrame )
+    {    
+    if ( !( iFlags & KAknButtonNoFrame ) )
         {
-        iExtension->iMargins.SetAllValuesTo( 0 );
+        if ( aFlags & KAknButtonNoFrame ) 
+            {
+            iExtension->iMargins.SetAllValuesTo( 0 );         
+            }
         }
     if ( aFlags & KAknButtonHitTest )
         {
@@ -2791,6 +2927,7 @@
         {
         skinIds[KLatchedDimmedCenterId] = aLatchedDimmedCenterId;
         }
+    SetFrameIDs(); 
     }
 
 // -----------------------------------------------------------------------------
@@ -2822,6 +2959,7 @@
 EXPORT_C void CAknButton::SetTextFont( const CFont* aFont )
     {
     iFont = aFont;
+    ConvertTextToVisualAndClip( iExtension->iTextRect ); 
     }
 
 // -----------------------------------------------------------------------------
@@ -3116,6 +3254,8 @@
         }
     
     TRAP_IGNORE( SetStateIndexL( newIndex ) );
+    // Updating background context might be needed if states flags differ
+    SetFrameIDs(); 
     
     if ( aDrawNow )
         {
@@ -3294,6 +3434,7 @@
     StopKeyRepeatTimer();
     StopLongPressTimer();
     iButtonPressed = EFalse;
+    SetFrameIDs(); 
     HideHelp();
     if ( iExtension )
         {
@@ -3383,24 +3524,28 @@
 //
 void CAknButton::DrawTextButton( CWindowGc& aGc ) const
     {
+    TRect textRect;
+    
+    TRect iconRect; //this is no use
+    GetCurrentStateTextAndIconRect( iconRect, textRect );
+      
     CAknButtonState* state = State();
-    if ( !state || !state->HasText() )
-        return;
-
+    if ( state->TextChanged() || iExtension->TextRectSizeChanged( textRect ) )
+        {
+        ConvertTextToVisualAndClip( textRect ); 
+        }
+    DrawText( aGc, textRect ); 
+    }
+
+// -----------------------------------------------------------------------------
+// CAknButton::DrawText
+// Continues drawing of the button which has text
+// -----------------------------------------------------------------------------
+//
+void CAknButton::DrawText( CWindowGc& aGc, TRect& aTextRect ) const
+    {
     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;
@@ -3418,17 +3563,6 @@
 
     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 )
@@ -3438,22 +3572,24 @@
             break;
 
         case EBottom:
-            baselineOffset = textRect.Height();
+            baselineOffset = aTextRect.Height();
             break;
 
         default:  // centered
             baselineOffset = font->AscentInPixels() +
-                           ( textRect.Height() - font->AscentInPixels() ) / 2;
+                           ( aTextRect.Height() - font->AscentInPixels() ) / 2;
         }
 
     CGraphicsContext::TTextAlign horAlignment = iHorizontalAlignment;
 
-    aGc.DrawText( visualText, textRect, baselineOffset, horAlignment );
+    aGc.DrawText( iExtension->iVisualText, aTextRect, baselineOffset, 
+            horAlignment );
     if ( iExtension->iPictographInterface )
         {
         // For Japanese variant only
         iExtension->iPictographInterface->Interface()->DrawPictographsInText(
-            aGc, *font, visualText, textRect, baselineOffset, horAlignment );
+            aGc, *font, iExtension->iVisualText, aTextRect, baselineOffset, 
+            horAlignment );
         }
     }
 
@@ -3464,13 +3600,13 @@
 //
 void CAknButton::DrawIconButton( CWindowGc& aGc ) const
     {
-    TRect iconRect( iExtension->iMargins.InnerRect( Rect() ) );
+    TRect iconRect;
+    TRect textRect; 
+    GetCurrentStateTextAndIconRect( iconRect, textRect );
     
     aGc.SetBrushStyle( CGraphicsContext::ENullBrush );
 
     const CGulIcon* icon = GetCurrentIcon();
-    if ( !icon )
-        return;
 
     CFbsBitmap* buttonBmp = icon->Bitmap();
     CFbsBitmap* buttonMask = icon->Mask();
@@ -3552,98 +3688,24 @@
     if ( !state  || !state->HasText() )
         {
         return;
-        }
+        }   
     
     const CGulIcon* icon = GetCurrentIcon();
-    if ( !icon )
-        {
-        return;
-        }
-
-    TRect rect = iExtension->iMargins.InnerRect( Rect() );
+
+   
     TRect iconRect;
     TRect textRect;
+    GetCurrentStateTextAndIconRect( iconRect, 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 )        
+   
+    if ( state->TextChanged() || iExtension->TextRectSizeChanged( textRect ) )
         {
-        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;
+        ConvertTextToVisualAndClip( textRect ); 
         }
-
     // Draw icon
     TPoint iconPoint;
     switch ( iExtension->iHorizontalIconAlignment )
@@ -3708,57 +3770,7 @@
         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 );
-        }
+    DrawText( aGc, textRect ); 
     }
 
 // -----------------------------------------------------------------------------
@@ -4345,6 +4357,7 @@
         iStates->Delete( iStateIndex );
         
         iStateIndex <= 0 ? iStateIndex = 0 : iStateIndex--;
+        SetFrameIDs(); 
         DrawNow();
         }
     }
@@ -4442,10 +4455,271 @@
         iHelpNote->SetTimeDelayBeforeShow( iHelpNoteWaitInterval );
         iHelpNote->SetTimePopupInView( iHelpNoteInViewInterval );
         iHelpNote->SetTooltipModeL( ETrue );
+        
+        //When state changed, empty rect to enable recalculate the 
+        //visual text if text exists in current state.
+        if ( !(iExtension->iTextRect.IsEmpty()) )
+            {
+            iExtension->iTextRect = TRect::EUninitialized;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAknButton::SetFrameIDs
+// Sets frame ids for background context
+// -----------------------------------------------------------------------------
+//
+void CAknButton::SetFrameIDs() const
+    {
+    // Skin ids are determined here (a bit too early than necessary) so that 
+    // we can avoid doing the same thing in DrawMaskedL.
+    CAknButtonState* state = State();
+    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;
+            }
+
+        TAknsItemID skinIID( SkinIID( frameIdIndex ) );
+
+        // Only change the background frame graphics if necessary.
+        if ( skinIID != KAknsIIDNone &&
+             skinIID != iExtension->iBackgroundSkinIID )
+            {
+            iBgContext->SetFrame( skinIID );
+            iBgContext->SetCenter( SkinIID( ++frameIdIndex) );
+            iExtension->iBackgroundSkinIID = skinIID;
+            }
+        }
+    if ( state )
+        {
+        state->ResetFlagsChanged(); 
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAknButton::SetFrameRects
+// -----------------------------------------------------------------------------
+//
+void CAknButton::SetFrameRects()
+    {
+    TRect rect( Rect() );
+
+    // Only change the frame rects is the button rectangle is valid and the
+    // button size has changed.
+    if ( !rect.IsEmpty() && iExtension->iBgFrameRect != rect )
+        {
+        TAknLayoutRect centerLayout;
+        centerLayout.LayoutRect( rect,
+            AknLayoutScalable_Avkon::toolbar_button_pane_g1().LayoutLine() );
+        TRect innerRect( centerLayout.Rect() );
+
+        iBgContext->SetFrameRects( rect, innerRect );
+        iExtension->iHighlightContext->SetFrameRects( rect, innerRect );
+        iExtension->iBgFrameRect = rect;
         }
     }
 
 // -----------------------------------------------------------------------------
+// CAknButton::ConvertTextToVisualAndClip
+// -----------------------------------------------------------------------------
+//
+void CAknButton::ConvertTextToVisualAndClip( const TRect& aRect ) const
+    {
+    CAknButtonState* state = State();
+    if ( !state || !state->HasText() )
+        {
+        if ( state ) 
+            {
+            state->ResetTextChanged();
+            } 
+        return;
+        }
+
+    TRect textRect( aRect );
+    //Using given rect to calculate the visual text if it's not empty.
+    if ( !textRect.IsEmpty() )
+        {
+        iExtension->iTextRect = textRect;
+        }
+    //Calculate text area.
+    //This branch means that it's the first calling after the state changed
+    //or client using new font before this is shown. 
+    else 
+        {
+        TRect iconRect;
+        GetCurrentStateTextAndIconRect( iconRect, textRect );
+        iExtension->iTextRect = textRect;
+        }
+   
+    TInt clipWidth = textRect.Width();
+
+    const CFont* font = iFont;
+    if ( !font )
+        {
+        font = iCoeEnv->NormalFont();
+        }
+
+    // bidi processing - using AknBidiTextUtils.
+    AknBidiTextUtils::ConvertToVisualAndClip(
+        state->Text(),
+        iExtension->iVisualText,
+        *font,
+        clipWidth,
+        clipWidth );
+    }
+      
+// -----------------------------------------------------------------------------
+// CAknButton::GetCurrentStateTextAndIconRect()
+// Get rect for icon and text of the current button state .
+// -----------------------------------------------------------------------------
+//
+void CAknButton::GetCurrentStateTextAndIconRect( TRect& aIconRect, 
+        TRect& aTextRect ) const
+    {
+    TRect iconRect( TRect::EUninitialized ) ;
+    TRect textRect( TRect::EUninitialized );
+    
+    CAknButtonState* state = State();
+    
+    //Return directly if no state
+    if ( !state )
+        {
+        aIconRect = iconRect;
+        aTextRect = textRect;
+        return;
+        }
+    
+    TBool hasText( state->HasText() );
+    TBool hasIcon( EFalse );  
+
+    const CGulIcon* icon = GetCurrentIcon();
+    if ( icon )
+        {
+        hasIcon = ETrue;
+        }  
+    
+    TRect rect = iExtension->iMargins.InnerRect( Rect() );    
+    
+    //Icon area is not effected by the frame flags.
+    if ( hasIcon )
+        {
+        iconRect = rect;
+        }
+    
+    if ( !( iFlags & KAknButtonNoFrame ) &&
+          ( iFlags & KAknButtonTextInsideFrame ))
+        {
+        TAknLayoutRect centerLayout;
+        centerLayout.LayoutRect( rect,
+        AknLayoutScalable_Avkon::toolbar_button_pane_g1().LayoutLine() );
+        rect = centerLayout.Rect();
+        }
+    
+    if ( hasText )
+        {
+        textRect = rect;
+        }
+ 
+
+    if ( hasText && hasIcon )
+        {
+        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 CAknButton::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 CAknButton::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 CAknButton::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 CAknButton::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 CAknButton::EOverlay:
+                {
+                textRect = rect;
+                iconRect = rect;
+                }
+                break;
+            default:
+                break; //Do nothing.
+            }            
+        }
+    aTextRect = textRect;
+    aIconRect = iconRect;
+    }
+// -----------------------------------------------------------------------------
 // CAknButton::TouchArea
 // Returns the button touchable area.
 // -----------------------------------------------------------------------------
@@ -4463,4 +4737,49 @@
         }
     return touchRect;
     }
+
+// -----------------------------------------------------------------------------
+// CAknButton::EnableFeedback
+// Enables or disables tactile feedback
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CAknButton::EnableFeedback( TBool aEnable )
+    {
+    if ( iExtension->iFeedbackEnabled == aEnable )
+        {
+        return; 
+        }
+    iExtension->iFeedbackEnabled = aEnable; 
+    if ( aEnable )
+        {
+        if ( !iExtension->iFeedback )
+            {
+            iExtension->iFeedback = MTouchFeedback::Instance();
+            }
+        if ( !iExtension->iFeedback )
+            {
+            return;
+            }
+        if ( IsVisible() )
+            {
+            iExtension->iFeedback->MoveFeedbackAreaToFirstPriority( this, 
+                                                                        0 );
+            iExtension->iFeedback->EnableFeedbackForControl( 
+                    this, 
+                   !IsDimmed() );
+            }
+        iExtension->HandleFeedbackAreaChange(); 
+        }
+    else 
+        {
+        // MTouchFeedback instance lives in AknAppUi. If there is no
+        // MTouchFeedback instance there is no need to remove any areas
+        // either.
+        MTouchFeedback* fb = MTouchFeedback::Instance();
+        if ( fb )
+            {
+            fb->RemoveFeedbackForControl( this );
+            }
+        }
+    }
 // end of file