/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qs60style_p.h" #include "qapplication.h" #include "qpainter.h" #include "qstyleoption.h" #include "qevent.h" #include "qpixmapcache.h" #include "qcalendarwidget.h" #include "qdial.h" #include "qdialog.h" #include "qmessagebox.h" #include "qgroupbox.h" #include "qheaderview.h" #include "qlist.h" #include "qlistwidget.h" #include "qlistview.h" #include "qmenu.h" #include "qmenubar.h" #include "qpushbutton.h" #include "qscrollarea.h" #include "qscrollbar.h" #include "qtabbar.h" #include "qtableview.h" #include "qtextedit.h" #include "qtoolbar.h" #include "qtoolbutton.h" #include "qfocusframe.h" #include "qformlayout.h" #include "qradiobutton.h" #include "qcheckbox.h" #include "qdesktopwidget.h" #include "qprogressbar.h" #include "private/qtoolbarextension_p.h" #include "private/qcombobox_p.h" #include "private/qwidget_p.h" #include "private/qapplication_p.h" #if !defined(QT_NO_STYLE_S60) || defined(QT_PLUGIN) QT_BEGIN_NAMESPACE // from text/qfont.cpp extern Q_GUI_EXPORT int qt_defaultDpiY(); const QS60StylePrivate::SkinElementFlags QS60StylePrivate::KDefaultSkinElementFlags = SkinElementFlags(SF_PointNorth | SF_StateEnabled); static const qreal goldenRatio = 1.618; const layoutHeader QS60StylePrivate::m_layoutHeaders[] = { // *** generated layout data *** {240,320,1,19,"QVGA Landscape"}, {320,240,1,19,"QVGA Portrait"}, {360,640,1,19,"NHD Landscape"}, {640,360,1,19,"NHD Portrait"}, {352,800,1,12,"E90 Landscape"} // *** End of generated data *** }; const int QS60StylePrivate::m_numberOfLayouts = (int)sizeof(QS60StylePrivate::m_layoutHeaders)/sizeof(QS60StylePrivate::m_layoutHeaders[0]); const short QS60StylePrivate::data[][MAX_PIXELMETRICS] = { // *** generated pixel metrics *** {5,0,-909,0,0,2,0,0,-1,7,12,22,15,15,7,198,-909,-909,-909,20,13,2,0,0,21,7,18,30,3,3,1,-909,-909,0,1,0,0,12,20,15,15,18,18,1,115,18,0,-909,-909,-909,-909,0,0,16,2,-909,0,0,-909,16,-909,-909,-909,-909,32,18,55,24,55,4,4,4,9,13,-909,5,51,11,5,0,3,3,6,8,3,3,-909,2,-909,-909,-909,-909,5,5,3,1,106}, {5,0,-909,0,0,1,0,0,-1,8,14,22,15,15,7,164,-909,-909,-909,19,15,2,0,0,21,8,27,28,4,4,1,-909,-909,0,7,6,0,13,23,17,17,21,21,7,115,21,0,-909,-909,-909,-909,0,0,15,1,-909,0,0,-909,15,-909,-909,-909,-909,32,21,65,27,65,3,3,5,10,15,-909,5,58,13,5,0,4,4,7,9,4,4,-909,2,-909,-909,-909,-909,6,6,3,1,106}, {7,0,-909,0,0,2,0,0,-1,25,69,46,37,37,9,258,-909,-909,-909,23,19,26,0,0,32,25,72,44,5,5,2,-909,-909,0,7,21,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,25,2,-909,0,0,-909,25,-909,-909,-909,-909,87,27,77,35,77,13,13,6,8,19,-909,7,74,19,7,0,5,5,8,12,5,5,-909,3,-909,-909,-909,-909,7,7,3,1,135}, {7,0,-909,0,0,2,0,0,-1,25,68,46,37,37,9,258,-909,-909,-909,31,19,6,0,0,32,25,60,52,5,5,2,-909,-909,0,7,32,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,26,2,-909,0,0,-909,26,-909,-909,-909,-909,87,27,96,35,96,12,12,6,8,19,-909,7,74,22,7,0,5,5,8,12,5,5,-909,3,-909,-909,-909,-909,7,7,3,1,135}, {7,0,-909,0,0,2,0,0,-1,10,20,27,18,18,9,301,-909,-909,-909,29,18,5,0,0,35,7,32,30,5,5,2,-909,-909,0,2,8,0,16,28,21,21,26,26,2,170,26,0,-909,-909,-909,-909,0,0,21,6,-909,0,0,-909,-909,-909,-909,-909,-909,54,26,265,34,265,5,5,6,3,18,-909,7,72,19,7,0,5,6,8,11,6,5,-909,2,-909,-909,-909,-909,5,5,3,1,106} // *** End of generated data *** }; const short *QS60StylePrivate::m_pmPointer = QS60StylePrivate::data[0]; // theme background texture QPixmap *QS60StylePrivate::m_background = 0; // theme palette QPalette *QS60StylePrivate::m_themePalette = 0; qint64 QS60StylePrivate::m_webPaletteKey = 0; QPointer QS60StylePrivate::m_pressedWidget = 0; const struct QS60StylePrivate::frameElementCenter QS60StylePrivate::m_frameElementsData[] = { {SE_ButtonNormal, QS60StyleEnums::SP_QsnFrButtonTbCenter}, {SE_ButtonPressed, QS60StyleEnums::SP_QsnFrButtonTbCenterPressed}, {SE_FrameLineEdit, QS60StyleEnums::SP_QsnFrInputCenter}, {SE_ListHighlight, QS60StyleEnums::SP_QsnFrListCenter}, {SE_PopupBackground, QS60StyleEnums::SP_QsnFrPopupCenter}, {SE_SettingsList, QS60StyleEnums::SP_QsnFrSetOptCenter}, {SE_TableItem, QS60StyleEnums::SP_QsnFrCaleCenter}, {SE_TableHeaderItem, QS60StyleEnums::SP_QsnFrCaleHeadingCenter}, {SE_ToolTip, QS60StyleEnums::SP_QsnFrPopupPreviewCenter}, {SE_ToolBar, QS60StyleEnums::SP_QsnFrPopupSubCenter}, {SE_ToolBarButton, QS60StyleEnums::SP_QgnFrSctrlButtonCenter}, {SE_ToolBarButtonPressed, QS60StyleEnums::SP_QgnFrSctrlButtonCenterPressed}, {SE_PanelBackground, QS60StyleEnums::SP_QsnFrSetOptCenter}, {SE_ButtonInactive, QS60StyleEnums::SP_QsnFrButtonCenterInactive}, {SE_Editor, QS60StyleEnums::SP_QsnFrInputCenter}, {SE_TableItemPressed, QS60StyleEnums::SP_QsnFrGridCenterPressed}, {SE_ListItemPressed, QS60StyleEnums::SP_QsnFrListCenterPressed}, }; static const int frameElementsCount = int(sizeof(QS60StylePrivate::m_frameElementsData)/sizeof(QS60StylePrivate::m_frameElementsData[0])); const int KNotFound = -909; const double KTabFontMul = 0.72; QS60StylePrivate::~QS60StylePrivate() { clearCaches(); //deletes also background image deleteThemePalette(); } void QS60StylePrivate::drawSkinElement(SkinElements element, QPainter *painter, const QRect &rect, SkinElementFlags flags) { switch (element) { case SE_ButtonNormal: drawFrame(SF_ButtonNormal, painter, rect, flags | SF_PointNorth); break; case SE_ButtonPressed: drawFrame(SF_ButtonPressed, painter, rect, flags | SF_PointNorth); break; case SE_FrameLineEdit: drawFrame(SF_FrameLineEdit, painter, rect, flags | SF_PointNorth); break; case SE_ProgressBarGrooveHorizontal: drawRow(QS60StyleEnums::SP_QgnGrafBarFrameSideL, QS60StyleEnums::SP_QgnGrafBarFrameCenter, QS60StyleEnums::SP_QgnGrafBarFrameSideR, Qt::Horizontal, painter, rect, flags | SF_PointNorth); break; case SE_ProgressBarGrooveVertical: drawRow(QS60StyleEnums::SP_QgnGrafBarFrameSideL, QS60StyleEnums::SP_QgnGrafBarFrameCenter, QS60StyleEnums::SP_QgnGrafBarFrameSideR, Qt::Vertical, painter, rect, flags | SF_PointEast); break; case SE_ProgressBarIndicatorHorizontal: drawPart(QS60StyleEnums::SP_QgnGrafBarProgress, painter, rect, flags | SF_PointNorth); break; case SE_ProgressBarIndicatorVertical: drawPart(QS60StyleEnums::SP_QgnGrafBarProgress, painter, rect, flags | SF_PointWest); break; case SE_ScrollBarGrooveHorizontal: drawRow(QS60StyleEnums::SP_QsnCpScrollBgBottom, QS60StyleEnums::SP_QsnCpScrollBgMiddle, QS60StyleEnums::SP_QsnCpScrollBgTop, Qt::Horizontal, painter, rect, flags | SF_PointEast); break; case SE_ScrollBarGrooveVertical: drawRow(QS60StyleEnums::SP_QsnCpScrollBgTop, QS60StyleEnums::SP_QsnCpScrollBgMiddle, QS60StyleEnums::SP_QsnCpScrollBgBottom, Qt::Vertical, painter, rect, flags | SF_PointNorth); break; case SE_ScrollBarHandleHorizontal: drawRow(QS60StyleEnums::SP_QsnCpScrollHandleBottom, QS60StyleEnums::SP_QsnCpScrollHandleMiddle, QS60StyleEnums::SP_QsnCpScrollHandleTop, Qt::Horizontal, painter, rect, flags | SF_PointEast); break; case SE_ScrollBarHandleVertical: drawRow(QS60StyleEnums::SP_QsnCpScrollHandleTop, QS60StyleEnums::SP_QsnCpScrollHandleMiddle, QS60StyleEnums::SP_QsnCpScrollHandleBottom, Qt::Vertical, painter, rect, flags | SF_PointNorth); break; case SE_SliderHandleHorizontal: drawPart(QS60StyleEnums::SP_QgnGrafNsliderMarker, painter, rect, flags | SF_PointNorth); break; case SE_SliderHandleVertical: drawPart(QS60StyleEnums::SP_QgnGrafNsliderMarker, painter, rect, flags | SF_PointEast); break; case SE_SliderHandleSelectedHorizontal: drawPart(QS60StyleEnums::SP_QgnGrafNsliderMarkerSelected, painter, rect, flags | SF_PointNorth); break; case SE_SliderHandleSelectedVertical: drawPart(QS60StyleEnums::SP_QgnGrafNsliderMarkerSelected, painter, rect, flags | SF_PointEast); break; case SE_SliderGrooveVertical: drawRow(QS60StyleEnums::SP_QgnGrafNsliderEndLeft, QS60StyleEnums::SP_QgnGrafNsliderMiddle, QS60StyleEnums::SP_QgnGrafNsliderEndRight, Qt::Vertical, painter, rect, flags | SF_PointEast); break; case SE_SliderGrooveHorizontal: drawRow(QS60StyleEnums::SP_QgnGrafNsliderEndLeft, QS60StyleEnums::SP_QgnGrafNsliderMiddle, QS60StyleEnums::SP_QgnGrafNsliderEndRight, Qt::Horizontal, painter, rect, flags | SF_PointNorth); break; case SE_TabBarTabEastActive: drawRow(QS60StyleEnums::SP_QgnGrafTabActiveL, QS60StyleEnums::SP_QgnGrafTabActiveM, QS60StyleEnums::SP_QgnGrafTabActiveR, Qt::Vertical, painter, rect, flags | SF_PointEast); break; case SE_TabBarTabEastInactive: drawRow(QS60StyleEnums::SP_QgnGrafTabPassiveL, QS60StyleEnums::SP_QgnGrafTabPassiveM, QS60StyleEnums::SP_QgnGrafTabPassiveR, Qt::Vertical, painter, rect, flags | SF_PointEast); break; case SE_TabBarTabNorthActive: drawRow(QS60StyleEnums::SP_QgnGrafTabActiveL, QS60StyleEnums::SP_QgnGrafTabActiveM, QS60StyleEnums::SP_QgnGrafTabActiveR, Qt::Horizontal, painter, rect, flags | SF_PointNorth); break; case SE_TabBarTabNorthInactive: drawRow(QS60StyleEnums::SP_QgnGrafTabPassiveL, QS60StyleEnums::SP_QgnGrafTabPassiveM, QS60StyleEnums::SP_QgnGrafTabPassiveR, Qt::Horizontal, painter, rect, flags | SF_PointNorth); break; case SE_TabBarTabSouthActive: drawRow(QS60StyleEnums::SP_QgnGrafTabActiveR, QS60StyleEnums::SP_QgnGrafTabActiveM, QS60StyleEnums::SP_QgnGrafTabActiveL, Qt::Horizontal, painter, rect, flags | SF_PointSouth); break; case SE_TabBarTabSouthInactive: drawRow(QS60StyleEnums::SP_QgnGrafTabPassiveR, QS60StyleEnums::SP_QgnGrafTabPassiveM, QS60StyleEnums::SP_QgnGrafTabPassiveL, Qt::Horizontal, painter, rect, flags | SF_PointSouth); break; case SE_TabBarTabWestActive: drawRow(QS60StyleEnums::SP_QgnGrafTabActiveR, QS60StyleEnums::SP_QgnGrafTabActiveM, QS60StyleEnums::SP_QgnGrafTabActiveL, Qt::Vertical, painter, rect, flags | SF_PointWest); break; case SE_TabBarTabWestInactive: drawRow(QS60StyleEnums::SP_QgnGrafTabPassiveR, QS60StyleEnums::SP_QgnGrafTabPassiveM, QS60StyleEnums::SP_QgnGrafTabPassiveL, Qt::Vertical, painter, rect, flags | SF_PointWest); break; case SE_ListHighlight: drawFrame(SF_ListHighlight, painter, rect, flags | SF_PointNorth); break; case SE_PopupBackground: drawFrame(SF_PopupBackground, painter, rect, flags | SF_PointNorth); break; case SE_SettingsList: drawFrame(SF_SettingsList, painter, rect, flags | SF_PointNorth); break; case SE_TableItem: drawFrame(SF_TableItem, painter, rect, flags | SF_PointNorth); break; case SE_TableHeaderItem: drawFrame(SF_TableHeaderItem, painter, rect, flags | SF_PointNorth); break; case SE_ToolTip: drawFrame(SF_ToolTip, painter, rect, flags | SF_PointNorth); break; case SE_ToolBar: drawFrame(SF_ToolBar, painter, rect, flags | SF_PointNorth); break; case SE_ToolBarButton: drawFrame(SF_ToolBarButton, painter, rect, flags | SF_PointNorth); break; case SE_ToolBarButtonPressed: drawFrame(SF_ToolBarButtonPressed, painter, rect, flags | SF_PointNorth); break; case SE_PanelBackground: drawFrame(SF_PanelBackground, painter, rect, flags | SF_PointNorth); break; case SE_ScrollBarHandlePressedHorizontal: drawRow(QS60StyleEnums::SP_QsnCpScrollHandleBottomPressed, QS60StyleEnums::SP_QsnCpScrollHandleMiddlePressed, QS60StyleEnums::SP_QsnCpScrollHandleTopPressed, Qt::Horizontal, painter, rect, flags | SF_PointEast); break; case SE_ScrollBarHandlePressedVertical: drawRow(QS60StyleEnums::SP_QsnCpScrollHandleTopPressed, QS60StyleEnums::SP_QsnCpScrollHandleMiddlePressed, QS60StyleEnums::SP_QsnCpScrollHandleBottomPressed, Qt::Vertical, painter, rect, flags | SF_PointNorth); break; case SE_ButtonInactive: drawFrame(SF_ButtonInactive, painter, rect, flags | SF_PointNorth); break; case SE_Editor: drawFrame(SF_FrameLineEdit, painter, rect, flags | SF_PointNorth); break; case SE_DropArea: drawPart(QS60StyleEnums::SP_QgnGrafOrgBgGrid, painter, rect, flags | SF_PointNorth); break; case SE_TableItemPressed: drawFrame(SF_TableItemPressed, painter, rect, flags | SF_PointNorth); break; case SE_ListItemPressed: drawFrame(SF_ListItemPressed, painter, rect, flags | SF_PointNorth); break; default: break; } } void QS60StylePrivate::drawSkinPart(QS60StyleEnums::SkinParts part, QPainter *painter, const QRect &rect, SkinElementFlags flags) { drawPart(part, painter, rect, flags); } short QS60StylePrivate::pixelMetric(int metric) { //If it is a custom value, need to strip away the base to map to internal //pixel metric value table if (metric & QStyle::PM_CustomBase) { metric -= QStyle::PM_CustomBase; metric += MAX_NON_CUSTOM_PIXELMETRICS - 1; } Q_ASSERT(metric < MAX_PIXELMETRICS); const short returnValue = m_pmPointer[metric]; return returnValue; } QColor QS60StylePrivate::stateColor(const QColor &color, const QStyleOption *option) { QColor retColor (color); if (option && !(option->state & QStyle::State_Enabled)) { QColor hsvColor = retColor.toHsv(); int colorSat = hsvColor.saturation(); int colorVal = hsvColor.value(); colorSat = (colorSat != 0) ? (colorSat >> 1) : 128; colorVal = (colorVal != 0) ? (colorVal >> 1) : 128; hsvColor.setHsv(hsvColor.hue(), colorSat, colorVal); retColor = hsvColor.toRgb(); } return retColor; } QColor QS60StylePrivate::lighterColor(const QColor &baseColor) { QColor result(baseColor); bool modifyColor = false; if (result.saturation() == 0) { result.setHsv(result.hue(), 128, result.value()); modifyColor = true; } if (result.value() == 0) { result.setHsv(result.hue(), result.saturation(), 128); modifyColor = true; } if (modifyColor) result = result.lighter(175); else result = result.lighter(225); return result; } bool QS60StylePrivate::drawsOwnThemeBackground(const QWidget *widget) { return (widget ? (widget->windowType() == Qt::Dialog) : false); } QFont QS60StylePrivate::s60Font( QS60StyleEnums::FontCategories fontCategory, int pointSize, bool resolveFontSize) const { QFont result; int actualPointSize = pointSize; if (actualPointSize <= 0) { const QFont appFont = QApplication::font(); actualPointSize = appFont.pointSize(); if (actualPointSize <= 0) actualPointSize = appFont.pixelSize() * 72 / qt_defaultDpiY(); } Q_ASSERT(actualPointSize > 0); const QPair key(fontCategory, actualPointSize); if (!m_mappedFontsCache.contains(key)) { result = s60Font_specific(fontCategory, actualPointSize, resolveFontSize); m_mappedFontsCache.insert(key, result); } else { result = m_mappedFontsCache.value(key); if (result.pointSize() != actualPointSize) result.setPointSize(actualPointSize); } return result; } void QS60StylePrivate::clearCaches(CacheClearReason reason) { switch(reason){ case CC_LayoutChange: // when layout changes, the colors remain in cache, but graphics and fonts can change m_mappedFontsCache.clear(); QPixmapCache::clear(); break; case CC_ThemeChange: m_colorCache.clear(); QPixmapCache::clear(); deleteBackground(); break; case CC_UndefinedChange: default: m_colorCache.clear(); m_mappedFontsCache.clear(); QPixmapCache::clear(); deleteBackground(); break; } } // Since S60Style has 'button' and 'tooltip' as a graphic, we don't have any native color which to use // for QPalette::Button and QPalette::ToolTipBase. Therefore S60Style needs to guesstimate // palette colors by calculating average rgb values for button pixels. // Returns Qt::black if there is an issue with the graphics (image is NULL, or no bits() found). QColor QS60StylePrivate::colorFromFrameGraphics(SkinFrameElements frame) const { const bool cachedColorExists = m_colorCache.contains(frame); if (!cachedColorExists) { const int frameCornerWidth = pixelMetric(PM_FrameCornerWidth); const int frameCornerHeight = pixelMetric(PM_FrameCornerHeight); Q_ASSERT(2 * frameCornerWidth < 32); Q_ASSERT(2 * frameCornerHeight < 32); const QImage frameImage = QS60StylePrivate::frame(frame, QSize(32, 32)).toImage(); Q_ASSERT(frameImage.bytesPerLine() > 0); if (frameImage.isNull()) return Qt::black; const QRgb *pixelRgb = (const QRgb*)frameImage.bits(); const int pixels = frameImage.byteCount()/sizeof(QRgb); int estimatedRed = 0; int estimatedGreen = 0; int estimatedBlue = 0; int skips = 0; int estimations = 0; const int topBorderLastPixel = frameCornerHeight*frameImage.width() - 1; const int bottomBorderFirstPixel = frameImage.width() * frameImage.height() - frameCornerHeight*frameImage.width() - 1; const int rightBorderFirstPixel = frameImage.width() - frameCornerWidth; const int leftBorderLastPixel = frameCornerWidth; while ((skips + estimations) < pixels) { if ((skips + estimations) > topBorderLastPixel && (skips + estimations) < bottomBorderFirstPixel) { for (int rowIndex = 0; rowIndex < frameImage.width(); rowIndex++) { if (rowIndex > leftBorderLastPixel && rowIndex < rightBorderFirstPixel) { estimatedRed += qRed(*pixelRgb); estimatedGreen += qGreen(*pixelRgb); estimatedBlue += qBlue(*pixelRgb); } pixelRgb++; estimations++; } } else { pixelRgb++; skips++; } } QColor frameColor(estimatedRed/estimations, estimatedGreen/estimations, estimatedBlue/estimations); m_colorCache.insert(frame, frameColor); return !estimations ? Qt::black : frameColor; } else { return m_colorCache.value(frame); } } void QS60StylePrivate::setThemePalette(QApplication *app) const { Q_UNUSED(app) QPalette widgetPalette = QPalette(Qt::white); setThemePalette(&widgetPalette); } QPalette* QS60StylePrivate::themePalette() { return m_themePalette; } void QS60StylePrivate::setBackgroundTexture(QApplication *app) const { Q_UNUSED(app) QPalette applicationPalette = QApplication::palette(); applicationPalette.setBrush(QPalette::Window, backgroundTexture()); setThemePalette(&applicationPalette); } void QS60StylePrivate::deleteBackground() { if (m_background) { delete m_background; m_background = 0; } } void QS60StylePrivate::setCurrentLayout(int index) { m_pmPointer = data[index]; } void QS60StylePrivate::drawPart(QS60StyleEnums::SkinParts skinPart, QPainter *painter, const QRect &rect, SkinElementFlags flags) { static const bool doCache = #if defined(Q_WS_S60) // Freezes on 3.1. Anyways, caching is only really needed on touch UI !(QSysInfo::s60Version() == QSysInfo::SV_S60_3_1 || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2); #else true; #endif const QPixmap skinPartPixMap((doCache ? cachedPart : part)(skinPart, rect.size(), painter, flags)); if (!skinPartPixMap.isNull()) painter->drawPixmap(rect.topLeft(), skinPartPixMap); } void QS60StylePrivate::drawFrame(SkinFrameElements frameElement, QPainter *painter, const QRect &rect, SkinElementFlags flags) { static const bool doCache = #if defined(Q_WS_S60) // Freezes on 3.1. Anyways, caching is only really needed on touch UI !(QSysInfo::s60Version() == QSysInfo::SV_S60_3_1 || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2); #else true; #endif const QPixmap frameElementPixMap((doCache ? cachedFrame : frame)(frameElement, rect.size(), flags)); if (!frameElementPixMap.isNull()) painter->drawPixmap(rect.topLeft(), frameElementPixMap); } void QS60StylePrivate::drawRow(QS60StyleEnums::SkinParts start, QS60StyleEnums::SkinParts middle, QS60StyleEnums::SkinParts end, Qt::Orientation orientation, QPainter *painter, const QRect &rect, SkinElementFlags flags) { QSize startEndSize(partSize(start, flags)); startEndSize.scale(rect.size(), Qt::KeepAspectRatio); QRect startRect = QRect(rect.topLeft(), startEndSize); QRect middleRect = rect; QRect endRect; if (orientation == Qt::Horizontal) { startRect.setHeight(rect.height()); startRect.setWidth(qMin((rect.width() >> 1) - 1, startRect.width())); endRect = startRect.translated(rect.width() - startRect.width(), 0); middleRect.adjust(startRect.width(), 0, -startRect.width(), 0); if (startRect.bottomRight().x() > endRect.topLeft().x()) { const int overlap = (startRect.bottomRight().x() - endRect.topLeft().x()) >> 1; startRect.setWidth(startRect.width() - overlap); endRect.adjust(overlap, 0, 0, 0); } } else { startRect.setWidth(rect.width()); startRect.setHeight(qMin((rect.height() >> 1) - 1, startRect.height())); endRect = startRect.translated(0, rect.height() - startRect.height()); middleRect.adjust(0, startRect.height(), 0, -startRect.height()); if (startRect.topRight().y() > endRect.bottomLeft().y()) { const int overlap = (startRect.topRight().y() - endRect.bottomLeft().y()) >> 1; startRect.setHeight(startRect.height() - overlap); endRect.adjust(0, overlap, 0, 0); } } #if 0 painter->save(); painter->setOpacity(.3); painter->fillRect(startRect, Qt::red); painter->fillRect(middleRect, Qt::green); painter->fillRect(endRect, Qt::blue); painter->restore(); #else drawPart(start, painter, startRect, flags); if (middleRect.isValid()) drawPart(middle, painter, middleRect, flags); drawPart(end, painter, endRect, flags); #endif } QPixmap QS60StylePrivate::cachedPart(QS60StyleEnums::SkinParts part, const QSize &size, QPainter *painter, SkinElementFlags flags) { QPixmap result; const int animationFrame = (flags & SF_Animation) ? currentAnimationFrame(part) : 0; const QString cacheKey = QString::fromLatin1("S60Style: SkinParts=%1 QSize=%2|%3 SkinPartFlags=%4 AnimationFrame=%5") .arg((int)part).arg(size.width()).arg(size.height()).arg((int)flags).arg(animationFrame); if (!QPixmapCache::find(cacheKey, result)) { result = QS60StylePrivate::part(part, size, painter, flags); QPixmapCache::insert(cacheKey, result); } return result; } QPixmap QS60StylePrivate::cachedFrame(SkinFrameElements frame, const QSize &size, SkinElementFlags flags) { QPixmap result; const QString cacheKey = QString::fromLatin1("S60Style: SkinFrameElements=%1 QSize=%2|%3 SkinElementFlags=%4") .arg((int)frame).arg(size.width()).arg(size.height()).arg((int)flags); if (!QPixmapCache::find(cacheKey, result)) { result = QS60StylePrivate::frame(frame, size, flags); QPixmapCache::insert(cacheKey, result); } return result; } void QS60StylePrivate::refreshUI() { QList widgets = QApplication::allWidgets(); for (int i = 0; i < widgets.size(); ++i) { QWidget *widget = widgets.at(i); if (widget == 0) continue; if (widget->style()) { widget->style()->polish(widget); QEvent event(QEvent::StyleChange); qApp->sendEvent(widget, &event); } widget->update(); widget->updateGeometry(); } } void QS60StylePrivate::setFont(QWidget *widget) const { QS60StyleEnums::FontCategories fontCategory = QS60StyleEnums::FC_Undefined; if (!widget) return; if (qobject_cast(widget)){ fontCategory = QS60StyleEnums::FC_Primary; } else if (qobject_cast(widget)){ fontCategory = QS60StyleEnums::FC_Primary; } else if (qobject_cast(widget)){ fontCategory = QS60StyleEnums::FC_Secondary; } else if (qobject_cast(widget)){ fontCategory = QS60StyleEnums::FC_Title; } else if (qobject_cast(widget)){ fontCategory = QS60StyleEnums::FC_Primary; } else if (qobject_cast(widget)){ fontCategory = QS60StyleEnums::FC_Primary; } else if (qobject_cast(widget)){ fontCategory = QS60StyleEnums::FC_Secondary; } if (fontCategory != QS60StyleEnums::FC_Undefined) { const bool resolveFontSize = widget->testAttribute(Qt::WA_SetFont) && (widget->font().resolve() & QFont::SizeResolved); const QFont suggestedFont = s60Font(fontCategory, widget->font().pointSizeF(), resolveFontSize); widget->setFont(suggestedFont); } } void QS60StylePrivate::setThemePalette(QWidget *widget) const { if(!widget) return; //header view and its viewport need to be set 100% transparent button color, since drawing code will //draw transparent theme graphics to table column and row headers. if (qobject_cast(widget)){ QPalette widgetPalette = QApplication::palette(widget); widgetPalette.setColor(QPalette::Active, QPalette::ButtonText, s60Color(QS60StyleEnums::CL_QsnTextColors, 23, 0)); QHeaderView* header = qobject_cast(widget); widgetPalette.setColor(QPalette::Button, Qt::transparent ); if (header->viewport()) header->viewport()->setPalette(widgetPalette); QApplication::setPalette(widgetPalette, "QHeaderView"); } } void QS60StylePrivate::setThemePalette(QPalette *palette) const { if (!palette) return; // basic colors palette->setColor(QPalette::WindowText, s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0)); palette->setColor(QPalette::ButtonText, s60Color(QS60StyleEnums::CL_QsnTextColors, 20, 0)); palette->setColor(QPalette::Text, s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0)); palette->setColor(QPalette::ToolTipText, s60Color(QS60StyleEnums::CL_QsnTextColors, 55, 0)); palette->setColor(QPalette::BrightText, palette->color(QPalette::WindowText).lighter()); palette->setColor(QPalette::HighlightedText, s60Color(QS60StyleEnums::CL_QsnTextColors, 24, 0)); palette->setColor(QPalette::Link, s60Color(QS60StyleEnums::CL_QsnHighlightColors, 3, 0)); palette->setColor(QPalette::LinkVisited, palette->color(QPalette::Link).darker()); palette->setColor(QPalette::Highlight, s60Color(QS60StyleEnums::CL_QsnHighlightColors, 2, 0)); // set background image as a texture brush palette->setBrush(QPalette::Window, backgroundTexture()); // set as transparent so that styled full screen theme background is visible palette->setBrush(QPalette::Base, Qt::transparent); // set button and tooltipbase based on pixel colors const QColor buttonColor = colorFromFrameGraphics(SF_ButtonNormal); palette->setColor(QPalette::Button, buttonColor); const QColor toolTipColor = colorFromFrameGraphics(SF_ToolTip); palette->setColor(QPalette::ToolTipBase, toolTipColor); palette->setColor(QPalette::Light, palette->color(QPalette::Button).lighter()); palette->setColor(QPalette::Dark, palette->color(QPalette::Button).darker()); palette->setColor(QPalette::Midlight, palette->color(QPalette::Button).lighter(125)); palette->setColor(QPalette::Mid, palette->color(QPalette::Button).darker(150)); palette->setColor(QPalette::Shadow, Qt::black); QColor alternateBase = palette->light().color(); alternateBase.setAlphaF(0.8); palette->setColor(QPalette::AlternateBase, alternateBase); QApplication::setPalette(*palette); //calling QApplication::setPalette clears palette hash setThemePaletteHash(palette); storeThemePalette(palette); } void QS60StylePrivate::deleteThemePalette() { if (m_themePalette) { delete m_themePalette; m_themePalette = 0; } } void QS60StylePrivate::storeThemePalette(QPalette *palette) { deleteThemePalette(); //store specified palette for latter use. m_themePalette = new QPalette(*palette); } // set widget specific palettes void QS60StylePrivate::setThemePaletteHash(QPalette *palette) const { if (!palette) return; //store the original palette QPalette widgetPalette = *palette; const QColor mainAreaTextColor = s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0); widgetPalette.setColor(QPalette::WindowText, s60Color(QS60StyleEnums::CL_QsnLineColors, 8, 0)); QApplication::setPalette(widgetPalette, "QSlider"); // return to original palette after each widget widgetPalette = *palette; widgetPalette.setColor(QPalette::Active, QPalette::ButtonText, mainAreaTextColor); widgetPalette.setColor(QPalette::Inactive, QPalette::ButtonText, mainAreaTextColor); const QStyleOption opt; widgetPalette.setColor(QPalette::Disabled, QPalette::ButtonText, s60Color(QS60StyleEnums::CL_QsnTextColors, 6, &opt)); QApplication::setPalette(widgetPalette, "QPushButton"); widgetPalette = *palette; widgetPalette.setColor(QPalette::Active, QPalette::ButtonText, mainAreaTextColor); widgetPalette.setColor(QPalette::Inactive, QPalette::ButtonText, mainAreaTextColor); QApplication::setPalette(widgetPalette, "QToolButton"); widgetPalette = *palette; widgetPalette.setColor(QPalette::Active, QPalette::ButtonText, s60Color(QS60StyleEnums::CL_QsnTextColors, 23, 0)); QApplication::setPalette(widgetPalette, "QHeaderView"); widgetPalette = *palette; widgetPalette.setColor(QPalette::ButtonText, s60Color(QS60StyleEnums::CL_QsnTextColors, 8, 0)); QApplication::setPalette(widgetPalette, "QMenuBar"); widgetPalette = *palette; widgetPalette.setColor(QPalette::Text, s60Color(QS60StyleEnums::CL_QsnTextColors, 22, 0)); widgetPalette.setColor(QPalette::HighlightedText, s60Color(QS60StyleEnums::CL_QsnTextColors, 11, 0)); QApplication::setPalette(widgetPalette, "QMenu"); widgetPalette = *palette; widgetPalette.setColor(QPalette::WindowText, s60Color(QS60StyleEnums::CL_QsnTextColors, 4, 0)); widgetPalette.setColor(QPalette::HighlightedText, s60Color(QS60StyleEnums::CL_QsnTextColors, 3, 0)); QApplication::setPalette(widgetPalette, "QTabBar"); widgetPalette = *palette; widgetPalette.setColor(QPalette::HighlightedText, s60Color(QS60StyleEnums::CL_QsnTextColors, 10, 0)); QApplication::setPalette(widgetPalette, "QListView"); widgetPalette = *palette; widgetPalette.setColor(QPalette::Text, s60Color(QS60StyleEnums::CL_QsnTextColors, 22, 0)); widgetPalette.setColor(QPalette::HighlightedText, s60Color(QS60StyleEnums::CL_QsnTextColors, 11, 0)); QApplication::setPalette(widgetPalette, "QTableView"); widgetPalette = *palette; widgetPalette.setColor(QPalette::Text, s60Color(QS60StyleEnums::CL_QsnTextColors, 27, 0)); widgetPalette.setColor(QPalette::HighlightedText, s60Color(QS60StyleEnums::CL_QsnTextColors, 24, 0)); QApplication::setPalette(widgetPalette, "QLineEdit"); QApplication::setPalette(widgetPalette, "QTextEdit"); widgetPalette = *palette; widgetPalette.setColor(QPalette::HighlightedText, s60Color(QS60StyleEnums::CL_QsnTextColors, 24, 0)); QApplication::setPalette(widgetPalette, "QComboBox"); widgetPalette = *palette; widgetPalette.setColor(QPalette::WindowText, s60Color(QS60StyleEnums::CL_QsnTextColors, 7, 0)); widgetPalette.setColor(QPalette::HighlightedText, s60Color(QS60StyleEnums::CL_QsnTextColors, 11, 0)); QApplication::setPalette(widgetPalette, "QRadioButton"); QApplication::setPalette(widgetPalette, "QCheckBox"); widgetPalette = *palette; widgetPalette.setColor(QPalette::WindowText, mainAreaTextColor); widgetPalette.setColor(QPalette::Button, QApplication::palette().color(QPalette::Button)); widgetPalette.setColor(QPalette::Dark, mainAreaTextColor.darker()); widgetPalette.setColor(QPalette::Light, mainAreaTextColor.lighter()); QApplication::setPalette(widgetPalette, "QDial"); widgetPalette = *palette; widgetPalette.setBrush(QPalette::Window, QBrush()); QApplication::setPalette(widgetPalette, "QScrollArea"); widgetPalette = *palette; //Webpages should not use S60 theme colors as they are designed to work //with themeBackground and do not generally mesh well with web page backgrounds. QPalette webPalette = *palette; webPalette.setColor(QPalette::WindowText, Qt::black); webPalette.setColor(QPalette::Text, Qt::black); webPalette.setBrush(QPalette::Base, Qt::white); QApplication::setPalette(webPalette, "QWebView"); QApplication::setPalette(webPalette, "QGraphicsWebView"); m_webPaletteKey = webPalette.cacheKey(); } QSize QS60StylePrivate::partSize(QS60StyleEnums::SkinParts part, SkinElementFlags flags) { QSize result(20, 20); switch (part) { case QS60StyleEnums::SP_QgnGrafBarProgress: result.setWidth(pixelMetric(QStyle::PM_ProgressBarChunkWidth)); break; case QS60StyleEnums::SP_QgnGrafTabActiveM: case QS60StyleEnums::SP_QgnGrafTabPassiveM: case QS60StyleEnums::SP_QgnGrafTabActiveR: case QS60StyleEnums::SP_QgnGrafTabPassiveR: case QS60StyleEnums::SP_QgnGrafTabPassiveL: case QS60StyleEnums::SP_QgnGrafTabActiveL: //Returned QSize for tabs must not be square, but narrow rectangle with width:height //ratio of 1:2 for horizontal tab bars (and 2:1 for vertical ones). result.setWidth(result.height() >> 1); break; case QS60StyleEnums::SP_QgnGrafNsliderEndLeft: case QS60StyleEnums::SP_QgnGrafNsliderEndRight: case QS60StyleEnums::SP_QgnGrafNsliderMiddle: break; case QS60StyleEnums::SP_QgnGrafNsliderMarker: case QS60StyleEnums::SP_QgnGrafNsliderMarkerSelected: result.scale(pixelMetric(QStyle::PM_SliderLength), pixelMetric(QStyle::PM_SliderControlThickness), Qt::IgnoreAspectRatio); break; case QS60StyleEnums::SP_QgnGrafBarFrameSideL: case QS60StyleEnums::SP_QgnGrafBarFrameSideR: result.setWidth(pixelMetric(PM_FrameCornerWidth)); break; case QS60StyleEnums::SP_QsnCpScrollHandleTopPressed: case QS60StyleEnums::SP_QsnCpScrollBgBottom: case QS60StyleEnums::SP_QsnCpScrollBgTop: case QS60StyleEnums::SP_QsnCpScrollHandleBottom: case QS60StyleEnums::SP_QsnCpScrollHandleTop: case QS60StyleEnums::SP_QsnCpScrollHandleBottomPressed: result.setHeight(pixelMetric(QStyle::PM_ScrollBarExtent)); result.setWidth(pixelMetric(QStyle::PM_ScrollBarExtent)); break; case QS60StyleEnums::SP_QsnCpScrollHandleMiddlePressed: case QS60StyleEnums::SP_QsnCpScrollBgMiddle: case QS60StyleEnums::SP_QsnCpScrollHandleMiddle: result.setHeight(pixelMetric(QStyle::PM_ScrollBarExtent)); result.setWidth(pixelMetric(QStyle::PM_ScrollBarSliderMin)); break; default: // Generic frame part size gathering. for (int i = 0; i < frameElementsCount; ++i) { switch (m_frameElementsData[i].center - part) { case 8: /* CornerTl */ case 7: /* CornerTr */ case 6: /* CornerBl */ case 5: /* CornerBr */ result.setWidth(pixelMetric(PM_FrameCornerWidth)); // Falltrough intended... case 4: /* SideT */ case 3: /* SideB */ result.setHeight(pixelMetric(PM_FrameCornerHeight)); break; case 2: /* SideL */ case 1: /* SideR */ result.setWidth(pixelMetric(PM_FrameCornerWidth)); break; case 0: /* center */ default: break; } } break; } if (flags & (SF_PointEast | SF_PointWest)) { const int temp = result.width(); result.setWidth(result.height()); result.setHeight(temp); } return result; } bool QS60StylePrivate::canDrawThemeBackground(const QBrush &backgroundBrush, const QWidget *widget) { // Always return true for web pages. if (widget && m_webPaletteKey == QApplication::palette(widget).cacheKey()) return true; //If brush is not changed from style's default values, draw theme graphics. return (backgroundBrush.color() == Qt::transparent || backgroundBrush.style() == Qt::NoBrush) ? true : false; } bool QS60StylePrivate::isWidgetPressed(const QWidget *widget) { return (widget && widget == m_pressedWidget); } /*! \class QS60Style \brief The QS60Style class provides a look and feel suitable for applications on S60. \since 4.6 \ingroup appearance \sa QMacStyle, QWindowsStyle, QWindowsXPStyle, QWindowsVistaStyle, QPlastiqueStyle, QCleanlooksStyle, QMotifStyle */ /*! Destroys the style. */ QS60Style::~QS60Style() { } /*! \reimp */ void QS60Style::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const { const QS60StylePrivate::SkinElementFlags flags = (option->state & State_Enabled) ? QS60StylePrivate::SF_StateEnabled : QS60StylePrivate::SF_StateDisabled; SubControls sub = option->subControls; switch (control) { #ifndef QT_NO_SCROLLBAR case CC_ScrollBar: if (const QStyleOptionSlider *optionSlider = qstyleoption_cast(option)) { const bool horizontal = optionSlider->orientation == Qt::Horizontal; const QRect scrollBarSlider = subControlRect(control, optionSlider, SC_ScrollBarSlider, widget); const QRect grooveRect = subControlRect(control, optionSlider, SC_ScrollBarGroove, widget); const QS60StylePrivate::SkinElements grooveElement = horizontal ? QS60StylePrivate::SE_ScrollBarGrooveHorizontal : QS60StylePrivate::SE_ScrollBarGrooveVertical; QS60StylePrivate::drawSkinElement(grooveElement, painter, grooveRect, flags); const SubControls subControls = optionSlider->subControls; // select correct slider (horizontal/vertical/pressed) const bool sliderPressed = ((optionSlider->state & State_Sunken) && (subControls & SC_ScrollBarSlider)); const QS60StylePrivate::SkinElements handleElement = horizontal ? ( sliderPressed ? QS60StylePrivate::SE_ScrollBarHandlePressedHorizontal : QS60StylePrivate::SE_ScrollBarHandleHorizontal ) : ( sliderPressed ? QS60StylePrivate::SE_ScrollBarHandlePressedVertical : QS60StylePrivate::SE_ScrollBarHandleVertical); QS60StylePrivate::drawSkinElement(handleElement, painter, scrollBarSlider, flags); } break; #endif // QT_NO_SCROLLBAR #ifndef QT_NO_SLIDER case CC_Slider: if (const QStyleOptionSlider *optionSlider = qstyleoption_cast(option)) { const QRect sliderGroove = subControlRect(control, optionSlider, SC_SliderGroove, widget); const bool horizontal = optionSlider->orientation == Qt::Horizontal; //Highlight /* if (optionSlider->state & State_HasFocus) drawPrimitive(PE_FrameFocusRect, optionSlider, painter, widget);*/ //Groove graphics if (QS60StylePrivate::hasSliderGrooveGraphic()) { const QS60StylePrivate::SkinElements grooveElement = horizontal ? QS60StylePrivate::SE_SliderGrooveHorizontal : QS60StylePrivate::SE_SliderGrooveVertical; QS60StylePrivate::drawSkinElement(grooveElement, painter, sliderGroove, flags); } else { const QPoint sliderGrooveCenter = sliderGroove.center(); const bool horizontal = optionSlider->orientation == Qt::Horizontal; painter->save(); if (widget) painter->setPen(widget->palette().windowText().color()); if (horizontal) painter->drawLine(0, sliderGrooveCenter.y(), sliderGroove.right(), sliderGrooveCenter.y()); else painter->drawLine(sliderGrooveCenter.x(), 0, sliderGrooveCenter.x(), sliderGroove.bottom()); painter->restore(); } //Handle graphics const QRect sliderHandle = subControlRect(control, optionSlider, SC_SliderHandle, widget); QS60StylePrivate::SkinElements handleElement; if (optionSlider->state & State_Sunken) handleElement = horizontal ? QS60StylePrivate::SE_SliderHandleSelectedHorizontal : QS60StylePrivate::SE_SliderHandleSelectedVertical; else handleElement = horizontal ? QS60StylePrivate::SE_SliderHandleHorizontal : QS60StylePrivate::SE_SliderHandleVertical; QS60StylePrivate::drawSkinElement(handleElement, painter, sliderHandle, flags); } break; #endif // QT_NO_SLIDER #ifndef QT_NO_COMBOBOX case CC_ComboBox: if (const QStyleOptionComboBox *cmb = qstyleoption_cast(option)) { const QRect cmbxEditField = subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget); const QRect cmbxFrame = subControlRect(CC_ComboBox, option, SC_ComboBoxFrame, widget); const bool direction = cmb->direction == Qt::LeftToRight; // Button frame QStyleOptionFrame buttonOption; buttonOption.QStyleOption::operator=(*cmb); const int maxHeight = cmbxFrame.height(); const int maxWidth = cmbxFrame.width() - cmbxEditField.width(); const int topLeftPoint = direction ? (cmbxEditField.right() + 1) : (cmbxEditField.left() + 1 - maxWidth); const QRect buttonRect(topLeftPoint, cmbxEditField.top(), maxWidth, maxHeight); buttonOption.rect = buttonRect; buttonOption.state = cmb->state; drawPrimitive(PE_PanelButtonCommand, &buttonOption, painter, widget); // draw label background - label itself is drawn separately const QS60StylePrivate::SkinElements skinElement = QS60StylePrivate::SE_FrameLineEdit; QS60StylePrivate::drawSkinElement(skinElement, painter, cmbxEditField, flags); // Draw the combobox arrow if (sub & SC_ComboBoxArrow) { // Make rect slightly smaller buttonOption.rect.adjust(1, 1, -1, -1); painter->save(); painter->setPen(option->palette.buttonText().color()); drawPrimitive(PE_IndicatorSpinDown, &buttonOption, painter, widget); painter->restore(); } } break; #endif // QT_NO_COMBOBOX #ifndef QT_NO_TOOLBUTTON case CC_ToolButton: if (const QStyleOptionToolButton *toolBtn = qstyleoption_cast(option)) { State bflags = toolBtn->state & ~State_Sunken; if (bflags & State_AutoRaise) { if (!(bflags & State_MouseOver) || !(bflags & State_Enabled)) { bflags &= ~State_Raised; } } State mflags = bflags; if (toolBtn->state & State_Sunken) { if (toolBtn->activeSubControls & SC_ToolButton) bflags |= State_Sunken; mflags |= State_Sunken; } const QRect button(subControlRect(control, toolBtn, SC_ToolButton, widget)); QRect menuRect = QRect(); if (toolBtn->subControls & SC_ToolButtonMenu) menuRect = subControlRect(control, toolBtn, SC_ToolButtonMenu, widget); if (toolBtn->subControls & SC_ToolButton) { QStyleOption tool(0); tool.palette = toolBtn->palette; if (bflags & (State_Sunken | State_On | State_Raised | State_Enabled)) { tool.rect = button.unite(menuRect); tool.state = bflags; const QToolButton *toolButtonWidget = qobject_cast(widget); const QS60StylePrivate::SkinElements element = ((toolButtonWidget && toolButtonWidget->isDown()) || (option->state & State_Sunken)) ? QS60StylePrivate::SE_ToolBarButtonPressed : QS60StylePrivate::SE_ToolBarButton; QS60StylePrivate::drawSkinElement(element, painter, tool.rect, flags); drawPrimitive(PE_PanelButtonTool, &tool, painter, widget); } if (toolBtn->subControls & SC_ToolButtonMenu) { tool.rect = menuRect; tool.state = mflags; drawPrimitive(PE_IndicatorArrowDown, &tool, painter, widget); } } QStyleOptionToolButton toolButton = *toolBtn; if (toolBtn->features & QStyleOptionToolButton::Arrow) { PrimitiveElement pe; switch (toolBtn->arrowType) { case Qt::LeftArrow: pe = PE_IndicatorArrowLeft; break; case Qt::RightArrow: pe = PE_IndicatorArrowRight; break; case Qt::UpArrow: pe = PE_IndicatorArrowUp; break; case Qt::DownArrow: pe = PE_IndicatorArrowDown; break; default: break; } toolButton.rect = button; drawPrimitive(pe, &toolButton, painter, widget); } if (toolBtn->text.length() > 0 || !toolBtn->icon.isNull()) { const int frameWidth = pixelMetric(PM_DefaultFrameWidth, option, widget); toolButton.rect = button.adjusted(frameWidth, frameWidth, -frameWidth, -frameWidth); drawControl(CE_ToolButtonLabel, &toolButton, painter, widget); } } break; #endif //QT_NO_TOOLBUTTON #ifndef QT_NO_SPINBOX case CC_SpinBox: if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast(option)) { QStyleOptionSpinBox copy = *spinBox; PrimitiveElement pe; if (spinBox->subControls & SC_SpinBoxUp) { copy.subControls = SC_SpinBoxUp; QPalette spinBoxPal = spinBox->palette; if (!(spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled)) { spinBoxPal.setCurrentColorGroup(QPalette::Disabled); copy.state &= ~State_Enabled; copy.palette = spinBoxPal; } if (spinBox->activeSubControls == SC_SpinBoxUp && (spinBox->state & State_Sunken)) { copy.state |= State_On; copy.state |= State_Sunken; } else { copy.state |= State_Raised; copy.state &= ~State_Sunken; } pe = (spinBox->buttonSymbols == QAbstractSpinBox::PlusMinus) ? PE_IndicatorSpinPlus : PE_IndicatorSpinUp; copy.rect = subControlRect(CC_SpinBox, spinBox, SC_SpinBoxUp, widget); drawPrimitive(PE_PanelButtonBevel, ©, painter, widget); copy.rect.adjust(1, 1, -1, -1); drawPrimitive(pe, ©, painter, widget); } if (spinBox->subControls & SC_SpinBoxDown) { copy.subControls = SC_SpinBoxDown; copy.state = spinBox->state; QPalette spinBoxPal = spinBox->palette; if (!(spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled)) { spinBoxPal.setCurrentColorGroup(QPalette::Disabled); copy.state &= ~State_Enabled; copy.palette = spinBoxPal; } if (spinBox->activeSubControls == SC_SpinBoxDown && (spinBox->state & State_Sunken)) { copy.state |= State_On; copy.state |= State_Sunken; } else { copy.state |= State_Raised; copy.state &= ~State_Sunken; } pe = (spinBox->buttonSymbols == QAbstractSpinBox::PlusMinus) ? PE_IndicatorSpinMinus : PE_IndicatorSpinDown; copy.rect = subControlRect(CC_SpinBox, spinBox, SC_SpinBoxDown, widget); drawPrimitive(PE_PanelButtonBevel, ©, painter, widget); copy.rect.adjust(1, 1, -1, -1); drawPrimitive(pe, ©, painter, widget); } } break; #endif //QT_NO_SPINBOX #ifndef QT_NO_GROUPBOX case CC_GroupBox: if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast(option)) { // Draw frame const QRect textRect = subControlRect(CC_GroupBox, option, SC_GroupBoxLabel, widget); const QRect checkBoxRect = subControlRect(CC_GroupBox, option, SC_GroupBoxCheckBox, widget); if (groupBox->subControls & SC_GroupBoxFrame) { QStyleOptionFrameV2 frame; frame.QStyleOption::operator=(*groupBox); frame.features = groupBox->features; frame.lineWidth = groupBox->lineWidth; frame.midLineWidth = groupBox->midLineWidth; frame.rect = subControlRect(CC_GroupBox, option, SC_GroupBoxFrame, widget); drawPrimitive(PE_FrameGroupBox, &frame, painter, widget); } // Draw title if ((groupBox->subControls & SC_GroupBoxLabel) && !groupBox->text.isEmpty()) { const QColor textColor = groupBox->textColor; painter->save(); if (textColor.isValid()) painter->setPen(textColor); int alignment = int(groupBox->textAlignment); if (!styleHint(SH_UnderlineShortcut, option, widget)) alignment |= Qt::TextHideMnemonic; drawItemText(painter, textRect, Qt::TextShowMnemonic | Qt::AlignHCenter | Qt::AlignVCenter | alignment, groupBox->palette, groupBox->state & State_Enabled, groupBox->text, textColor.isValid() ? QPalette::NoRole : QPalette::WindowText); painter->restore(); } // Draw checkbox if (groupBox->subControls & SC_GroupBoxCheckBox) { QStyleOptionButton box; box.QStyleOption::operator=(*groupBox); box.rect = checkBoxRect; drawPrimitive(PE_IndicatorCheckBox, &box, painter, widget); } } break; #endif //QT_NO_GROUPBOX default: QCommonStyle::drawComplexControl(control, option, painter, widget); } } /*! \reimp */ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { Q_D(const QS60Style); const QS60StylePrivate::SkinElementFlags flags = (option->state & State_Enabled) ? QS60StylePrivate::SF_StateEnabled : QS60StylePrivate::SF_StateDisabled; switch (element) { case CE_CheckBox: case CE_RadioButton: if (const QStyleOptionButton *btn = qstyleoption_cast(option)) { bool isRadio = (element == CE_RadioButton); QStyleOptionButton subopt = *btn; // Highlight needs to be drawn first, as it goes "underneath" the text and indicator. if (btn->state & State_HasFocus) { QStyleOptionFocusRect fropt; fropt.QStyleOption::operator=(*btn); fropt.rect = subElementRect(isRadio ? SE_RadioButtonFocusRect : SE_CheckBoxFocusRect, btn, widget); drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); subopt.palette.setColor(QPalette::Active, QPalette::WindowText, subopt.palette.highlightedText().color()); } subopt.rect = subElementRect(isRadio ? SE_RadioButtonIndicator : SE_CheckBoxIndicator, btn, widget); drawPrimitive(isRadio ? PE_IndicatorRadioButton : PE_IndicatorCheckBox, &subopt, painter, widget); subopt.rect = subElementRect(isRadio ? SE_RadioButtonContents : SE_CheckBoxContents, btn, widget); drawControl(isRadio ? CE_RadioButtonLabel : CE_CheckBoxLabel, &subopt, painter, widget); } break; case CE_PushButton: if (const QStyleOptionButton *btn = qstyleoption_cast(option)) { drawControl(CE_PushButtonBevel, btn, painter, widget); QStyleOptionButton subopt = *btn; subopt.rect = subElementRect(SE_PushButtonContents, btn, widget); drawControl(CE_PushButtonLabel, &subopt, painter, widget); } break; case CE_PushButtonBevel: if (const QStyleOptionButton *button = qstyleoption_cast(option)) { const bool isDisabled = !(option->state & State_Enabled); const bool isFlat = button->features & QStyleOptionButton::Flat; QS60StyleEnums::SkinParts skinPart; QS60StylePrivate::SkinElements skinElement; if (!isDisabled) { const bool isPressed = (option->state & State_Sunken) || (option->state & State_On); if (isFlat) { skinPart = isPressed ? QS60StyleEnums::SP_QsnFrButtonTbCenterPressed : QS60StyleEnums::SP_QsnFrButtonTbCenter; } else { skinElement = isPressed ? QS60StylePrivate::SE_ButtonPressed : QS60StylePrivate::SE_ButtonNormal; } } else { if (isFlat) skinPart =QS60StyleEnums::SP_QsnFrButtonCenterInactive; else skinElement = QS60StylePrivate::SE_ButtonInactive; } if (isFlat) QS60StylePrivate::drawSkinPart(skinPart, painter, option->rect, flags); else QS60StylePrivate::drawSkinElement(skinElement, painter, option->rect, flags); } break; #ifndef QT_NO_TOOLBUTTON case CE_ToolButtonLabel: if (const QStyleOptionToolButton *toolBtn = qstyleoption_cast(option)) { QStyleOptionToolButton optionToolButton = *toolBtn; if (!optionToolButton.icon.isNull() && (optionToolButton.state & State_Sunken) && (optionToolButton.state & State_Enabled)) { const QIcon::State state = optionToolButton.state & State_On ? QIcon::On : QIcon::Off; const QPixmap pm(optionToolButton.icon.pixmap(optionToolButton.rect.size().boundedTo(optionToolButton.iconSize), QIcon::Normal, state)); optionToolButton.icon = generatedIconPixmap(QIcon::Selected, pm, &optionToolButton); } QCommonStyle::drawControl(element, &optionToolButton, painter, widget); } break; #endif //QT_NO_TOOLBUTTON #ifndef QT_NO_COMBOBOX case CE_ComboBoxLabel: if (const QStyleOptionComboBox *comboBox = qstyleoption_cast(option)) { QStyleOption optionComboBox = *comboBox; optionComboBox.palette.setColor(QPalette::Active, QPalette::WindowText, optionComboBox.palette.text().color() ); optionComboBox.palette.setColor(QPalette::Inactive, QPalette::WindowText, optionComboBox.palette.text().color() ); QRect editRect = subControlRect(CC_ComboBox, comboBox, SC_ComboBoxEditField, widget); const int frameW = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget); if (!comboBox->currentIcon.isNull()) { const QIcon::Mode mode = comboBox->state & State_Enabled ? QIcon::Normal : QIcon::Disabled; const QPixmap pixmap = comboBox->currentIcon.pixmap(comboBox->iconSize, mode); QRect iconRect(editRect); iconRect.setWidth(comboBox->iconSize.width() + frameW); iconRect = alignedRect(comboBox->direction, Qt::AlignLeft | Qt::AlignVCenter, iconRect.size(), editRect); if (comboBox->editable) painter->fillRect(iconRect, optionComboBox.palette.brush(QPalette::Base)); drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); if (comboBox->direction == Qt::RightToLeft) editRect.setRight(editRect.right() - frameW - comboBox->iconSize.width()); else editRect.setLeft(comboBox->iconSize.width() + frameW); } if (!comboBox->currentText.isEmpty() && !comboBox->editable) { const Qt::TextElideMode elideMode = (comboBox->direction == Qt::LeftToRight) ? Qt::ElideRight : Qt::ElideLeft; const QString text = comboBox->fontMetrics.elidedText(comboBox->currentText, elideMode, editRect.width()); QCommonStyle::drawItemText(painter, editRect.adjusted(QS60StylePrivate::pixelMetric(PM_FrameCornerWidth), 0, -1, 0), visualAlignment(comboBox->direction, Qt::AlignLeft | Qt::AlignVCenter), comboBox->palette, comboBox->state & State_Enabled, text); } } break; #endif //QT_NO_COMBOBOX #ifndef QT_NO_ITEMVIEWS case CE_ItemViewItem: if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast(option)) { QStyleOptionViewItemV4 voptAdj = *vopt; painter->save(); painter->setClipRect(voptAdj.rect); const bool isSelected = (vopt->state & State_Selected); const bool hasFocus = (vopt->state & State_HasFocus); bool isScrollBarVisible = false; int scrollBarWidth = 0; QList scrollBars = widget->findChildren(); for (int i = 0; i < scrollBars.size(); ++i) { QScrollBar *scrollBar = scrollBars.at(i); if (scrollBar && scrollBar->orientation() == Qt::Vertical) { isScrollBarVisible = scrollBar->isVisible(); scrollBarWidth = scrollBar->size().width(); break; } } int rightValue = widget ? widget->contentsRect().right() : voptAdj.rect.right(); if (isScrollBarVisible) rightValue -= scrollBarWidth; if (voptAdj.rect.right() > rightValue) voptAdj.rect.setRight(rightValue); const QRect iconRect = subElementRect(SE_ItemViewItemDecoration, &voptAdj, widget); QRect textRect = subElementRect(SE_ItemViewItemText, &voptAdj, widget); const QAbstractItemView *itemView = qobject_cast(widget); // draw themed background for table unless background brush has been defined. if (vopt->backgroundBrush == Qt::NoBrush) { if (itemView) { drawPrimitive(PE_PanelItemViewItem, &voptAdj, painter, widget); } } else { QCommonStyle::drawPrimitive(PE_PanelItemViewItem, &voptAdj, painter, widget);} // draw the icon const QIcon::Mode mode = (voptAdj.state & State_Enabled) ? QIcon::Normal : QIcon::Disabled; const QIcon::State state = (voptAdj.state & State_Open) ? QIcon::On : QIcon::Off; voptAdj.icon.paint(painter, iconRect, voptAdj.decorationAlignment, mode, state); // Draw selection check mark. Show check mark only in multi selection modes. if (itemView) { const bool singleSelection = (itemView->selectionMode() == QAbstractItemView::SingleSelection || itemView->selectionMode() == QAbstractItemView::NoSelection)|| (itemView->selectionModel()->selectedIndexes().count() < 2 ); const bool selectItemsOnly = (itemView->selectionBehavior() == QAbstractItemView::SelectItems); const QRect selectionRect = subElementRect(SE_ItemViewItemCheckIndicator, &voptAdj, widget); QStyleOptionViewItemV4 checkMarkOption(voptAdj); if (selectionRect.isValid()) checkMarkOption.rect = selectionRect; // Draw selection mark. if (isSelected && !singleSelection && selectItemsOnly) { proxy()->drawPrimitive(PE_IndicatorViewItemCheck, &checkMarkOption, painter, widget); // @todo: this should happen in the rect retrievel i.e. subElementRect() if (textRect.right() > selectionRect.left()) textRect.setRight(selectionRect.left()); } else if (singleSelection && voptAdj.features & QStyleOptionViewItemV2::HasCheckIndicator) { checkMarkOption.state = checkMarkOption.state & ~State_HasFocus; switch (vopt->checkState) { case Qt::Unchecked: checkMarkOption.state |= State_Off; break; case Qt::PartiallyChecked: checkMarkOption.state |= State_NoChange; break; case Qt::Checked: checkMarkOption.state |= State_On; break; } drawPrimitive(PE_IndicatorViewItemCheck, &checkMarkOption, painter, widget); } } // draw the text if (!voptAdj.text.isEmpty()) { if (isSelected || hasFocus ) painter->setPen(voptAdj.palette.highlightedText().color()); else painter->setPen(voptAdj.palette.text().color()); d->viewItemDrawText(painter, &voptAdj, textRect); } painter->restore(); } break; #endif // QT_NO_ITEMVIEWS #ifndef QT_NO_TABBAR case CE_TabBarTabShape: if (const QStyleOptionTabV3 *optionTab = qstyleoption_cast(option)) { QStyleOptionTabV3 optionTabAdj = *optionTab; const bool isSelected = optionTab->state & State_Selected; const bool directionMirrored = (optionTab->direction == Qt::RightToLeft); QS60StylePrivate::SkinElements skinElement; switch (optionTab->shape) { case QTabBar::TriangularEast: case QTabBar::RoundedEast: skinElement = isSelected ? QS60StylePrivate::SE_TabBarTabEastActive: QS60StylePrivate::SE_TabBarTabEastInactive; break; case QTabBar::TriangularSouth: case QTabBar::RoundedSouth: skinElement = isSelected ? QS60StylePrivate::SE_TabBarTabSouthActive: QS60StylePrivate::SE_TabBarTabSouthInactive; break; case QTabBar::TriangularWest: case QTabBar::RoundedWest: skinElement = isSelected ? QS60StylePrivate::SE_TabBarTabWestActive: QS60StylePrivate::SE_TabBarTabWestInactive; break; case QTabBar::TriangularNorth: case QTabBar::RoundedNorth: default: skinElement = isSelected ? QS60StylePrivate::SE_TabBarTabNorthActive: QS60StylePrivate::SE_TabBarTabNorthInactive; break; } if (skinElement == QS60StylePrivate::SE_TabBarTabEastInactive || skinElement == QS60StylePrivate::SE_TabBarTabNorthInactive || skinElement == QS60StylePrivate::SE_TabBarTabSouthInactive || skinElement == QS60StylePrivate::SE_TabBarTabWestInactive || skinElement == QS60StylePrivate::SE_TabBarTabEastActive || skinElement == QS60StylePrivate::SE_TabBarTabNorthActive || skinElement == QS60StylePrivate::SE_TabBarTabSouthActive || skinElement==QS60StylePrivate::SE_TabBarTabWestActive) { const int borderThickness = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); const int tabOverlap = QS60StylePrivate::pixelMetric(PM_TabBarTabOverlap) - borderThickness; const bool usesScrollButtons = (widget) ? (qobject_cast(widget))->usesScrollButtons() : false; const int roomForScrollButton = usesScrollButtons ? QS60StylePrivate::pixelMetric(PM_TabBarScrollButtonWidth) : 0; // adjust for overlapping tabs and scrollbuttons, if necessary if (skinElement == QS60StylePrivate::SE_TabBarTabEastInactive || skinElement == QS60StylePrivate::SE_TabBarTabEastActive || skinElement == QS60StylePrivate::SE_TabBarTabWestInactive || skinElement == QS60StylePrivate::SE_TabBarTabWestActive){ if (optionTabAdj.position == QStyleOptionTabV3::Beginning) optionTabAdj.rect.adjust(0, roomForScrollButton, 0, tabOverlap); else if (optionTabAdj.position == QStyleOptionTabV3::End) optionTabAdj.rect.adjust(0, 0, 0, tabOverlap); else optionTabAdj.rect.adjust(0, 0, 0, tabOverlap); } else { if (directionMirrored) { if (optionTabAdj.position == QStyleOptionTabV3::Beginning) optionTabAdj.rect.adjust(-tabOverlap, 0, -roomForScrollButton, 0); else optionTabAdj.rect.adjust(-tabOverlap, 0, 0, 0); } else { if (optionTabAdj.position == QStyleOptionTabV3::Beginning) optionTabAdj.rect.adjust(roomForScrollButton, 0, tabOverlap, 0); else optionTabAdj.rect.adjust(0, 0, tabOverlap, 0); } } } QS60StylePrivate::drawSkinElement(skinElement, painter, optionTabAdj.rect, flags); } break; case CE_TabBarTabLabel: if (const QStyleOptionTabV3 *tab = qstyleoption_cast(option)) { QStyleOptionTabV3 optionTab = *tab; QRect tr = optionTab.rect; const bool directionMirrored = (optionTab.direction == Qt::RightToLeft); const int borderThickness = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); const int tabOverlap = QS60StylePrivate::pixelMetric(PM_TabBarTabOverlap) - borderThickness; const bool usesScrollButtons = (widget) ? (qobject_cast(widget))->usesScrollButtons() : false; const int roomForScrollButton = usesScrollButtons ? QS60StylePrivate::pixelMetric(PM_TabBarScrollButtonWidth) : 0; switch (tab->shape) { case QTabBar::TriangularWest: case QTabBar::RoundedWest: case QTabBar::TriangularEast: case QTabBar::RoundedEast: tr.adjust(0, 0, 0, tabOverlap); break; case QTabBar::TriangularSouth: case QTabBar::RoundedSouth: case QTabBar::TriangularNorth: case QTabBar::RoundedNorth: default: if (directionMirrored) tr.adjust(-tabOverlap, 0, 0, 0); else tr.adjust(0, 0, tabOverlap, 0); break; } painter->save(); QFont f = painter->font(); f.setPointSizeF(f.pointSizeF() * KTabFontMul); painter->setFont(f); const bool selected = optionTab.state & State_Selected; if (selected) optionTab.palette.setColor(QPalette::Active, QPalette::WindowText, optionTab.palette.highlightedText().color()); const bool verticalTabs = optionTab.shape == QTabBar::RoundedEast || optionTab.shape == QTabBar::RoundedWest || optionTab.shape == QTabBar::TriangularEast || optionTab.shape == QTabBar::TriangularWest; //make room for scrollbuttons if (!verticalTabs) { if ((tab->position == QStyleOptionTabV3::Beginning && !directionMirrored)) tr.adjust(roomForScrollButton, 0, 0, 0); else if ((tab->position == QStyleOptionTabV3::Beginning && directionMirrored)) tr.adjust(0, 0, -roomForScrollButton, 0); } else { if (tab->position == QStyleOptionTabV3::Beginning) tr.adjust(0, roomForScrollButton, 0, 0); } if (verticalTabs) { painter->save(); int newX, newY, newRotation; if (optionTab.shape == QTabBar::RoundedEast || optionTab.shape == QTabBar::TriangularEast) { newX = tr.width(); newY = tr.y(); newRotation = 90; } else { newX = 0; newY = tr.y() + tr.height(); newRotation = -90; } tr.setRect(0, 0, tr.height(), tr.width()); QTransform m; m.translate(newX, newY); m.rotate(newRotation); painter->setTransform(m, true); } tr.adjust(0, 0, pixelMetric(PM_TabBarTabShiftHorizontal, tab, widget), pixelMetric(PM_TabBarTabShiftVertical, tab, widget)); if (selected) { tr.setBottom(tr.bottom() - pixelMetric(PM_TabBarTabShiftVertical, tab, widget)); tr.setRight(tr.right() - pixelMetric(PM_TabBarTabShiftHorizontal, tab, widget)); } int alignment = Qt::AlignCenter | Qt::TextShowMnemonic; if (!styleHint(SH_UnderlineShortcut, &optionTab, widget)) alignment |= Qt::TextHideMnemonic; if (!optionTab.icon.isNull()) { QSize iconSize = optionTab.iconSize; if (!iconSize.isValid()) { const int iconExtent = pixelMetric(PM_TabBarIconSize); iconSize = QSize(iconExtent, iconExtent); } QPixmap tabIcon = optionTab.icon.pixmap(iconSize, (optionTab.state & State_Enabled) ? QIcon::Normal : QIcon::Disabled); if (tab->text.isEmpty()) painter->drawPixmap(tr.center().x() - (tabIcon.height() >> 1), tr.center().y() - (tabIcon.height() >> 1), tabIcon); else painter->drawPixmap(tr.left() + tabOverlap, tr.center().y() - (tabIcon.height() >> 1), tabIcon); tr.setLeft(tr.left() + iconSize.width() + 4); //todo: magic four } QCommonStyle::drawItemText(painter, tr, alignment, optionTab.palette, tab->state & State_Enabled, tab->text, QPalette::WindowText); if (verticalTabs) painter->restore(); painter->restore(); } break; #endif // QT_NO_TABBAR #ifndef QT_NO_PROGRESSBAR case CE_ProgressBarContents: if (const QStyleOptionProgressBarV2 *optionProgressBar = qstyleoption_cast(option)) { QRect progressRect = optionProgressBar->rect; if (optionProgressBar->minimum == optionProgressBar->maximum && optionProgressBar->minimum == 0) { // busy indicator const QS60StylePrivate::SkinElementFlag orientationFlag = optionProgressBar->orientation == Qt::Horizontal ? QS60StylePrivate::SF_PointNorth : QS60StylePrivate::SF_PointWest; QS60StylePrivate::drawSkinPart(QS60StyleEnums::SP_QgnGrafBarWaitAnim, painter, progressRect, flags | orientationFlag | QS60StylePrivate::SF_Animation ); } else { const qreal progressFactor = (optionProgressBar->minimum == optionProgressBar->maximum) ? 1.0 : (qreal)optionProgressBar->progress / optionProgressBar->maximum; const int frameWidth = pixelMetric(PM_DefaultFrameWidth, option, widget); if (optionProgressBar->orientation == Qt::Horizontal) { progressRect.setWidth(int(progressRect.width() * progressFactor)); if(optionProgressBar->direction == Qt::RightToLeft) progressRect.translate(optionProgressBar->rect.width() - progressRect.width(), 0); progressRect.adjust(frameWidth, 0, -frameWidth, 0); } else { progressRect.adjust(0, frameWidth, 0, -frameWidth); progressRect.setTop(progressRect.bottom() - int(progressRect.height() * progressFactor)); } const QS60StylePrivate::SkinElements skinElement = optionProgressBar->orientation == Qt::Horizontal ? QS60StylePrivate::SE_ProgressBarIndicatorHorizontal : QS60StylePrivate::SE_ProgressBarIndicatorVertical; QS60StylePrivate::drawSkinElement(skinElement, painter, progressRect, flags); } } break; case CE_ProgressBarGroove: if (const QStyleOptionProgressBarV2 *optionProgressBar = qstyleoption_cast(option)) { const QS60StylePrivate::SkinElements skinElement = optionProgressBar->orientation == Qt::Horizontal ? QS60StylePrivate::SE_ProgressBarGrooveHorizontal : QS60StylePrivate::SE_ProgressBarGrooveVertical; QS60StylePrivate::drawSkinElement(skinElement, painter, option->rect, flags); } break; case CE_ProgressBarLabel: if (const QStyleOptionProgressBarV2 *progressbar = qstyleoption_cast(option)) { QStyleOptionProgressBarV2 optionProgressBar = *progressbar; QCommonStyle::drawItemText(painter, progressbar->rect, flags | Qt::AlignCenter | Qt::TextSingleLine, optionProgressBar.palette, progressbar->state & State_Enabled, progressbar->text, QPalette::WindowText); } break; #endif // QT_NO_PROGRESSBAR #ifndef QT_NO_MENU case CE_MenuItem: if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast(option)) { QStyleOptionMenuItem optionMenuItem = *menuItem; bool drawSubMenuIndicator = false; switch(menuItem->menuItemType) { case QStyleOptionMenuItem::Scroller: case QStyleOptionMenuItem::Separator: return; // no separators or scrollers in S60 menus case QStyleOptionMenuItem::SubMenu: drawSubMenuIndicator = true; break; default: break; } const bool enabled = optionMenuItem.state & State_Enabled; const bool checkable = optionMenuItem.checkType != QStyleOptionMenuItem::NotCheckable; bool ignoreCheckMark = false; #ifndef QT_NO_COMBOBOX if (qobject_cast(widget)) ignoreCheckMark = true; //ignore the checkmarks provided by the QComboMenuDelegate #endif uint text_flags = Qt::AlignLeading | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine | Qt::AlignVCenter; if (!styleHint(SH_UnderlineShortcut, menuItem, widget)) text_flags |= Qt::TextHideMnemonic; QRect iconRect = subElementRect(SE_ItemViewItemDecoration, &optionMenuItem, widget); QRect textRect = subElementRect(SE_ItemViewItemText, &optionMenuItem, widget); QStyleOptionMenuItem optionCheckBox; //Regardless of checkbox visibility, make room for it, this mirrors native implementation, //where text and icon placement is static regardless of content of menu item. optionCheckBox.QStyleOptionMenuItem::operator=(*menuItem); optionCheckBox.rect.setWidth(pixelMetric(PM_IndicatorWidth)); optionCheckBox.rect.setHeight(pixelMetric(PM_IndicatorHeight)); const int vSpacing = QS60StylePrivate::pixelMetric(PM_LayoutVerticalSpacing); //The vertical spacing is doubled; it needs one spacing to separate checkbox from //highlight and then it needs one to separate it whatever is shown after it (text/icon/both). const int moveByX = optionCheckBox.rect.width() + 2 * vSpacing; optionCheckBox.rect.moveCenter(QPoint( optionCheckBox.rect.center().x() + moveByX >> 1, menuItem->rect.center().y())); if (optionMenuItem.direction != Qt::LeftToRight) optionCheckBox.rect.translate(textRect.width() + iconRect.width(), 0); const bool selected = (option->state & State_Selected) && (option->state & State_Enabled); if (selected) { const int spacing = ignoreCheckMark ? (vSpacing + QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth)) : 0; const int start = optionMenuItem.rect.left() + spacing; const int end = optionMenuItem.rect.right() - spacing; //-1 adjustment to avoid highlight being on top of possible separator item const QRect highlightRect = QRect( QPoint(start, option->rect.top()), QPoint(end, option->rect.bottom() - 1)); QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ListHighlight, painter, highlightRect, flags); } if (checkable && !ignoreCheckMark) drawPrimitive(PE_IndicatorMenuCheckMark, &optionCheckBox, painter, widget); //draw icon and/or checkState QPixmap pix = menuItem->icon.pixmap(pixelMetric(PM_SmallIconSize), enabled ? QIcon::Normal : QIcon::Disabled); const bool itemWithIcon = !pix.isNull(); if (itemWithIcon) { drawItemPixmap(painter, iconRect, text_flags, pix); if (optionMenuItem.direction == Qt::LeftToRight) textRect.translate(vSpacing, 0); else textRect.translate(-vSpacing, 0); textRect.setWidth(textRect.width() - vSpacing); } //draw indicators if (drawSubMenuIndicator) { QStyleOptionMenuItem arrowOptions; arrowOptions.QStyleOption::operator=(*menuItem); const int indicatorWidth = (pixelMetric(PM_ListViewIconSize, option, widget) >> 1) + pixelMetric(PM_LayoutVerticalSpacing, option, widget); if (optionMenuItem.direction == Qt::LeftToRight) arrowOptions.rect.setLeft(textRect.right()); arrowOptions.rect.setWidth(indicatorWidth); //by default sub menu indicator in S60 points to east,so here icon // direction is set to north (and south when in RightToLeft) const QS60StylePrivate::SkinElementFlag arrowDirection = (arrowOptions.direction == Qt::LeftToRight) ? QS60StylePrivate::SF_PointNorth : QS60StylePrivate::SF_PointSouth; painter->save(); painter->setPen(option->palette.windowText().color()); QS60StylePrivate::drawSkinPart(QS60StyleEnums::SP_QgnIndiSubmenu, painter, arrowOptions.rect, (flags | QS60StylePrivate::SF_ColorSkinned | arrowDirection)); painter->restore(); } //draw text if (!enabled){ //In s60, if something becomes disabled, it is removed from menu, so no native look-alike available. optionMenuItem.palette.setColor(QPalette::Disabled, QPalette::Text, QS60StylePrivate::lighterColor( optionMenuItem.palette.color(QPalette::Disabled, QPalette::Text))); painter->save(); painter->setOpacity(0.5); } if (selected) optionMenuItem.palette.setColor( QPalette::Active, QPalette::Text, optionMenuItem.palette.highlightedText().color()); QCommonStyle::drawItemText(painter, textRect, text_flags, optionMenuItem.palette, enabled, optionMenuItem.text, QPalette::Text); //In Sym^3, native menu items have "lines" between them if (QS60StylePrivate::isSingleClickUi()) { const QColor lineColorAlpha = QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 15, 0); const int spacing = QS60StylePrivate::pixelMetric(PM_FrameCornerWidth); //native platform sets each color byte to same value for "line 16" which just defines alpha for //menuitem lines; lets use first byte "red". QColor lineColor = optionMenuItem.palette.text().color(); if (lineColorAlpha.isValid()) lineColor.setAlpha(lineColorAlpha.red()); painter->save(); painter->setPen(lineColor); const int lineStartX = optionMenuItem.rect.left() + (QS60StylePrivate::pixelMetric(PM_FrameCornerWidth) - 2) + spacing; const int lineEndX = optionMenuItem.rect.right() - (QS60StylePrivate::pixelMetric(PM_FrameCornerWidth) - 2) - spacing; painter->drawLine(QPoint(lineStartX, optionMenuItem.rect.bottom()), QPoint(lineEndX, optionMenuItem.rect.bottom())); painter->restore(); } if (!enabled) painter->restore(); } break; case CE_MenuEmptyArea: break; #endif //QT_NO_MENU #ifndef QT_NO_MENUBAR case CE_MenuBarEmptyArea: break; #endif //QT_NO_MENUBAR case CE_HeaderSection: if (const QStyleOptionHeader *header = qstyleoption_cast(option)) { painter->save(); QPen linePen = QPen(QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 1, header)); const int penWidth = (header->orientation == Qt::Horizontal) ? linePen.width() + QS60StylePrivate::pixelMetric(PM_BoldLineWidth) : linePen.width() + QS60StylePrivate::pixelMetric(PM_ThinLineWidth); linePen.setWidth(penWidth); painter->setPen(linePen); if (header->orientation == Qt::Horizontal){ painter->drawLine(header->rect.bottomLeft(), header->rect.bottomRight()); } else { if ( header->direction == Qt::LeftToRight ) { painter->drawLine(header->rect.topRight(), header->rect.bottomRight()); } else { painter->drawLine(header->rect.topLeft(), header->rect.bottomLeft()); } } painter->restore(); //Draw corner button as normal pushButton. if (qobject_cast(widget)) { //Make cornerButton slightly smaller so that it is not on top of table border graphic. QStyleOptionHeader subopt = *header; const int borderTweak = QS60StylePrivate::pixelMetric(PM_FrameCornerWidth) >> 1; if (subopt.direction == Qt::LeftToRight) subopt.rect.adjust(borderTweak, borderTweak, 0, -borderTweak); else subopt.rect.adjust(0, borderTweak, -borderTweak, -borderTweak); drawPrimitive(PE_PanelButtonBevel, &subopt, painter, widget); } else if ((header->palette.brush(QPalette::Button) != Qt::transparent)) { //Draw non-themed background. Background for theme is drawn in CE_ShapedFrame //to get continuous theme graphic across all the header cells. qDrawShadePanel(painter, header->rect, header->palette, header->state & (State_Sunken | State_On), penWidth, &header->palette.brush(QPalette::Button)); } } break; case CE_HeaderEmptyArea: // no need to draw this break; case CE_Header: if ( const QStyleOptionHeader *header = qstyleoption_cast(option)) { drawControl(CE_HeaderSection, header, painter, widget); QStyleOptionHeader subopt = *header; subopt.rect = subElementRect(SE_HeaderLabel, header, widget); if (subopt.rect.isValid()) drawControl(CE_HeaderLabel, &subopt, painter, widget); if (header->sortIndicator != QStyleOptionHeader::None) { subopt.rect = subElementRect(SE_HeaderArrow, option, widget); drawPrimitive(PE_IndicatorHeaderArrow, &subopt, painter, widget); } } break; #ifndef QT_NO_TOOLBAR case CE_ToolBar: if (const QStyleOptionToolBar *toolBar = qstyleoption_cast(option)) { const QToolBar *tbWidget = qobject_cast(widget); //toolbar within a toolbar, skip if (!tbWidget || (widget && qobject_cast(widget->parentWidget()))) break; // Normally in S60 5.0+ there is no background for toolbar, but in some cases with versatile QToolBar, // it looks a bit strange. So, lets fillRect with Button. if (!QS60StylePrivate::isToolBarBackground()) { QList actions = tbWidget->actions(); bool justToolButtonsInToolBar = true; for (int i = 0; i < actions.size(); ++i) { QWidget *childWidget = tbWidget->widgetForAction(actions.at(i)); const QToolButton *button = qobject_cast(childWidget); if (!button){ justToolButtonsInToolBar = false; } } // Draw frame background // for vertical toolbars with text only and // for toolbars with extension buttons and // for toolbars with widgets in them. if (!justToolButtonsInToolBar || (tbWidget && (tbWidget->orientation() == Qt::Vertical) && (tbWidget->toolButtonStyle() == Qt::ToolButtonTextOnly))) { painter->save(); if (widget) painter->setBrush(widget->palette().button()); painter->setOpacity(0.3); painter->fillRect(toolBar->rect, painter->brush()); painter->restore(); } } else { QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ToolBar, painter, toolBar->rect, flags); } } break; #endif //QT_NO_TOOLBAR case CE_ShapedFrame: if (const QTextEdit *textEdit = qobject_cast(widget)) { const QStyleOptionFrame *frame = qstyleoption_cast(option); if (QS60StylePrivate::canDrawThemeBackground(frame->palette.base(), widget)) QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_Editor, painter, option->rect, flags); else QCommonStyle::drawControl(element, option, painter, widget); } else if (qobject_cast(widget)) { QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_TableItem, painter, option->rect, flags); } else if (const QHeaderView *header = qobject_cast(widget)) { //QS60style draws header background here instead of in each headersection, to get //continuous graphic from section to section. QS60StylePrivate::SkinElementFlags adjustableFlags = flags; QRect headerRect = option->rect; if (header->orientation() != Qt::Horizontal) { //todo: update to horizontal table graphic adjustableFlags = (adjustableFlags | QS60StylePrivate::SF_PointWest); } else { const int frameWidth = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); if (option->direction == Qt::LeftToRight) headerRect.adjust(-2 * frameWidth, 0, 0, 0); else headerRect.adjust(0, 0, 2 * frameWidth, 0); } if (option->palette.brush(QPalette::Button).color() == Qt::transparent) QS60StylePrivate::drawSkinElement( QS60StylePrivate::SE_TableHeaderItem, painter, headerRect, adjustableFlags); } else if (qobject_cast(widget)) { QCommonStyle::drawControl(element, option, painter, widget); } break; case CE_MenuScroller: break; case CE_FocusFrame: { #ifdef QT_KEYPAD_NAVIGATION bool editFocus = false; if (const QFocusFrame *focusFrame = qobject_cast(widget)) { if (focusFrame->widget() && focusFrame->widget()->hasEditFocus()) editFocus = true; } const qreal opacity = editFocus ? 1 : 0.75; // Trial and error factors. Feel free to improve. #else const qreal opacity = 0.85; #endif // We need to reduce the focus frame size if LayoutSpacing is smaller than FocusFrameMargin // Otherwise, we would overlay adjacent widgets. const int frameHeightReduction = qMin(0, pixelMetric(PM_LayoutVerticalSpacing) - pixelMetric(PM_FocusFrameVMargin)); const int frameWidthReduction = qMin(0, pixelMetric(PM_LayoutHorizontalSpacing) - pixelMetric(PM_FocusFrameHMargin)); const int rounding = qMin(pixelMetric(PM_FocusFrameVMargin), pixelMetric(PM_LayoutVerticalSpacing)); const QRect frameRect = option->rect.adjusted(-frameWidthReduction, -frameHeightReduction, frameWidthReduction, frameHeightReduction); QPainterPath framePath; framePath.addRoundedRect(frameRect, rounding, rounding); painter->save(); painter->setRenderHint(QPainter::Antialiasing); painter->setOpacity(opacity); painter->fillPath(framePath, option->palette.color(QPalette::Text)); painter->restore(); } break; case CE_Splitter: if (option->state & State_Sunken && option->state & State_Enabled) { painter->save(); painter->setOpacity(0.5); painter->setBrush(QS60StylePrivate::themePalette()->light()); painter->setRenderHint(QPainter::Antialiasing); const qreal roundRectRadius = 4 * goldenRatio; painter->drawRoundedRect(option->rect, roundRectRadius, roundRectRadius); painter->restore(); } break; default: QCommonStyle::drawControl(element, option, painter, widget); } } /*! \reimp */ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { const QS60StylePrivate::SkinElementFlags flags = (option->state & State_Enabled) ? QS60StylePrivate::SF_StateEnabled : QS60StylePrivate::SF_StateDisabled; bool commonStyleDraws = false; switch (element) { case PE_FrameFocusRect: { //Draw themed highlight to radiobuttons and checkboxes. //For other widgets skip, unless palette has been modified. In that case, draw with commonstyle. if (option->palette.highlight().color() == QS60StylePrivate::themePalette()->highlight().color()) { if ((qstyleoption_cast(option) && (qobject_cast(widget) || qobject_cast(widget)))) QS60StylePrivate::drawSkinElement( QS60StylePrivate::isWidgetPressed(widget) ? QS60StylePrivate::SE_ListItemPressed : QS60StylePrivate::SE_ListHighlight, painter, option->rect, flags); } else { commonStyleDraws = true; } } break; #ifndef QT_NO_LINEEDIT case PE_PanelLineEdit: if (const QStyleOptionFrame *lineEdit = qstyleoption_cast(option)) { #ifndef QT_NO_COMBOBOX if (widget && qobject_cast(widget->parentWidget())) break; #endif if (QS60StylePrivate::canDrawThemeBackground(option->palette.base(), widget)) QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_FrameLineEdit, painter, option->rect, flags); else commonStyleDraws = true; } break; #endif // QT_NO_LINEEDIT case PE_IndicatorCheckBox: { // Draw checkbox indicator as color skinned graphics. const QS60StyleEnums::SkinParts skinPart = (option->state & State_On) ? QS60StyleEnums::SP_QgnIndiCheckboxOn : QS60StyleEnums::SP_QgnIndiCheckboxOff; painter->save(); const QColor themeColor = QS60StylePrivate::themePalette()->windowText().color(); const QColor windowTextColor = option->palette.windowText().color(); if (themeColor != windowTextColor) painter->setPen(windowTextColor); QS60StylePrivate::drawSkinPart(skinPart, painter, option->rect, flags | QS60StylePrivate::SF_ColorSkinned ); painter->restore(); } break; case PE_IndicatorViewItemCheck: #ifndef QT_NO_ITEMVIEWS if (const QAbstractItemView *itemView = (qobject_cast(widget))) { if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast(option)) { const bool checkBoxVisible = vopt->features & QStyleOptionViewItemV2::HasCheckIndicator; const bool singleSelection = itemView->selectionMode() == QAbstractItemView::SingleSelection || itemView->selectionMode() == QAbstractItemView::NoSelection; // draw either checkbox at the beginning if (checkBoxVisible && singleSelection) { drawPrimitive(PE_IndicatorCheckBox, option, painter, widget); // ... or normal "tick" selection at the end. } else if (option->state & State_Selected) { QRect tickRect = option->rect; const int frameBorderWidth = QS60StylePrivate::pixelMetric(PM_FrameCornerWidth); // adjust tickmark rect to exclude frame border tickRect.adjust(0, -frameBorderWidth, 0, -frameBorderWidth); QS60StyleEnums::SkinParts skinPart = QS60StyleEnums::SP_QgnIndiMarkedAdd; QS60StylePrivate::drawSkinPart(skinPart, painter, tickRect, (flags | QS60StylePrivate::SF_ColorSkinned)); } } } #endif //QT_NO_ITEMVIEWS break; case PE_IndicatorRadioButton: { QRect buttonRect = option->rect; //there is empty (a. 33%) space in svg graphics for radiobutton const qreal reduceWidth = (qreal)buttonRect.width() / 3.0; const qreal rectWidth = (qreal)option->rect.width() != 0 ? option->rect.width() : 1.0; // Try to occupy the full area const qreal scaler = 1 + (reduceWidth/rectWidth); buttonRect.setWidth((int)((buttonRect.width()-reduceWidth) * scaler)); buttonRect.setHeight((int)(buttonRect.height() * scaler)); // move the rect up for half of the new height-gain const int newY = (buttonRect.bottomRight().y() - option->rect.bottomRight().y()) >> 1 ; buttonRect.adjust(0, -newY, -1, -newY); painter->save(); const QColor themeColor = QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 6, option); const QColor buttonTextColor = option->palette.buttonText().color(); if (themeColor != buttonTextColor) painter->setPen(buttonTextColor); else painter->setPen(themeColor); // Draw radiobutton indicator as color skinned graphics. QS60StyleEnums::SkinParts skinPart = (option->state & State_On) ? QS60StyleEnums::SP_QgnIndiRadiobuttOn : QS60StyleEnums::SP_QgnIndiRadiobuttOff; QS60StylePrivate::drawSkinPart(skinPart, painter, buttonRect, (flags | QS60StylePrivate::SF_ColorSkinned)); painter->restore(); } break; case PE_PanelButtonCommand: case PE_PanelButtonTool: case PE_PanelButtonBevel: case PE_FrameButtonBevel: if (QS60StylePrivate::canDrawThemeBackground(option->palette.base(), widget)) { const bool isPressed = option->state & State_Sunken; const QS60StylePrivate::SkinElements skinElement = isPressed ? QS60StylePrivate::SE_ButtonPressed : QS60StylePrivate::SE_ButtonNormal; QS60StylePrivate::drawSkinElement(skinElement, painter, option->rect, flags); } else { commonStyleDraws = true; } break; #ifndef QT_NO_TOOLBUTTON case PE_IndicatorArrowDown: case PE_IndicatorArrowLeft: case PE_IndicatorArrowRight: case PE_IndicatorArrowUp: { QS60StyleEnums::SkinParts skinPart; if (element==PE_IndicatorArrowDown) skinPart = QS60StyleEnums::SP_QgnGrafScrollArrowDown; else if (element==PE_IndicatorArrowLeft) skinPart = QS60StyleEnums::SP_QgnGrafScrollArrowLeft; else if (element==PE_IndicatorArrowRight) skinPart = QS60StyleEnums::SP_QgnGrafScrollArrowRight; else if (element==PE_IndicatorArrowUp) skinPart = QS60StyleEnums::SP_QgnGrafScrollArrowUp; QS60StylePrivate::drawSkinPart(skinPart, painter, option->rect, flags); } break; #endif //QT_NO_TOOLBUTTON #ifndef QT_NO_SPINBOX case PE_IndicatorSpinDown: case PE_IndicatorSpinUp: if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast(option)) { if (QS60StylePrivate::canDrawThemeBackground(spinBox->palette.base(), widget)) { QStyleOptionSpinBox optionSpinBox = *spinBox; const QS60StyleEnums::SkinParts part = (element == PE_IndicatorSpinUp) ? QS60StyleEnums::SP_QgnGrafScrollArrowUp : QS60StyleEnums::SP_QgnGrafScrollArrowDown; const int iconMargin = QS60StylePrivate::pixelMetric(PM_FrameCornerWidth) >> 1; optionSpinBox.rect.translate(0, (element == PE_IndicatorSpinDown) ? iconMargin : -iconMargin ); QS60StylePrivate::drawSkinPart(part, painter, optionSpinBox.rect, flags); } else { commonStyleDraws = true; } } #endif //QT_NO_SPINBOX #ifndef QT_NO_COMBOBOX if (const QStyleOptionFrame *cmb = qstyleoption_cast(option)) { if (QS60StylePrivate::canDrawThemeBackground( option->palette.base(), widget)) { // We want to draw down arrow here for comboboxes as well. QStyleOptionFrame optionsComboBox = *cmb; const QS60StyleEnums::SkinParts part = QS60StyleEnums::SP_QgnGrafScrollArrowDown; const int iconMargin = QS60StylePrivate::pixelMetric(PM_FrameCornerWidth) >> 1; optionsComboBox.rect.translate(0, (element == PE_IndicatorSpinDown) ? iconMargin : -iconMargin ); QS60StylePrivate::drawSkinPart(part, painter, optionsComboBox.rect, flags); } else { commonStyleDraws = true; } } #endif //QT_NO_COMBOBOX break; case PE_IndicatorSpinMinus: case PE_IndicatorSpinPlus: if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast(option)) { QStyleOptionSpinBox optionSpinBox = *spinBox; QCommonStyle::drawPrimitive(element, &optionSpinBox, painter, widget); } #ifndef QT_NO_COMBOBOX else if (const QStyleOptionFrame *cmb = qstyleoption_cast(option)) { // We want to draw down arrow here for comboboxes as well. QStyleOptionFrame comboBox = *cmb; const int frameWidth = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); comboBox.rect.adjust(0, frameWidth, 0, -frameWidth); QCommonStyle::drawPrimitive(element, &comboBox, painter, widget); } #endif //QT_NO_COMBOBOX break; case PE_Widget: if (QS60StylePrivate::drawsOwnThemeBackground(widget) #ifndef QT_NO_COMBOBOX || qobject_cast(widget) #endif //QT_NO_COMBOBOX #ifndef QT_NO_MENU || qobject_cast (widget) #endif //QT_NO_MENU ) { //Need extra check since dialogs have their own theme background if (QS60StylePrivate::canDrawThemeBackground(option->palette.base(), widget) && option->palette.window().texture().cacheKey() == QS60StylePrivate::m_themePalette->window().texture().cacheKey()) //todo: for combobox listviews, the background should include area for menu scrollers, //but this produces drawing issues as we need to turn clipping off. QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_PopupBackground, painter, option->rect, flags); else commonStyleDraws = true; } break; case PE_FrameWindow: case PE_FrameTabWidget: if (const QStyleOptionTabWidgetFrame *tabFrame = qstyleoption_cast(option)) { QStyleOptionTabWidgetFrame optionTabFrame = *tabFrame; QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_PanelBackground, painter, optionTabFrame.rect, flags); } break; case PE_IndicatorHeaderArrow: if (const QStyleOptionHeader *header = qstyleoption_cast(option)) { if (header->sortIndicator & QStyleOptionHeader::SortUp) drawPrimitive(PE_IndicatorArrowUp, header, painter, widget); else if (header->sortIndicator & QStyleOptionHeader::SortDown) drawPrimitive(PE_IndicatorArrowDown, header, painter, widget); } // QStyleOptionHeader::None is not drawn => not needed break; #ifndef QT_NO_GROUPBOX case PE_FrameGroupBox: if (const QStyleOptionFrameV2 *frame = qstyleoption_cast(option)) QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_SettingsList, painter, frame->rect, flags); break; #endif //QT_NO_GROUPBOX // Qt3 primitives are not supported case PE_Q3CheckListController: case PE_Q3CheckListExclusiveIndicator: case PE_Q3CheckListIndicator: case PE_Q3DockWindowSeparator: case PE_Q3Separator: Q_ASSERT(false); break; case PE_Frame: break; #ifndef QT_NO_ITEMVIEWS case PE_PanelItemViewItem: if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast(option)) { const bool isSelected = (vopt->state & State_Selected); const bool hasFocus = (vopt->state & State_HasFocus); const bool isPressed = QS60StylePrivate::isWidgetPressed(widget); if (option->palette.highlight().color() == QS60StylePrivate::themePalette()->highlight().color()) { QRect highlightRect = vopt->rect.adjusted(1,1,-1,-1); const QAbstractItemView *itemView = qobject_cast(widget); QAbstractItemView::SelectionBehavior selectionBehavior = itemView ? itemView->selectionBehavior() : QAbstractItemView::SelectItems; // Set the draw area for highlights (focus, select rect or pressed rect) if (hasFocus || isSelected || isPressed) { if (selectionBehavior != QAbstractItemView::SelectItems) { // set highlight rect so that it is continuous from cell to cell, yet sligthly // smaller than cell rect int xBeginning = 0, yBeginning = 0, xEnd = 0, yEnd = 0; if (selectionBehavior == QAbstractItemView::SelectRows) { yBeginning = 1; yEnd = -1; if (vopt->viewItemPosition == QStyleOptionViewItemV4::Beginning) xBeginning = 1; else if (vopt->viewItemPosition == QStyleOptionViewItemV4::End) xEnd = -1; } else if (selectionBehavior == QAbstractItemView::SelectColumns) { xBeginning = 1; xEnd = -1; if (vopt->viewItemPosition == QStyleOptionViewItemV4::Beginning) yBeginning = 1; else if (vopt->viewItemPosition == QStyleOptionViewItemV4::End) yEnd = -1; } highlightRect = option->rect.adjusted(xBeginning, yBeginning, xEnd, yEnd); } } bool tableView = false; if (itemView && qobject_cast(widget)) tableView = true; QS60StylePrivate::SkinElements element; QRect elementRect = option->rect; //draw item is drawn as pressed, if it already has focus. if (isPressed && (hasFocus || isSelected)) { element = tableView ? QS60StylePrivate::SE_TableItemPressed : QS60StylePrivate::SE_ListItemPressed; } else if (hasFocus || (isSelected && selectionBehavior != QAbstractItemView::SelectItems)) { element = QS60StylePrivate::SE_ListHighlight; elementRect = highlightRect; } QS60StylePrivate::drawSkinElement(element, painter, elementRect, flags); } else { QCommonStyle::drawPrimitive(element, option, painter, widget); } } break; #endif //QT_NO_ITEMVIEWS case PE_IndicatorMenuCheckMark: if (const QStyleOptionMenuItem *checkBox = qstyleoption_cast(option)){ QStyleOptionMenuItem optionCheckBox = *checkBox; if (optionCheckBox.checked) optionCheckBox.state = (optionCheckBox.state | State_On); drawPrimitive(PE_IndicatorCheckBox, &optionCheckBox, painter, widget); } break; #ifndef QT_NO_TOOLBAR case PE_IndicatorToolBarHandle: // no toolbar handles in S60/AVKON UI case PE_IndicatorToolBarSeparator: // no separators in S60/AVKON UI break; #endif //QT_NO_TOOLBAR case PE_PanelMenuBar: case PE_FrameMenu: break; //disable frame in menu case PE_IndicatorBranch: #if defined(Q_WS_S60) // 3.1 AVKON UI does not have tree view component, use common style for drawing there if (QSysInfo::s60Version() == QSysInfo::SV_S60_3_1) { #else if (true) { #endif QCommonStyle::drawPrimitive(element, option, painter, widget); } else { if (const QStyleOptionViewItemV2 *vopt = qstyleoption_cast(option)) { const bool rightLine = option->state & State_Item; const bool downLine = option->state & State_Sibling; const bool upLine = option->state & (State_Open | State_Children | State_Item | State_Sibling); QS60StylePrivate::SkinElementFlags adjustedFlags = flags; QS60StyleEnums::SkinParts skinPart; bool drawSkinPart = false; if (rightLine && downLine && upLine) { skinPart = QS60StyleEnums::SP_QgnIndiHlLineBranch; drawSkinPart = true; } else if (rightLine && upLine) { skinPart = QS60StyleEnums::SP_QgnIndiHlLineEnd; drawSkinPart = true; } else if (upLine && downLine) { skinPart = QS60StyleEnums::SP_QgnIndiHlLineStraight; drawSkinPart = true; } if (option->direction == Qt::RightToLeft) adjustedFlags |= QS60StylePrivate::SF_Mirrored_X_Axis; if (drawSkinPart) QS60StylePrivate::drawSkinPart(skinPart, painter, option->rect, adjustedFlags); if (option->state & State_Children) { QS60StyleEnums::SkinParts skinPart = (option->state & State_Open) ? QS60StyleEnums::SP_QgnIndiHlColSuper : QS60StyleEnums::SP_QgnIndiHlExpSuper; const QRect selectionRect = subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget); const int minDimension = qMin(option->rect.width(), option->rect.height()); const int magicTweak = (option->direction == Qt::RightToLeft) ? -3 : 3; //@todo: magic //The branch indicator icon in S60 is supposed to be superimposed on top of branch lines. QRect iconRect(QPoint(option->rect.left() + magicTweak, selectionRect.top() + 1), QSize(minDimension, minDimension)); if (!QS60StylePrivate::isTouchSupported()) iconRect.translate(0, -4); //@todo: magic QS60StylePrivate::drawSkinPart(skinPart, painter, iconRect, adjustedFlags); } } } break; case PE_PanelItemViewRow: // ### Qt 5: remove #ifndef QT_NO_ITEMVIEWS if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast(option)) { if (vopt->palette.base().texture().cacheKey() != QS60StylePrivate::m_themePalette->base().texture().cacheKey()) { //QPalette::Base has been changed, let commonstyle draw the item commonStyleDraws = true; } else { QPalette::ColorGroup cg = vopt->state & State_Enabled ? QPalette::Normal : QPalette::Disabled; if (cg == QPalette::Normal && !(vopt->state & State_Active)) cg = QPalette::Inactive; if (vopt->features & QStyleOptionViewItemV2::Alternate) painter->fillRect(vopt->rect, vopt->palette.brush(cg, QPalette::AlternateBase)); //apart from alternate base, no background for list item is drawn for S60Style } } #endif break; case PE_PanelScrollAreaCorner: break; case PE_IndicatorItemViewItemDrop: if (QS60StylePrivate::isTouchSupported()) QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_DropArea, painter, option->rect, flags); else commonStyleDraws = true; break; // todo: items are below with #ifdefs "just in case". in final version, remove all non-required cases case PE_FrameLineEdit: case PE_IndicatorDockWidgetResizeHandle: case PE_PanelTipLabel: #ifndef QT_NO_TABBAR case PE_IndicatorTabTear: // No tab tear in S60 #endif // QT_NO_TABBAR case PE_FrameDefaultButton: #ifndef QT_NO_DOCKWIDGET case PE_FrameDockWidget: #endif //QT_NO_DOCKWIDGET #ifndef QT_NO_PROGRESSBAR case PE_IndicatorProgressChunk: #endif //QT_NO_PROGRESSBAR #ifndef QT_NO_TOOLBAR case PE_PanelToolBar: #endif //QT_NO_TOOLBAR #ifndef QT_NO_COLUMNVIEW case PE_IndicatorColumnViewArrow: #endif //QT_NO_COLUMNVIEW case PE_FrameTabBarBase: // since tabs are in S60 always in navipane, let's use common style for tab base in Qt. default: commonStyleDraws = true; } if (commonStyleDraws) { QCommonStyle::drawPrimitive(element, option, painter, widget); } } /*! \reimp */ int QS60Style::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const { int metricValue = QS60StylePrivate::pixelMetric(metric); if (metricValue == KNotFound) metricValue = QCommonStyle::pixelMetric(metric, option, widget); // Menu scrollers should be set to zero height for combobox popups if (metric == PM_MenuScrollerHeight && !qobject_cast(widget)) metricValue = 0; //if layout direction is mirrored, switch left and right border margins if (option && option->direction == Qt::RightToLeft) { if (metric == PM_LayoutLeftMargin) metricValue = QS60StylePrivate::pixelMetric(PM_LayoutRightMargin); else if (metric == PM_LayoutRightMargin) metricValue = QS60StylePrivate::pixelMetric(PM_LayoutLeftMargin); } if (widget && (metric == PM_LayoutTopMargin)) if (widget->windowType() == Qt::Dialog) //double the top layout margin for dialogs, it is very close to real value //without having to define custom pixel metric metricValue *= 2; if (widget && (metric == PM_FocusFrameHMargin)) if (qobject_cast(widget)) //Halve the focus frame margin for table items metricValue /= 2; return metricValue; } /*! \reimp */ QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &csz, const QWidget *widget) const { QSize sz(csz); switch (ct) { case CT_ToolButton: sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); //FIXME properly - style should calculate the location of border frame-part sz += QSize(2 * pixelMetric(PM_ButtonMargin), 2 * pixelMetric(PM_ButtonMargin)); if (const QStyleOptionToolButton *toolBtn = qstyleoption_cast(opt)) if (toolBtn->subControls & SC_ToolButtonMenu) sz += QSize(pixelMetric(PM_MenuButtonIndicator), 0); break; case CT_PushButton: sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); //FIXME properly - style should calculate the location of border frame-part if (const QAbstractButton *buttonWidget = (qobject_cast(widget))) { if (buttonWidget->isCheckable()) sz += QSize(pixelMetric(PM_IndicatorWidth) + pixelMetric(PM_CheckBoxLabelSpacing), 0); const int iconHeight = (!buttonWidget->icon().isNull()) ? buttonWidget->iconSize().height() : 0; const int textHeight = (buttonWidget->text().length() > 0) ? buttonWidget->fontMetrics().size(Qt::TextSingleLine, buttonWidget->text()).height() : opt->fontMetrics.height(); const int decoratorHeight = (buttonWidget->isCheckable()) ? pixelMetric(PM_IndicatorHeight) : 0; const int contentHeight = qMax(qMax(iconHeight, decoratorHeight) + pixelMetric(PM_ButtonMargin), textHeight + 2*pixelMetric(PM_ButtonMargin)); sz.setHeight(qMax(sz.height(), contentHeight)); sz += QSize(2 * pixelMetric(PM_ButtonMargin), 0); } break; case CT_LineEdit: if (const QStyleOptionFrame *f = qstyleoption_cast(opt)) sz += QSize(2 * f->lineWidth, 4 * f->lineWidth); break; case CT_TabBarTab: { const QSize naviPaneSize = QS60StylePrivate::naviPaneSize(); sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget); if (naviPaneSize.height() > sz.height()) sz.setHeight(naviPaneSize.height()); // Adjust beginning tabbar item size, if scrollbuttons are used. This is to ensure that the // tabbar item content fits, since scrollbuttons are making beginning tabbar item smaller. int scrollButtonSize = 0; if (const QTabBar *tabBar = qobject_cast(widget)) scrollButtonSize = tabBar->usesScrollButtons() ? pixelMetric(PM_TabBarScrollButtonWidth) : 0; if (const QStyleOptionTab *tab = qstyleoption_cast(opt)) { const bool verticalTabs = tab->shape == QTabBar::RoundedEast || tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularEast || tab->shape == QTabBar::TriangularWest; if (tab->position == QStyleOptionTab::Beginning) sz += QSize(verticalTabs ? 0 : scrollButtonSize, !verticalTabs ? 0 : scrollButtonSize); } } break; case CT_MenuItem: case CT_ItemViewItem: if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast(opt)) { if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) { sz = QSize(); break; } } sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); //native items have small empty areas at the beginning and end of menu item sz.setWidth(sz.width() + 2 * pixelMetric(PM_MenuHMargin) + 2 * QS60StylePrivate::pixelMetric(PM_FrameCornerWidth)); if (QS60StylePrivate::isTouchSupported()) //Make itemview easier to use in touch devices //QCommonStyle does not adjust height with horizontal margin, it only adjusts width sz.setHeight(sz.height() + 2 * pixelMetric(PM_FocusFrameVMargin) - 8); //QCommonstyle adds 8 to height that this style handles through PM values break; #ifndef QT_NO_COMBOBOX case CT_ComboBox: { // Fixing Ui design issues with too wide QComboBoxes and greedy SizeHints // Make sure, that the combobox stays within the screen. const QSize desktopContentSize = QApplication::desktop()->availableGeometry().size() - QSize(pixelMetric(PM_LayoutLeftMargin) + pixelMetric(PM_LayoutRightMargin), 0); sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget). boundedTo(desktopContentSize); } break; #endif default: sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); break; } return sz; } /*! \reimp */ int QS60Style::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *widget, QStyleHintReturn *hret) const { int retValue = 0; switch (sh) { case SH_RequestSoftwareInputPanel: if (QS60StylePrivate::isSingleClickUi()) retValue = RSIP_OnMouseClick; else retValue = RSIP_OnMouseClickAndAlreadyFocused; break; case SH_ComboBox_Popup: retValue = true; break; case SH_Table_GridLineColor: retValue = int(QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 2, 0).rgba()); break; case SH_GroupBox_TextLabelColor: retValue = int(QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0).rgba()); break; case SH_ScrollBar_ScrollWhenPointerLeavesControl: retValue = true; break; case SH_Slider_SnapToValue: retValue = true; break; case SH_Slider_StopMouseOverSlider: retValue = true; break; case SH_LineEdit_PasswordCharacter: retValue = '*'; break; case SH_ComboBox_PopupFrameStyle: retValue = QFrame::NoFrame | QFrame::Plain; break; case SH_Dial_BackgroundRole: retValue = QPalette::Base; break; case SH_ItemView_ActivateItemOnSingleClick: { if (QS60StylePrivate::isSingleClickUi()) retValue = true; else if (opt && opt->state & QStyle::State_Selected) retValue = true; break; } case SH_ProgressDialog_TextLabelAlignment: retValue = (QApplication::layoutDirection() == Qt::LeftToRight) ? Qt::AlignLeft : Qt::AlignRight; break; case SH_Menu_SubMenuPopupDelay: retValue = 300; break; case SH_Menu_Scrollable: retValue = true; break; case SH_Menu_SelectionWrap: retValue = true; break; case SH_Menu_MouseTracking: retValue = true; break; case SH_ItemView_ShowDecorationSelected: retValue = true; break; case SH_ToolBar_Movable: retValue = false; break; case SH_BlinkCursorWhenTextSelected: retValue = true; break; case SH_UnderlineShortcut: retValue = 0; break; case SH_FormLayoutWrapPolicy: retValue = QFormLayout::WrapLongRows; break; case SH_ScrollBar_ContextMenu: retValue = false; break; default: retValue = QCommonStyle::styleHint(sh, opt, widget, hret); break; } return retValue; } /*! \reimp */ QRect QS60Style::subControlRect(ComplexControl control, const QStyleOptionComplex *option, SubControl scontrol, const QWidget *widget) const { QRect ret; switch (control) { #ifndef QT_NO_SCROLLBAR // This implementation of subControlRect(CC_ScrollBar..) basically just removes the SC_ScrollBarSubLine and SC_ScrollBarAddLine case CC_ScrollBar: if (const QStyleOptionSlider *scrollbarOption = qstyleoption_cast(option)) { const QRect scrollBarRect = scrollbarOption->rect; const bool isHorizontal = scrollbarOption->orientation == Qt::Horizontal; const int maxlen = isHorizontal ? scrollBarRect.width() : scrollBarRect.height(); int sliderlen; // calculate slider length if (scrollbarOption->maximum != scrollbarOption->minimum) { const uint range = scrollbarOption->maximum - scrollbarOption->minimum; sliderlen = (qint64(scrollbarOption->pageStep) * maxlen) / (range + scrollbarOption->pageStep); const int slidermin = pixelMetric(PM_ScrollBarSliderMin, scrollbarOption, widget); if (sliderlen < slidermin || range > (INT_MAX >> 1)) sliderlen = slidermin; if (sliderlen > maxlen) sliderlen = maxlen; } else { sliderlen = maxlen; } const int sliderstart = sliderPositionFromValue(scrollbarOption->minimum, scrollbarOption->maximum, scrollbarOption->sliderPosition, maxlen - sliderlen, scrollbarOption->upsideDown); switch (scontrol) { case SC_ScrollBarSubPage: // between top/left button and slider if (isHorizontal) ret.setRect(0, 0, sliderstart, scrollBarRect.height()); else ret.setRect(0, 0, scrollBarRect.width(), sliderstart); break; case SC_ScrollBarAddPage: { // between bottom/right button and slider const int addPageLength = sliderstart + sliderlen; if (isHorizontal) ret = scrollBarRect.adjusted(addPageLength, 0, 0, 0); else ret = scrollBarRect.adjusted(0, addPageLength, 0, 0); } break; case SC_ScrollBarGroove: ret = scrollBarRect; break; case SC_ScrollBarSlider: if (scrollbarOption->orientation == Qt::Horizontal) ret.setRect(sliderstart, 0, sliderlen, scrollBarRect.height()); else ret.setRect(0, sliderstart, scrollBarRect.width(), sliderlen); break; case SC_ScrollBarSubLine: // top/left button case SC_ScrollBarAddLine: // bottom/right button default: break; } ret = visualRect(scrollbarOption->direction, scrollBarRect, ret); } break; #endif // QT_NO_SCROLLBAR case CC_SpinBox: if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast(option)) { const int frameThickness = spinbox->frame ? pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget) : 0; const int buttonMargin = spinbox->frame ? 2 : 0; const int buttonContentWidth = QS60StylePrivate::pixelMetric(PM_ButtonIconSize) + 2 * buttonMargin; // Spinbox buttons should be no larger than one fourth of total width. // Thus, side-by-side buttons would take half of the total width. const int maxSize = qMax(spinbox->rect.width() / 4, buttonContentWidth); QSize buttonSize; buttonSize.setHeight(qMin(maxSize, qMax(8, spinbox->rect.height() - frameThickness))); //width should at least be equal to height buttonSize.setWidth(qMax(buttonSize.height(), buttonContentWidth)); buttonSize = buttonSize.expandedTo(QApplication::globalStrut()); // Normally spinbuttons should be side-by-side, but if spinbox grows very big // and spinbuttons reach their maximum size, they can be deployed one top of the other. const bool sideBySide = (buttonSize.height() * 2 < spinbox->rect.height()) ? false : true; const int y = frameThickness + spinbox->rect.y() + (spinbox->rect.height() - (sideBySide ? 1 : 2) * buttonSize.height()) / 2; const int x = spinbox->rect.x() + spinbox->rect.width() - frameThickness - (sideBySide ? 2 : 1) * buttonSize.width(); switch (scontrol) { case SC_SpinBoxUp: if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) return QRect(); ret = QRect(x, y, buttonSize.width(), buttonSize.height()); break; case SC_SpinBoxDown: if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) return QRect(); ret = QRect(x + (sideBySide ? buttonSize.width() : 0), y + (sideBySide ? 0 : buttonSize.height()), buttonSize.width(), buttonSize.height()); break; case SC_SpinBoxEditField: if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) ret = QRect( frameThickness, frameThickness, spinbox->rect.width() - 2 * frameThickness, spinbox->rect.height() - 2 * frameThickness); else ret = QRect( frameThickness, frameThickness, x - frameThickness, spinbox->rect.height() - 2 * frameThickness); break; case SC_SpinBoxFrame: ret = spinbox->rect; break; default: break; } ret = visualRect(spinbox->direction, spinbox->rect, ret); } break; case CC_ComboBox: if (const QStyleOptionComboBox *cmb = qstyleoption_cast(option)) { ret = cmb->rect; const int width = cmb->rect.width(); const int height = cmb->rect.height(); const int buttonIconSize = QS60StylePrivate::pixelMetric(PM_ButtonIconSize); const int buttonMargin = cmb->frame ? 2 : 0; // lets use spinbox frame here as well, as no combobox specific value available. const int frameThickness = cmb->frame ? pixelMetric(PM_SpinBoxFrameWidth, cmb, widget) : 0; const int buttonWidth = qMax(cmb->rect.height(), buttonIconSize); QSize buttonSize; buttonSize.setWidth(buttonWidth + 2 * buttonMargin); buttonSize.setHeight(qMax(8, (cmb->rect.height() >> 1) - frameThickness)); //buttons should be squares buttonSize = buttonSize.expandedTo(QApplication::globalStrut()); switch (scontrol) { case SC_ComboBoxArrow: { const int xposMod = cmb->rect.x() + width - buttonMargin - buttonWidth; const int ypos = cmb->rect.y(); ret.setRect(xposMod, ypos + buttonMargin, buttonWidth, height - 2 * buttonMargin); } break; case SC_ComboBoxEditField: { const int withFrameX = cmb->rect.x() + width - frameThickness - buttonSize.width(); ret = QRect( frameThickness, frameThickness, withFrameX - frameThickness, height - 2 * frameThickness); } break; case SC_ComboBoxListBoxPopup: { ret = QApplication::desktop()->availableGeometry(); } break; default: break; } ret = visualRect(cmb->direction, cmb->rect, ret); } break; case CC_GroupBox: if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast(option)) { ret = QCommonStyle::subControlRect(control, option, scontrol, widget); switch (scontrol) { case SC_GroupBoxCheckBox: //fallthrough case SC_GroupBoxLabel: { //slightly indent text and boxes, so that dialog border does not mess with them. const int horizontalSpacing = QS60StylePrivate::pixelMetric(PM_LayoutHorizontalSpacing); ret.adjust(2, horizontalSpacing - 3, 0, 0); } break; case SC_GroupBoxFrame: { const QRect textBox = subControlRect(control, option, SC_GroupBoxLabel, widget); const int tbHeight = textBox.height(); ret.translate(0, -ret.y()); // include title to within the groupBox frame ret.setHeight(ret.height() + tbHeight); if (widget && ret.bottom() > widget->rect().bottom()) ret.setBottom(widget->rect().bottom()); } break; default: break; } } break; case CC_ToolButton: if (const QStyleOptionToolButton *toolButton = qstyleoption_cast(option)) { const int indicatorRect = pixelMetric(PM_MenuButtonIndicator) + 2 * pixelMetric(PM_ButtonMargin); const int border = pixelMetric(PM_ButtonMargin) + pixelMetric(PM_DefaultFrameWidth); ret = toolButton->rect; const bool popup = (toolButton->features & (QStyleOptionToolButton::MenuButtonPopup | QStyleOptionToolButton::PopupDelay)) == QStyleOptionToolButton::MenuButtonPopup; switch (scontrol) { case SC_ToolButton: if (popup) ret.adjust(0, 0, -indicatorRect, 0); break; case SC_ToolButtonMenu: if (popup) ret.adjust(ret.width() - indicatorRect, border, -pixelMetric(PM_ButtonMargin), -border); break; default: break; } ret = visualRect(toolButton->direction, toolButton->rect, ret); } break; default: ret = QCommonStyle::subControlRect(control, option, scontrol, widget); } return ret; } /*! \reimp */ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, const QWidget *widget) const { QRect ret; switch (element) { case SE_RadioButtonFocusRect: ret = opt->rect; break; case SE_LineEditContents: { // in S60 the input text box doesn't start from line Edit's TL, but // a bit indented (8 pixels). const int KLineEditDefaultIndention = 8; ret = visualRect( opt->direction, opt->rect, opt->rect.adjusted(KLineEditDefaultIndention, 0, 0, 0)); } break; case SE_TabBarTearIndicator: ret = QRect(0, 0, 0, 0); break; case SE_TabWidgetTabBar: if (const QStyleOptionTabWidgetFrame *optionTab = qstyleoption_cast(opt)) { ret = QCommonStyle::subElementRect(element, opt, widget); if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast(opt)) { const int tabOverlapNoBorder = QS60StylePrivate::pixelMetric(PM_TabBarTabOverlap); const int tabOverlap = tabOverlapNoBorder - QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); const QTabWidget *tab = qobject_cast(widget); int gain = (tab) ? tabOverlap * tab->count() : 0; switch (twf->shape) { case QTabBar::RoundedNorth: case QTabBar::TriangularNorth: case QTabBar::RoundedSouth: case QTabBar::TriangularSouth: { if (widget) { // make sure that gain does not set the rect outside of widget boundaries if (twf->direction == Qt::RightToLeft) { if ((ret.left() - gain) < widget->rect().left()) gain = widget->rect().left() - ret.left(); ret.adjust(-gain, 0, 0, 0); } else { if ((ret.right() + gain) > widget->rect().right()) gain = widget->rect().right() - ret.right(); ret.adjust(0, 0, gain, 0); } } break; } default: { if (widget) { if ((ret.bottom() + gain) > widget->rect().bottom()) gain = widget->rect().bottom() - ret.bottom(); ret.adjust(0, 0, 0, gain); } break; } } } } break; case SE_ItemViewItemText: case SE_ItemViewItemDecoration: if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast(opt)) { const QListWidget *listItem = qobject_cast(widget); const bool multiSelection = !listItem ? false : listItem->selectionMode() == QAbstractItemView::MultiSelection || listItem->selectionMode() == QAbstractItemView::ExtendedSelection || listItem->selectionMode() == QAbstractItemView::ContiguousSelection; ret = QCommonStyle::subElementRect(element, opt, widget); // If both multiselect & check-state, then remove checkbox and move // text and decoration towards the beginning if (listItem && multiSelection && (vopt->features & QStyleOptionViewItemV2::HasCheckIndicator)) { const int verticalSpacing = QS60StylePrivate::pixelMetric(PM_LayoutVerticalSpacing); //const int horizontalSpacing = QS60StylePrivate::pixelMetric(PM_LayoutHorizontalSpacing); const int checkBoxRectWidth = subElementRect(SE_ItemViewItemCheckIndicator, opt, widget).width(); ret.adjust(-checkBoxRectWidth - verticalSpacing, 0, -checkBoxRectWidth - verticalSpacing, 0); } } else if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast(opt)) { const bool checkable = menuItem->checkType != QStyleOptionMenuItem::NotCheckable; const int indicatorWidth = checkable ? pixelMetric(PM_ListViewIconSize, opt, widget) : pixelMetric(PM_SmallIconSize, opt, widget); ret = menuItem->rect; QRect checkBoxRect = checkable ? menuItem->rect : QRect(); if (checkable) { checkBoxRect.setWidth(pixelMetric(PM_IndicatorWidth)); checkBoxRect.setHeight(pixelMetric(PM_IndicatorHeight)); } const int vSpacing = QS60StylePrivate::pixelMetric(PM_LayoutVerticalSpacing); //The vertical spacing is doubled; it needs one spacing to separate checkbox from //highlight and then it needs one to separate it whatever is shown after it (text/icon/both). const int moveByX = checkBoxRect.width() + 2 * vSpacing; if (element == SE_ItemViewItemDecoration) { if (menuItem->icon.isNull()) { ret = QRect(); } else { if (menuItem->direction == Qt::RightToLeft) ret.translate(ret.width() - indicatorWidth - moveByX, 0); else ret.translate(moveByX, 0); ret.setWidth(indicatorWidth); } } else { if (!menuItem->icon.isNull()) { if (menuItem->direction == Qt::LeftToRight) ret.adjust(indicatorWidth, 0, 0, 0); else ret.adjust(0, 0, -indicatorWidth, 0); } if (menuItem->direction == Qt::LeftToRight) ret.adjust(moveByX, 0, 0, 0); else ret.adjust(0, 0, -moveByX, 0); // Make room for submenu indicator if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu){ // submenu indicator is very small, so lets halve the rect if (menuItem->direction == Qt::LeftToRight) ret.adjust(0, 0, -(indicatorWidth >> 1), 0); else ret.adjust((indicatorWidth >> 1), 0, 0, 0); } } } break; case SE_ItemViewItemCheckIndicator: if (const QStyleOptionViewItemV2 *vopt = qstyleoption_cast(opt)) { const QListWidget *listItem = qobject_cast(widget); const bool singleSelection = listItem && (listItem->selectionMode() == QAbstractItemView::SingleSelection || listItem->selectionMode() == QAbstractItemView::NoSelection); const bool checkBoxOnly = (vopt->features & QStyleOptionViewItemV2::HasCheckIndicator) && listItem && singleSelection; // Selection check mark rect. const int indicatorWidth = QS60StylePrivate::pixelMetric(PM_IndicatorWidth); const int indicatorHeight = QS60StylePrivate::pixelMetric(PM_IndicatorHeight); const int spacing = QS60StylePrivate::pixelMetric(PM_CheckBoxLabelSpacing); const int itemHeight = opt->rect.height(); int heightOffset = 0; if (indicatorHeight < itemHeight) heightOffset = ((itemHeight - indicatorHeight) >> 1); if (checkBoxOnly) { // Move rect and make it slightly smaller, so that // a) highlight border does not cross the rect // b) in s60 list checkbox is smaller than normal checkbox //todo; magic three ret.setRect(opt->rect.left() + 3, opt->rect.top() + heightOffset, indicatorWidth - 3, indicatorHeight - 3); } else { ret.setRect(opt->rect.right() - indicatorWidth - spacing, opt->rect.top() + heightOffset, indicatorWidth, indicatorHeight); } } else { ret = QCommonStyle::subElementRect(element, opt, widget); } break; case SE_HeaderLabel: ret = QCommonStyle::subElementRect(element, opt, widget); if (qstyleoption_cast(opt)) { // Subtract area needed for line if (opt->state & State_Horizontal) ret.setHeight(ret.height() - QS60StylePrivate::pixelMetric(PM_BoldLineWidth)); else ret.setWidth(ret.width() - QS60StylePrivate::pixelMetric(PM_ThinLineWidth)); } ret = visualRect(opt->direction, opt->rect, ret); break; case SE_RadioButtonIndicator: { const int height = pixelMetric(PM_ExclusiveIndicatorHeight, opt, widget); ret.setRect(opt->rect.x(), opt->rect.y() + ((opt->rect.height() - height) >> 1), pixelMetric(PM_ExclusiveIndicatorWidth, opt, widget), height); ret.translate(2, 0); //move indicator slightly to avoid highlight crossing over it ret = visualRect(opt->direction, opt->rect, ret); } break; case SE_CheckBoxIndicator: { const int height = pixelMetric(PM_IndicatorHeight, opt, widget); ret.setRect(opt->rect.x(), opt->rect.y() + ((opt->rect.height() - height) >> 1), pixelMetric(PM_IndicatorWidth, opt, widget), height); ret.translate(2, 0); //move indicator slightly to avoid highlight crossing over it ret = visualRect(opt->direction, opt->rect, ret); } break; case SE_CheckBoxFocusRect: ret = opt->rect; break; case SE_ProgressBarLabel: case SE_ProgressBarContents: case SE_ProgressBarGroove: ret = opt->rect; break; default: ret = QCommonStyle::subElementRect(element, opt, widget); } return ret; } /*! \reimp */ void QS60Style::polish(QWidget *widget) { Q_D(const QS60Style); QCommonStyle::polish(widget); if (!widget) return; //Currently we only support animations in QProgressBar. #ifndef QT_NO_PROGRESSBAR if (qobject_cast(widget)) widget->installEventFilter(this); #endif if (false #ifndef QT_NO_SCROLLBAR || qobject_cast(widget) #endif ) { widget->setAttribute(Qt::WA_OpaquePaintEvent, false); } if (QS60StylePrivate::drawsOwnThemeBackground(widget)) { widget->setAttribute(Qt::WA_StyledBackground); } else if (false #ifndef QT_NO_MENU || qobject_cast (widget) #endif // QT_NO_MENU ) { widget->setAttribute(Qt::WA_StyledBackground); } else if (false #ifndef QT_NO_COMBOBOX || qobject_cast(widget) #endif //QT_NO_COMBOBOX ) { widget->setAttribute(Qt::WA_StyledBackground); } d->setThemePalette(widget); d->setFont(widget); } /*! \reimp */ void QS60Style::unpolish(QWidget *widget) { Q_D(QS60Style); if (false #ifndef QT_NO_SCROLLBAR || qobject_cast(widget) #endif ) widget->setAttribute(Qt::WA_OpaquePaintEvent); if (QS60StylePrivate::drawsOwnThemeBackground(widget)) { widget->setAttribute(Qt::WA_StyledBackground, false); } else if (false #ifndef QT_NO_MENU || qobject_cast (widget) #endif // QT_NO_MENU ) { widget->setAttribute(Qt::WA_StyledBackground, false); } else if (false #ifndef QT_NO_COMBOBOX || qobject_cast(widget) #endif //QT_NO_COMBOBOX ) { widget->setAttribute(Qt::WA_StyledBackground, false); } if (widget) widget->setPalette(QPalette()); #if defined(Q_WS_S60) && !defined(QT_NO_PROGRESSBAR) if (QProgressBar *bar = qobject_cast(widget)) { widget->removeEventFilter(this); d->m_bars.removeAll(bar); } #else Q_UNUSED(d) #endif QCommonStyle::unpolish(widget); } /*! \reimp */ void QS60Style::polish(QApplication *application) { Q_D(QS60Style); QCommonStyle::polish(qApp); d->m_originalPalette = application->palette(); d->setThemePalette(application); if (QS60StylePrivate::isTouchSupported()) qApp->installEventFilter(this); } /*! \reimp */ void QS60Style::unpolish(QApplication *application) { Q_UNUSED(application) Q_D(QS60Style); QCommonStyle::unpolish(qApp); const QPalette newPalette = QApplication::style()->standardPalette(); QApplication::setPalette(newPalette); QApplicationPrivate::setSystemPalette(d->m_originalPalette); if (QS60StylePrivate::isTouchSupported()) qApp->removeEventFilter(this); } /*! \reimp */ bool QS60Style::event(QEvent *e) { #ifdef QT_KEYPAD_NAVIGATION Q_D(QS60Style); const QEvent::Type eventType = e->type(); if ((eventType == QEvent::FocusIn || eventType == QEvent::FocusOut || eventType == QEvent::EnterEditFocus || eventType == QEvent::LeaveEditFocus) && QS60StylePrivate::isTouchSupported()) return false; #endif switch (e->type()) { case QEvent::Timer: { QTimerEvent *te = static_cast(e); timerEvent(te); } break; #ifdef QT_KEYPAD_NAVIGATION case QEvent::FocusIn: if (QWidget *focusWidget = QApplication::focusWidget()) { // Menus and combobox popups do not draw focus frame around them if (qobject_cast(focusWidget) || qobject_cast(focusWidget)) break; if (!d->m_focusFrame) d->m_focusFrame = new QFocusFrame(focusWidget); d->m_focusFrame->setWidget(focusWidget); } else if (d->m_focusFrame) { d->m_focusFrame->setWidget(0); } break; case QEvent::FocusOut: if (d->m_focusFrame) d->m_focusFrame->setWidget(0); break; case QEvent::EnterEditFocus: case QEvent::LeaveEditFocus: if (d->m_focusFrame) d->m_focusFrame->update(); break; #endif default: break; } return false; } /*! \internal */ QIcon QS60Style::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const { const int iconDimension = QS60StylePrivate::pixelMetric(PM_ToolBarIconSize); const QRect iconSize = (!option) ? QRect(0, 0, iconDimension, iconDimension) : option->rect; QS60StyleEnums::SkinParts part; QS60StylePrivate::SkinElementFlags adjustedFlags; if (option) adjustedFlags = (option->state & State_Enabled || option->state == 0) ? QS60StylePrivate::SF_StateEnabled : QS60StylePrivate::SF_StateDisabled; switch(standardIcon) { case SP_MessageBoxWarning: part = QS60StyleEnums::SP_QgnNoteWarning; break; case SP_MessageBoxInformation: part = QS60StyleEnums::SP_QgnNoteInfo; break; case SP_MessageBoxCritical: part = QS60StyleEnums::SP_QgnNoteError; break; case SP_MessageBoxQuestion: part = QS60StyleEnums::SP_QgnNoteQuery; break; case SP_ArrowRight: part = QS60StyleEnums::SP_QgnIndiNaviArrowRight; break; case SP_ArrowLeft: part = QS60StyleEnums::SP_QgnIndiNaviArrowLeft; break; case SP_ArrowUp: part = QS60StyleEnums::SP_QgnIndiNaviArrowLeft; adjustedFlags |= QS60StylePrivate::SF_PointEast; break; case SP_ArrowDown: part = QS60StyleEnums::SP_QgnIndiNaviArrowLeft; adjustedFlags |= QS60StylePrivate::SF_PointWest; break; case SP_ArrowBack: if (QApplication::layoutDirection() == Qt::RightToLeft) return QS60Style::standardIcon(SP_ArrowRight, option, widget); return QS60Style::standardIcon(SP_ArrowLeft, option, widget); case SP_ArrowForward: if (QApplication::layoutDirection() == Qt::RightToLeft) return QS60Style::standardIcon(SP_ArrowLeft, option, widget); return QS60Style::standardIcon(SP_ArrowRight, option, widget); case SP_ComputerIcon: part = QS60StyleEnums::SP_QgnPropPhoneMemcLarge; break; case SP_DirClosedIcon: part = QS60StyleEnums::SP_QgnPropFolderSmall; break; case SP_DirOpenIcon: part = QS60StyleEnums::SP_QgnPropFolderCurrent; break; case SP_DirIcon: part = QS60StyleEnums::SP_QgnPropFolderSmall; break; case SP_FileDialogNewFolder: part = QS60StyleEnums::SP_QgnPropFolderSmallNew; break; case SP_FileIcon: part = QS60StyleEnums::SP_QgnPropFileSmall; break; case SP_TrashIcon: part = QS60StyleEnums::SP_QgnNoteErased; break; case SP_ToolBarHorizontalExtensionButton: part = QS60StyleEnums::SP_QgnIndiSubmenu; if (QApplication::layoutDirection() == Qt::RightToLeft) adjustedFlags |= QS60StylePrivate::SF_PointSouth; break; case SP_ToolBarVerticalExtensionButton: adjustedFlags |= QS60StylePrivate::SF_PointEast; part = QS60StyleEnums::SP_QgnIndiSubmenu; break; default: return QCommonStyle::standardIconImplementation(standardIcon, option, widget); } const QS60StylePrivate::SkinElementFlags flags = adjustedFlags; const QPixmap cachedPixMap(QS60StylePrivate::cachedPart(part, iconSize.size(), 0, flags)); return cachedPixMap.isNull() ? QCommonStyle::standardIconImplementation(standardIcon, option, widget) : QIcon(cachedPixMap); } /*! \internal Animate indeterminate progress bars only when visible */ bool QS60Style::eventFilter(QObject *object, QEvent *event) { Q_D(QS60Style); switch(event->type()) { case QEvent::MouseButtonPress: { QWidget *w = QApplication::widgetAt(QCursor::pos()); if (w) { QWidget *focusW = w->focusProxy(); if (qobject_cast(focusW) || qobject_cast(focusW) || qobject_cast(focusW)) d->m_pressedWidget = focusW; else if (qobject_cast(w)|| qobject_cast(w) || qobject_cast(w)) d->m_pressedWidget = w; if ( d->m_pressedWidget) d->m_pressedWidget->update(); } break; } case QEvent::MouseButtonRelease: { const QWidget *w = QApplication::widgetAt(QCursor::pos()); if (w && d->m_pressedWidget) { d->m_pressedWidget->update(); d->m_pressedWidget = 0; } break; } default: break; } #ifdef Q_WS_S60 #ifndef QT_NO_PROGRESSBAR switch(event->type()) { case QEvent::StyleChange: case QEvent::Show: if (QProgressBar *bar = qobject_cast(object)) { if (!d->m_bars.contains(bar)) d->m_bars << bar; if (d->m_bars.size() == 1) //only start with first animated progressbar d->startAnimation(QS60StyleEnums::SP_QgnGrafBarWaitAnim); } break; case QEvent::Destroy: case QEvent::Hide: if (QProgressBar *bar = reinterpret_cast(object)) { d->stopAnimation(QS60StyleEnums::SP_QgnGrafBarWaitAnim); d->m_bars.removeAll(bar); } break; default: break; } #endif // QT_NO_PROGRESSBAR #endif // Q_WS_S60 return QCommonStyle::eventFilter(object, event); } /*! \internal Handle the timer \a event. */ void QS60Style::timerEvent(QTimerEvent *event) { #ifdef Q_WS_S60 #ifndef QT_NO_PROGRESSBAR Q_D(QS60Style); QS60StyleAnimation *progressBarAnimation = QS60StylePrivate::animationDefinition(QS60StyleEnums::SP_QgnGrafBarWaitAnim); if (event->timerId() == progressBarAnimation->timerId()) { Q_ASSERT(progressBarAnimation->interval() > 0); if (progressBarAnimation->currentFrame() == progressBarAnimation->frameCount() ) if (progressBarAnimation->playMode() == QS60StyleEnums::AM_Looping) progressBarAnimation->setCurrentFrame(0); else d->stopAnimation(progressBarAnimation->animationId()); foreach (QProgressBar *bar, d->m_bars) { if ((bar->minimum() == 0 && bar->maximum() == 0)) bar->update(); } progressBarAnimation->setCurrentFrame(progressBarAnimation->currentFrame() + 1); } #endif // QT_NO_PROGRESSBAR #endif // Q_WS_S60 event->ignore(); } extern QPoint qt_s60_fill_background_offset(const QWidget *targetWidget); bool qt_s60_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush) { const QPixmap backgroundTexture(QS60StylePrivate::backgroundTexture()); if (backgroundTexture.cacheKey() != brush.texture().cacheKey()) return false; const QPaintDevice *target = painter->device(); if (target->devType() == QInternal::Widget) { const QWidget *widget = static_cast(target); if (!widget->testAttribute(Qt::WA_TranslucentBackground)) { const QVector &rects = rgn.rects(); for (int i = 0; i < rects.size(); ++i) { const QRect rect(rects.at(i)); painter->drawPixmap(rect.topLeft(), backgroundTexture, rect.translated(qt_s60_fill_background_offset(widget))); } } } return true; } QT_END_NAMESPACE #endif // QT_NO_STYLE_S60 || QT_PLUGIN