src/gui/kernel/qsoftkeymanager_s60.cpp
branchRCL_3
changeset 8 3f74d0d4af4c
parent 5 d3bac044e0f0
child 12 25a739ee40f4
equal deleted inserted replaced
6:dee5afe5301f 8:3f74d0d4af4c
    47 #include "private/qt_s60_p.h"
    47 #include "private/qt_s60_p.h"
    48 #include "private/qmenu_p.h"
    48 #include "private/qmenu_p.h"
    49 #include "private/qsoftkeymanager_p.h"
    49 #include "private/qsoftkeymanager_p.h"
    50 #include "private/qsoftkeymanager_s60_p.h"
    50 #include "private/qsoftkeymanager_s60_p.h"
    51 #include "private/qobject_p.h"
    51 #include "private/qobject_p.h"
    52 //#include <eiksoftkeyimage.h>
    52 #include <eiksoftkeyimage.h>
    53 #include <eikcmbut.h>
    53 #include <eikcmbut.h>
    54 
    54 
    55 #ifndef QT_NO_SOFTKEYMANAGER
    55 #ifndef QT_NO_SOFTKEYMANAGER
    56 QT_BEGIN_NAMESPACE
    56 QT_BEGIN_NAMESPACE
    57 
    57 
    58 const int S60_COMMAND_START = 6000;
    58 const int S60_COMMAND_START = 6000;
    59 const int LSK_POSITION = 0;
    59 const int LSK_POSITION = 0;
    60 const int MSK_POSITION = 3;
    60 const int MSK_POSITION = 3;
    61 const int RSK_POSITION = 2;
    61 const int RSK_POSITION = 2;
    62 
    62 
    63 QSoftKeyManagerPrivateS60::QSoftKeyManagerPrivateS60()
    63 QSoftKeyManagerPrivateS60::QSoftKeyManagerPrivateS60() : cbaHasImage(4) // 4 since MSK position index is 3
    64 {
    64 {
    65     cachedCbaIconSize[0] = QSize(0,0);
    65     cachedCbaIconSize[0] = QSize(0,0);
    66     cachedCbaIconSize[1] = QSize(0,0);
    66     cachedCbaIconSize[1] = QSize(0,0);
    67     skipNextUpdate = false;
    67     cachedCbaIconSize[2] = QSize(0,0);
       
    68     cachedCbaIconSize[3] = QSize(0,0);
    68 }
    69 }
    69 
    70 
    70 bool QSoftKeyManagerPrivateS60::skipCbaUpdate()
    71 bool QSoftKeyManagerPrivateS60::skipCbaUpdate()
    71 {
    72 {
    72     // lets not update softkeys if
    73     // Lets not update softkeys if
    73     // 1. We don't have application panes, i.e. cba
    74     // 1. We don't have application panes, i.e. cba
    74     // 2. S60 native dialog or menu is shown
    75     // 2. Our CBA is not active, i.e. S60 native dialog or menu with custom CBA is shown
    75     if (QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes) ||
    76     //    2.1. Except if thre is no current CBA at all and WindowSoftkeysRespondHint is set
    76         CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog() || skipNextUpdate) {
    77 
    77         skipNextUpdate = false;
    78     // Note: Cannot use IsDisplayingMenuOrDialog since CBA update can be triggered before
       
    79     // menu/dialog CBA is actually displayed i.e. it is being costructed.
       
    80     CEikButtonGroupContainer *appUiCba = S60->buttonGroupContainer();
       
    81     // CEikButtonGroupContainer::Current returns 0 if CBA is not visible at all
       
    82     CEikButtonGroupContainer *currentCba = CEikButtonGroupContainer::Current();
       
    83     // Check if softkey need to be update even they are not visible
       
    84     bool cbaRespondsWhenInvisible = false;
       
    85     QWidget *window = QApplication::activeWindow();
       
    86     if (window && (window->windowFlags() & Qt::WindowSoftkeysRespondHint))
       
    87         cbaRespondsWhenInvisible = true;
       
    88 
       
    89     if (QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes)
       
    90             || (appUiCba != currentCba && !cbaRespondsWhenInvisible)) {
    78         return true;
    91         return true;
    79     }
    92     }
    80     return false;
    93     return false;
    81 }
    94 }
    82 
    95 
   147 {
   160 {
   148     // Calling SetCommandL causes CBA redraw
   161     // Calling SetCommandL causes CBA redraw
   149     QT_TRAP_THROWING(cba.SetCommandL(position, command, text));
   162     QT_TRAP_THROWING(cba.SetCommandL(position, command, text));
   150 }
   163 }
   151 
   164 
       
   165 QPoint QSoftKeyManagerPrivateS60::softkeyIconPosition(int position, QSize sourceSize, QSize targetSize)
       
   166 {
       
   167     QPoint iconPosition(0,0);
       
   168     switch( AknLayoutUtils::CbaLocation() )
       
   169         {
       
   170         case AknLayoutUtils::EAknCbaLocationBottom:
       
   171             // RSK must be moved to right, LSK in on correct position by default
       
   172             if (position == RSK_POSITION)
       
   173                 iconPosition.setX(targetSize.width() - sourceSize.width());
       
   174             break;
       
   175         case AknLayoutUtils::EAknCbaLocationRight:
       
   176         case AknLayoutUtils::EAknCbaLocationLeft:
       
   177             // Already in correct position
       
   178         default:
       
   179             break;
       
   180         }
       
   181 
       
   182     // Align horizontally to center
       
   183     iconPosition.setY((targetSize.height() - sourceSize.height()) >> 1);
       
   184     return iconPosition;
       
   185 }
       
   186 
       
   187 QPixmap QSoftKeyManagerPrivateS60::prepareSoftkeyPixmap(QPixmap src, int position, QSize targetSize)
       
   188 {
       
   189     QPixmap target(targetSize);
       
   190     target.fill(Qt::transparent);
       
   191     QPainter p;
       
   192     p.begin(&target);
       
   193     p.drawPixmap(softkeyIconPosition(position, src.size(), targetSize), src);
       
   194     p.end();
       
   195     return target;
       
   196 }
       
   197 
   152 bool QSoftKeyManagerPrivateS60::isOrientationLandscape()
   198 bool QSoftKeyManagerPrivateS60::isOrientationLandscape()
   153 {
   199 {
   154     // Hard to believe that there is no public API in S60 to
   200     // Hard to believe that there is no public API in S60 to
   155     // get current orientation. This workaround works with currently supported resolutions
   201     // get current orientation. This workaround works with currently supported resolutions
   156     return  S60->screenHeightInPixels <  S60->screenWidthInPixels;
   202     return  S60->screenHeightInPixels <  S60->screenWidthInPixels;
   157 }
   203 }
   158 
   204 
   159 QSize QSoftKeyManagerPrivateS60::cbaIconSize(CEikButtonGroupContainer *cba, int position)
   205 QSize QSoftKeyManagerPrivateS60::cbaIconSize(CEikButtonGroupContainer *cba, int position)
   160 {
   206 {
   161     Q_UNUSED(cba);
   207 
   162     Q_UNUSED(position);
   208     int index = position;
   163 
   209     index += isOrientationLandscape() ? 0 : 1;
   164     // Will be implemented when EikSoftkeyImage usage license wise is OK
       
   165 /*
       
   166     const int index = isOrientationLandscape() ? 0 : 1;
       
   167     if(cachedCbaIconSize[index].isNull()) {
   210     if(cachedCbaIconSize[index].isNull()) {
   168         // Only way I figured out to get CBA icon size without RnD SDK, was
       
   169         // Only way I figured out to get CBA icon size without RnD SDK, was
   211         // Only way I figured out to get CBA icon size without RnD SDK, was
   170         // to set some dummy icon to CBA first and then ask CBA button CCoeControl::Size()
   212         // to set some dummy icon to CBA first and then ask CBA button CCoeControl::Size()
   171         // The returned value is cached to avoid unnecessary icon setting every time.
   213         // The returned value is cached to avoid unnecessary icon setting every time.
   172         const bool left = (position == LSK_POSITION);
   214         const bool left = (position == LSK_POSITION);
   173         if(position == LSK_POSITION || position == RSK_POSITION) {
   215         if(position == LSK_POSITION || position == RSK_POSITION) {
   176             EikSoftkeyImage::SetImage(cba, *tmpImage, left); // Takes myimage ownership
   218             EikSoftkeyImage::SetImage(cba, *tmpImage, left); // Takes myimage ownership
   177             int command = S60_COMMAND_START + position;
   219             int command = S60_COMMAND_START + position;
   178             setNativeSoftkey(*cba, position, command, KNullDesC());
   220             setNativeSoftkey(*cba, position, command, KNullDesC());
   179             cachedCbaIconSize[index] = qt_TSize2QSize(cba->ControlOrNull(command)->Size());
   221             cachedCbaIconSize[index] = qt_TSize2QSize(cba->ControlOrNull(command)->Size());
   180             EikSoftkeyImage::SetLabel(cba, left);
   222             EikSoftkeyImage::SetLabel(cba, left);
       
   223 
       
   224             if(cachedCbaIconSize[index] == QSize(138,72)) {
       
   225                 // Hack for S60 5.0 (5800) landscape orientation, which return wrong icon size
       
   226                 cachedCbaIconSize[index] = QSize(60,60);
       
   227             }
   181         }
   228         }
   182     }
   229     }
   183 
   230 
   184     return cachedCbaIconSize[index];
   231     return cachedCbaIconSize[index];
   185 */
       
   186     return QSize();
       
   187 }
   232 }
   188 
   233 
   189 bool QSoftKeyManagerPrivateS60::setSoftkeyImage(CEikButtonGroupContainer *cba,
   234 bool QSoftKeyManagerPrivateS60::setSoftkeyImage(CEikButtonGroupContainer *cba,
   190                                             QAction &action, int position)
   235                                             QAction &action, int position)
   191 {
   236 {
   192     bool ret = false;
   237     bool ret = false;
   193     Q_UNUSED(cba);
   238 
   194     Q_UNUSED(action);
       
   195     Q_UNUSED(position);
       
   196 
       
   197     // Will be implemented when EikSoftkeyImage usage license wise is OK
       
   198     /*
       
   199     const bool left = (position == LSK_POSITION);
   239     const bool left = (position == LSK_POSITION);
   200     if(position == LSK_POSITION || position == RSK_POSITION) {
   240     if(position == LSK_POSITION || position == RSK_POSITION) {
   201         QIcon icon = action.icon();
   241         QIcon icon = action.icon();
   202         if (!icon.isNull()) {
   242         if (!icon.isNull()) {
   203             QPixmap pm = icon.pixmap(cbaIconSize(cba, position));
   243             // Get size of CBA icon area based on button position and orientation
   204             pm = pm.scaled(cbaIconSize(cba, position));
   244             QSize requiredIconSize = cbaIconSize(cba, position);
   205             QBitmap mask = pm.mask();
   245             // Get pixmap out of icon based on preferred size, the aspect ratio is kept
   206             if (mask.isNull()) {
   246             QPixmap pmWihtAspectRatio = icon.pixmap(requiredIconSize);
   207                 mask = QBitmap(pm.size());
   247             // Native softkeys require that pixmap size is exactly the same as requiredIconSize
   208                 mask.fill(Qt::color1);
   248             // prepareSoftkeyPixmap creates a new pixmap with requiredIconSize and blits the 'pmWihtAspectRatio'
   209             }
   249             // to correct location of it
   210 
   250             QPixmap softkeyPixmap = prepareSoftkeyPixmap(pmWihtAspectRatio, position, requiredIconSize);
   211             CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
   251 
   212             CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
   252             QPixmap softkeyAlpha = softkeyPixmap.alphaChannel();
       
   253             // Alpha channel in 5.1 and older devices need to be inverted
       
   254             // TODO: Switch to use toSymbianCFbsBitmap with invert when available
       
   255             if(QSysInfo::s60Version() <= QSysInfo::SV_S60_5_1) {
       
   256                 QImage alphaImage = softkeyAlpha.toImage();
       
   257                 alphaImage.invertPixels();
       
   258                 softkeyAlpha = QPixmap::fromImage(alphaImage);
       
   259             }
       
   260 
       
   261             CFbsBitmap* nBitmap = softkeyPixmap.toSymbianCFbsBitmap();
       
   262             CFbsBitmap* nMask = softkeyAlpha.toSymbianCFbsBitmap();
   213 
   263 
   214             CEikImage* myimage = new (ELeave) CEikImage;
   264             CEikImage* myimage = new (ELeave) CEikImage;
   215             myimage->SetPicture( nBitmap, nMask ); // nBitmap and nMask ownership transfered
   265             myimage->SetPicture( nBitmap, nMask ); // nBitmap and nMask ownership transfered
   216 
   266 
   217             EikSoftkeyImage::SetImage(cba, *myimage, left); // Takes myimage ownership
   267             EikSoftkeyImage::SetImage(cba, *myimage, left); // Takes myimage ownership
       
   268             cbaHasImage[position] = true;
   218             ret = true;
   269             ret = true;
   219         } else {
   270         } else {
   220             // Restore softkey to text based
   271             // Restore softkey to text based
   221             EikSoftkeyImage::SetLabel(cba, left);
   272             if (cbaHasImage[position]) {
   222         }
   273                 EikSoftkeyImage::SetLabel(cba, left);
   223     }
   274                 cbaHasImage[position] = false;
   224     */
   275             }
       
   276         }
       
   277     }
   225     return ret;
   278     return ret;
   226 }
   279 }
   227 
   280 
   228 bool QSoftKeyManagerPrivateS60::setSoftkey(CEikButtonGroupContainer &cba,
   281 bool QSoftKeyManagerPrivateS60::setSoftkey(CEikButtonGroupContainer &cba,
   229                                         QAction::SoftKeyRole role, int position)
   282                                         QAction::SoftKeyRole role, int position)
   233         setSoftkeyImage(&cba, *action, position);
   286         setSoftkeyImage(&cba, *action, position);
   234         QString text = softkeyText(*action);
   287         QString text = softkeyText(*action);
   235         TPtrC nativeText = qt_QString2TPtrC(text);
   288         TPtrC nativeText = qt_QString2TPtrC(text);
   236         int command = S60_COMMAND_START + position;
   289         int command = S60_COMMAND_START + position;
   237         setNativeSoftkey(cba, position, command, nativeText);
   290         setNativeSoftkey(cba, position, command, nativeText);
   238         cba.DimCommand(command, !action->isEnabled());
   291         const bool dimmed = !action->isEnabled() && !QSoftKeyManager::isForceEnabledInSofkeys(action);
       
   292         cba.DimCommand(command, dimmed);
   239         realSoftKeyActions.insert(command, action);
   293         realSoftKeyActions.insert(command, action);
   240         return true;
   294         return true;
   241     }
   295     }
   242     return false;
   296     return false;
   243 }
   297 }
   270         }
   324         }
   271 
   325 
   272         if (windowType != Qt::Dialog && windowType != Qt::Popup) {
   326         if (windowType != Qt::Dialog && windowType != Qt::Popup) {
   273             QString text(QSoftKeyManager::tr("Exit"));
   327             QString text(QSoftKeyManager::tr("Exit"));
   274             TPtrC nativeText = qt_QString2TPtrC(text);
   328             TPtrC nativeText = qt_QString2TPtrC(text);
       
   329             if (cbaHasImage[RSK_POSITION]) {
       
   330                 EikSoftkeyImage::SetLabel(&cba, false);
       
   331                 cbaHasImage[RSK_POSITION] = false;
       
   332             }
   275             setNativeSoftkey(cba, RSK_POSITION, EAknSoftkeyExit, nativeText);
   333             setNativeSoftkey(cba, RSK_POSITION, EAknSoftkeyExit, nativeText);
       
   334             cba.DimCommand(EAknSoftkeyExit, false);
   276             return true;
   335             return true;
   277         }
   336         }
   278     }
   337     }
   279     return false;
   338     return false;
   280 }
   339 }
   301     }
   360     }
   302 }
   361 }
   303 
   362 
   304 void QSoftKeyManagerPrivateS60::updateSoftKeys_sys()
   363 void QSoftKeyManagerPrivateS60::updateSoftKeys_sys()
   305 {
   364 {
   306     //bool status = CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog();
       
   307     if (skipCbaUpdate())
   365     if (skipCbaUpdate())
   308         return;
   366         return;
   309 
   367 
   310     CEikButtonGroupContainer *nativeContainer = S60->buttonGroupContainer();
   368     CEikButtonGroupContainer *nativeContainer = S60->buttonGroupContainer();
   311     Q_ASSERT_X(nativeContainer, Q_FUNC_INFO, "Native CBA does not exist!");
   369     Q_ASSERT_X(nativeContainer, Q_FUNC_INFO, "Native CBA does not exist!");
   344                 v.setValue(actionContainer);
   402                 v.setValue(actionContainer);
   345                 action->setProperty("_q_action_widget", v);
   403                 action->setProperty("_q_action_widget", v);
   346             }
   404             }
   347             qt_symbian_next_menu_from_action(actionContainer);
   405             qt_symbian_next_menu_from_action(actionContainer);
   348             QT_TRAP_THROWING(S60->menuBar()->TryDisplayMenuBarL());
   406             QT_TRAP_THROWING(S60->menuBar()->TryDisplayMenuBarL());
   349             // TODO: hack remove, it can happen that IsDisplayingMenuOrDialog return false
       
   350             // in updateSoftKeys_sys, and we will override menu CBA with our own
       
   351             skipNextUpdate = true;
       
   352         } else {
   407         } else {
   353             Q_ASSERT(action->softKeyRole() != QAction::NoSoftKey);
   408             Q_ASSERT(action->softKeyRole() != QAction::NoSoftKey);
   354             QWidget *actionParent = action->parentWidget();
   409             QWidget *actionParent = action->parentWidget();
   355             Q_ASSERT_X(actionParent, Q_FUNC_INFO, "No parent set for softkey action!");
   410             Q_ASSERT_X(actionParent, Q_FUNC_INFO, "No parent set for softkey action!");
   356             if (actionParent->isEnabled()) {
   411             if (actionParent->isEnabled()) {