src/gui/kernel/qsoftkeymanager_s60.cpp
branchRCL_3
changeset 8 3f74d0d4af4c
parent 5 d3bac044e0f0
child 12 25a739ee40f4
--- a/src/gui/kernel/qsoftkeymanager_s60.cpp	Mon Mar 15 12:43:09 2010 +0200
+++ b/src/gui/kernel/qsoftkeymanager_s60.cpp	Thu Apr 08 14:19:33 2010 +0300
@@ -49,7 +49,7 @@
 #include "private/qsoftkeymanager_p.h"
 #include "private/qsoftkeymanager_s60_p.h"
 #include "private/qobject_p.h"
-//#include <eiksoftkeyimage.h>
+#include <eiksoftkeyimage.h>
 #include <eikcmbut.h>
 
 #ifndef QT_NO_SOFTKEYMANAGER
@@ -60,21 +60,34 @@
 const int MSK_POSITION = 3;
 const int RSK_POSITION = 2;
 
-QSoftKeyManagerPrivateS60::QSoftKeyManagerPrivateS60()
+QSoftKeyManagerPrivateS60::QSoftKeyManagerPrivateS60() : cbaHasImage(4) // 4 since MSK position index is 3
 {
     cachedCbaIconSize[0] = QSize(0,0);
     cachedCbaIconSize[1] = QSize(0,0);
-    skipNextUpdate = false;
+    cachedCbaIconSize[2] = QSize(0,0);
+    cachedCbaIconSize[3] = QSize(0,0);
 }
 
 bool QSoftKeyManagerPrivateS60::skipCbaUpdate()
 {
-    // lets not update softkeys if
+    // Lets not update softkeys if
     // 1. We don't have application panes, i.e. cba
-    // 2. S60 native dialog or menu is shown
-    if (QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes) ||
-        CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog() || skipNextUpdate) {
-        skipNextUpdate = false;
+    // 2. Our CBA is not active, i.e. S60 native dialog or menu with custom CBA is shown
+    //    2.1. Except if thre is no current CBA at all and WindowSoftkeysRespondHint is set
+
+    // Note: Cannot use IsDisplayingMenuOrDialog since CBA update can be triggered before
+    // menu/dialog CBA is actually displayed i.e. it is being costructed.
+    CEikButtonGroupContainer *appUiCba = S60->buttonGroupContainer();
+    // CEikButtonGroupContainer::Current returns 0 if CBA is not visible at all
+    CEikButtonGroupContainer *currentCba = CEikButtonGroupContainer::Current();
+    // Check if softkey need to be update even they are not visible
+    bool cbaRespondsWhenInvisible = false;
+    QWidget *window = QApplication::activeWindow();
+    if (window && (window->windowFlags() & Qt::WindowSoftkeysRespondHint))
+        cbaRespondsWhenInvisible = true;
+
+    if (QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes)
+            || (appUiCba != currentCba && !cbaRespondsWhenInvisible)) {
         return true;
     }
     return false;
@@ -149,6 +162,39 @@
     QT_TRAP_THROWING(cba.SetCommandL(position, command, text));
 }
 
+QPoint QSoftKeyManagerPrivateS60::softkeyIconPosition(int position, QSize sourceSize, QSize targetSize)
+{
+    QPoint iconPosition(0,0);
+    switch( AknLayoutUtils::CbaLocation() )
+        {
+        case AknLayoutUtils::EAknCbaLocationBottom:
+            // RSK must be moved to right, LSK in on correct position by default
+            if (position == RSK_POSITION)
+                iconPosition.setX(targetSize.width() - sourceSize.width());
+            break;
+        case AknLayoutUtils::EAknCbaLocationRight:
+        case AknLayoutUtils::EAknCbaLocationLeft:
+            // Already in correct position
+        default:
+            break;
+        }
+
+    // Align horizontally to center
+    iconPosition.setY((targetSize.height() - sourceSize.height()) >> 1);
+    return iconPosition;
+}
+
+QPixmap QSoftKeyManagerPrivateS60::prepareSoftkeyPixmap(QPixmap src, int position, QSize targetSize)
+{
+    QPixmap target(targetSize);
+    target.fill(Qt::transparent);
+    QPainter p;
+    p.begin(&target);
+    p.drawPixmap(softkeyIconPosition(position, src.size(), targetSize), src);
+    p.end();
+    return target;
+}
+
 bool QSoftKeyManagerPrivateS60::isOrientationLandscape()
 {
     // Hard to believe that there is no public API in S60 to
@@ -158,15 +204,11 @@
 
 QSize QSoftKeyManagerPrivateS60::cbaIconSize(CEikButtonGroupContainer *cba, int position)
 {
-    Q_UNUSED(cba);
-    Q_UNUSED(position);
 
-    // Will be implemented when EikSoftkeyImage usage license wise is OK
-/*
-    const int index = isOrientationLandscape() ? 0 : 1;
+    int index = position;
+    index += isOrientationLandscape() ? 0 : 1;
     if(cachedCbaIconSize[index].isNull()) {
         // Only way I figured out to get CBA icon size without RnD SDK, was
-        // Only way I figured out to get CBA icon size without RnD SDK, was
         // to set some dummy icon to CBA first and then ask CBA button CCoeControl::Size()
         // The returned value is cached to avoid unnecessary icon setting every time.
         const bool left = (position == LSK_POSITION);
@@ -178,50 +220,61 @@
             setNativeSoftkey(*cba, position, command, KNullDesC());
             cachedCbaIconSize[index] = qt_TSize2QSize(cba->ControlOrNull(command)->Size());
             EikSoftkeyImage::SetLabel(cba, left);
+
+            if(cachedCbaIconSize[index] == QSize(138,72)) {
+                // Hack for S60 5.0 (5800) landscape orientation, which return wrong icon size
+                cachedCbaIconSize[index] = QSize(60,60);
+            }
         }
     }
 
     return cachedCbaIconSize[index];
-*/
-    return QSize();
 }
 
 bool QSoftKeyManagerPrivateS60::setSoftkeyImage(CEikButtonGroupContainer *cba,
                                             QAction &action, int position)
 {
     bool ret = false;
-    Q_UNUSED(cba);
-    Q_UNUSED(action);
-    Q_UNUSED(position);
 
-    // Will be implemented when EikSoftkeyImage usage license wise is OK
-    /*
     const bool left = (position == LSK_POSITION);
     if(position == LSK_POSITION || position == RSK_POSITION) {
         QIcon icon = action.icon();
         if (!icon.isNull()) {
-            QPixmap pm = icon.pixmap(cbaIconSize(cba, position));
-            pm = pm.scaled(cbaIconSize(cba, position));
-            QBitmap mask = pm.mask();
-            if (mask.isNull()) {
-                mask = QBitmap(pm.size());
-                mask.fill(Qt::color1);
+            // Get size of CBA icon area based on button position and orientation
+            QSize requiredIconSize = cbaIconSize(cba, position);
+            // Get pixmap out of icon based on preferred size, the aspect ratio is kept
+            QPixmap pmWihtAspectRatio = icon.pixmap(requiredIconSize);
+            // Native softkeys require that pixmap size is exactly the same as requiredIconSize
+            // prepareSoftkeyPixmap creates a new pixmap with requiredIconSize and blits the 'pmWihtAspectRatio'
+            // to correct location of it
+            QPixmap softkeyPixmap = prepareSoftkeyPixmap(pmWihtAspectRatio, position, requiredIconSize);
+
+            QPixmap softkeyAlpha = softkeyPixmap.alphaChannel();
+            // Alpha channel in 5.1 and older devices need to be inverted
+            // TODO: Switch to use toSymbianCFbsBitmap with invert when available
+            if(QSysInfo::s60Version() <= QSysInfo::SV_S60_5_1) {
+                QImage alphaImage = softkeyAlpha.toImage();
+                alphaImage.invertPixels();
+                softkeyAlpha = QPixmap::fromImage(alphaImage);
             }
 
-            CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
-            CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
+            CFbsBitmap* nBitmap = softkeyPixmap.toSymbianCFbsBitmap();
+            CFbsBitmap* nMask = softkeyAlpha.toSymbianCFbsBitmap();
 
             CEikImage* myimage = new (ELeave) CEikImage;
             myimage->SetPicture( nBitmap, nMask ); // nBitmap and nMask ownership transfered
 
             EikSoftkeyImage::SetImage(cba, *myimage, left); // Takes myimage ownership
+            cbaHasImage[position] = true;
             ret = true;
         } else {
             // Restore softkey to text based
-            EikSoftkeyImage::SetLabel(cba, left);
+            if (cbaHasImage[position]) {
+                EikSoftkeyImage::SetLabel(cba, left);
+                cbaHasImage[position] = false;
+            }
         }
     }
-    */
     return ret;
 }
 
@@ -235,7 +288,8 @@
         TPtrC nativeText = qt_QString2TPtrC(text);
         int command = S60_COMMAND_START + position;
         setNativeSoftkey(cba, position, command, nativeText);
-        cba.DimCommand(command, !action->isEnabled());
+        const bool dimmed = !action->isEnabled() && !QSoftKeyManager::isForceEnabledInSofkeys(action);
+        cba.DimCommand(command, dimmed);
         realSoftKeyActions.insert(command, action);
         return true;
     }
@@ -272,7 +326,12 @@
         if (windowType != Qt::Dialog && windowType != Qt::Popup) {
             QString text(QSoftKeyManager::tr("Exit"));
             TPtrC nativeText = qt_QString2TPtrC(text);
+            if (cbaHasImage[RSK_POSITION]) {
+                EikSoftkeyImage::SetLabel(&cba, false);
+                cbaHasImage[RSK_POSITION] = false;
+            }
             setNativeSoftkey(cba, RSK_POSITION, EAknSoftkeyExit, nativeText);
+            cba.DimCommand(EAknSoftkeyExit, false);
             return true;
         }
     }
@@ -303,7 +362,6 @@
 
 void QSoftKeyManagerPrivateS60::updateSoftKeys_sys()
 {
-    //bool status = CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog();
     if (skipCbaUpdate())
         return;
 
@@ -346,9 +404,6 @@
             }
             qt_symbian_next_menu_from_action(actionContainer);
             QT_TRAP_THROWING(S60->menuBar()->TryDisplayMenuBarL());
-            // TODO: hack remove, it can happen that IsDisplayingMenuOrDialog return false
-            // in updateSoftKeys_sys, and we will override menu CBA with our own
-            skipNextUpdate = true;
         } else {
             Q_ASSERT(action->softKeyRole() != QAction::NoSoftKey);
             QWidget *actionParent = action->parentWidget();