Home | History | Annotate | Download | only in qt
      1 /*
      2  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Library General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Library General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Library General Public License
     15  * along with this library; see the file COPYING.LIB.  If not, write to
     16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  * Boston, MA 02110-1301, USA.
     18  *
     19  */
     20 #include "config.h"
     21 #include "QtMobileWebStyle.h"
     22 
     23 #include "QtStyleOptionWebComboBox.h"
     24 
     25 #include <QPainter>
     26 #include <QPixmapCache>
     27 #include <QStyleOption>
     28 
     29 QtMobileWebStyle::QtMobileWebStyle()
     30 {
     31 }
     32 
     33 static inline void drawRectangularControlBackground(QPainter* painter, const QPen& pen, const QRect& rect, const QBrush& brush)
     34 {
     35     QPen oldPen = painter->pen();
     36     QBrush oldBrush = painter->brush();
     37     painter->setRenderHint(QPainter::Antialiasing, true);
     38     painter->setPen(pen);
     39     painter->setBrush(brush);
     40 
     41     int line = 1;
     42     painter->drawRoundedRect(rect.adjusted(line, line, -line, -line),
     43             /* xRadius */ 5.0, /* yRadious */ 5.0);
     44     painter->setPen(oldPen);
     45     painter->setBrush(oldBrush);
     46 }
     47 
     48 void QtMobileWebStyle::drawChecker(QPainter* painter, int size, QColor color) const
     49 {
     50     int border = qMin(qMax(1, int(0.2 * size)), 6);
     51     int checkerSize = qMax(size - 2 * border, 3);
     52     int width = checkerSize / 3;
     53     int middle = qMax(3 * checkerSize / 7, 3);
     54     int x = ((size - checkerSize) >> 1);
     55     int y = ((size - checkerSize) >> 1) + (checkerSize - width - middle);
     56     QVector<QLineF> lines(checkerSize + 1);
     57     painter->setPen(color);
     58     for (int i = 0; i < middle; ++i) {
     59         lines[i] = QLineF(x, y, x, y + width);
     60         ++x;
     61         ++y;
     62     }
     63     for (int i = middle; i <= checkerSize; ++i) {
     64         lines[i] = QLineF(x, y, x, y + width);
     65         ++x;
     66         --y;
     67     }
     68     painter->drawLines(lines.constData(), lines.size());
     69 }
     70 
     71 QPixmap QtMobileWebStyle::findChecker(const QRect& rect, bool disabled) const
     72 {
     73     int size = qMin(rect.width(), rect.height());
     74     QPixmap result;
     75     static const QString prefix = QLatin1String("$qt-maemo5-") + QLatin1String(metaObject()->className())+ QLatin1String("-checker-");
     76     QString key = prefix + QString::number(size) + QLatin1String("-") + (disabled ? QLatin1String("disabled") : QLatin1String("enabled"));
     77     if (!QPixmapCache::find(key, result)) {
     78         result = QPixmap(size, size);
     79         result.fill(Qt::transparent);
     80         QPainter painter(&result);
     81         drawChecker(&painter, size, disabled ? Qt::lightGray : Qt::darkGray);
     82         QPixmapCache::insert(key, result);
     83     }
     84     return result;
     85 }
     86 
     87 void QtMobileWebStyle::drawRadio(QPainter* painter, const QSize& size, bool checked, QColor color) const
     88 {
     89     painter->setRenderHint(QPainter::Antialiasing, true);
     90 
     91     // get minor size to do not paint a wide elipse
     92     qreal squareSize = qMin(size.width(), size.height());
     93     // deflate one pixel
     94     QRect rect = QRect(QPoint(1, 1), QSize(squareSize - 2, squareSize - 2));
     95     const QPoint centerGradient(rect.bottomRight() * 0.7);
     96 
     97     QRadialGradient radialGradient(centerGradient, centerGradient.x() - 1);
     98     radialGradient.setColorAt(0.0, Qt::white);
     99     radialGradient.setColorAt(0.6, Qt::white);
    100     radialGradient.setColorAt(1.0, color);
    101 
    102     painter->setPen(color);
    103     painter->setBrush(color);
    104     painter->drawEllipse(rect);
    105     painter->setBrush(radialGradient);
    106     painter->drawEllipse(rect);
    107 
    108     int border = 0.1 * (rect.width() + rect.height());
    109     border = qMin(qMax(2, border), 10);
    110     rect.adjust(border, border, -border, -border);
    111     if (checked) {
    112         painter->setPen(Qt::NoPen);
    113         painter->setBrush(color);
    114         painter->drawEllipse(rect);
    115     }
    116 }
    117 
    118 QPixmap QtMobileWebStyle::findRadio(const QSize& size, bool checked, bool disabled) const
    119 {
    120     QPixmap result;
    121     static const QString prefix = QLatin1String("$qt-maemo5-") + QLatin1String(metaObject()->className()) + QLatin1String("-radio-");
    122     QString key = prefix + QString::number(size.width()) + QLatin1String("-") + QString::number(size.height()) + QLatin1String("-")
    123         + (disabled ? QLatin1String("disabled") : QLatin1String("enabled")) + (checked ? QLatin1String("-checked") : QLatin1String(""));
    124     if (!QPixmapCache::find(key, result)) {
    125         result = QPixmap(size);
    126         result.fill(Qt::transparent);
    127         QPainter painter(&result);
    128         drawRadio(&painter, size, checked, disabled ? Qt::lightGray : Qt::darkGray);
    129         QPixmapCache::insert(key, result);
    130     }
    131     return result;
    132 }
    133 
    134 void QtMobileWebStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
    135 {
    136     switch (element) {
    137     case CE_CheckBox: {
    138         QRect rect = option->rect;
    139         const bool disabled = !(option->state & State_Enabled);
    140 
    141         QLinearGradient linearGradient(rect.topLeft(), rect.bottomLeft());
    142         if (disabled) {
    143             linearGradient.setColorAt(0.0, Qt::lightGray);
    144             linearGradient.setColorAt(0.5, Qt::white);
    145         } else {
    146             linearGradient.setColorAt(0.0, Qt::darkGray);
    147             linearGradient.setColorAt(0.5, Qt::white);
    148         }
    149 
    150         painter->setPen(QPen(disabled ? Qt::lightGray : Qt::darkGray));
    151         painter->setBrush(linearGradient);
    152         painter->drawRect(rect);
    153         rect.adjust(1, 1, -1, -1);
    154 
    155         if (option->state & State_Off)
    156             break;
    157 
    158         QPixmap checker = findChecker(rect, disabled);
    159         if (checker.isNull())
    160             break;
    161 
    162         int x = (rect.width() - checker.width()) >> 1;
    163         int y = (rect.height() - checker.height()) >> 1;
    164         painter->drawPixmap(rect.x() + x, rect.y() + y, checker);
    165         break;
    166     }
    167     case CE_RadioButton: {
    168         const bool disabled = !(option->state & State_Enabled);
    169         QPixmap radio = findRadio(option->rect.size(), option->state & State_On, disabled);
    170         if (radio.isNull())
    171             break;
    172         painter->drawPixmap(option->rect.x(), option->rect.y(), radio);
    173         break;
    174     }
    175     case CE_PushButton: {
    176         const bool disabled = !(option->state & State_Enabled);
    177         QRect rect = option->rect;
    178         QPen pen(Qt::darkGray, 1.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
    179         painter->setPen(pen);
    180 
    181         const bool sunken = (option->state & State_Sunken);
    182         if (sunken) {
    183             drawRectangularControlBackground(painter, pen, rect, QBrush(Qt::darkGray));
    184             break;
    185         }
    186 
    187         QLinearGradient linearGradient;
    188         if (disabled) {
    189             linearGradient.setStart(rect.bottomLeft());
    190             linearGradient.setFinalStop(rect.topLeft());
    191             linearGradient.setColorAt(0.0, Qt::gray);
    192             linearGradient.setColorAt(1.0, Qt::white);
    193         } else {
    194             linearGradient.setStart(rect.bottomLeft());
    195             linearGradient.setFinalStop(QPoint(rect.bottomLeft().x(),
    196                         rect.bottomLeft().y() - /* offset limit for gradient */ 20));
    197             linearGradient.setColorAt(0.0, Qt::gray);
    198             linearGradient.setColorAt(0.4, Qt::white);
    199         }
    200 
    201         drawRectangularControlBackground(painter, pen, rect, linearGradient);
    202         break;
    203     }
    204     default:
    205         QWindowsStyle::drawControl(element, option, painter, widget);
    206     }
    207 }
    208 void QtMobileWebStyle::drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
    209 {
    210     switch (element) {
    211     case QStyle::PE_PanelLineEdit: {
    212         const bool disabled = !(option->state & State_Enabled);
    213         const bool sunken = (option->state & State_Sunken);
    214         QRect rect = option->rect;
    215         QPen pen(Qt::darkGray, 1.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
    216         painter->setPen(pen);
    217 
    218         if (sunken) {
    219             drawRectangularControlBackground(painter, pen, rect, QBrush(Qt::darkGray));
    220             break;
    221         }
    222 
    223         QLinearGradient linearGradient;
    224         if (disabled) {
    225             linearGradient.setStart(rect.topLeft());
    226             linearGradient.setFinalStop(rect.bottomLeft());
    227             linearGradient.setColorAt(0.0, Qt::lightGray);
    228             linearGradient.setColorAt(1.0, Qt::white);
    229         } else {
    230             linearGradient.setStart(rect.topLeft());
    231             linearGradient.setFinalStop(QPoint(rect.topLeft().x(),
    232                         rect.topLeft().y() + /* offset limit for gradient */ 20));
    233             linearGradient.setColorAt(0.0, Qt::darkGray);
    234             linearGradient.setColorAt(0.35, Qt::white);
    235         }
    236 
    237         drawRectangularControlBackground(painter, pen, rect, linearGradient);
    238         break;
    239     }
    240     default:
    241         QWindowsStyle::drawPrimitive(element, option, painter, widget);
    242     }
    243 }
    244 
    245 void QtMobileWebStyle::drawMultipleComboButton(QPainter* painter, const QSize& size, QColor color) const
    246 {
    247     int rectWidth = size.width() - 1;
    248     int width = qMax(2, rectWidth >> 3);
    249     int distance = (rectWidth - 3 * width) >> 1;
    250     int top = (size.height() - width) >> 1;
    251 
    252     painter->setPen(color);
    253     painter->setBrush(color);
    254 
    255     painter->drawRect(0, top, width, width);
    256     painter->drawRect(width + distance, top, width, width);
    257     painter->drawRect(2 * (width + distance), top, width, width);
    258 }
    259 
    260 void QtMobileWebStyle::drawSimpleComboButton(QPainter* painter, const QSize& size, QColor color) const
    261 {
    262     int width = size.width();
    263     int midle = width >> 1;
    264     QVector<QLine> lines(width + 1);
    265 
    266     for (int x = 0, y = 0;  x < midle; x++, y++) {
    267         lines[x] = QLine(x, y, x, y + 2);
    268         lines[x + midle] = QLine(width - x - 1, y, width - x - 1, y + 2);
    269     }
    270     // Just to ensure the lines' intersection.
    271     lines[width] = QLine(midle, midle, midle, midle + 2);
    272 
    273     painter->setPen(color);
    274     painter->setBrush(color);
    275     painter->drawLines(lines);
    276 }
    277 
    278 QSize QtMobileWebStyle::getButtonImageSize(const QSize& buttonSize) const
    279 {
    280     const int border = qMax(3, buttonSize.width() >> 3) << 1;
    281 
    282     int width = buttonSize.width() - border;
    283     int height = buttonSize.height() - border;
    284 
    285     if (width < 0 || height < 0)
    286         return QSize();
    287 
    288     if (height >= (width >> 1))
    289         width = width >> 1 << 1;
    290     else
    291         width = height << 1;
    292 
    293     return QSize(width + 1, width);
    294 }
    295 
    296 QPixmap QtMobileWebStyle::findComboButton(const QSize& size, bool multiple, bool disabled) const
    297 {
    298     QPixmap result;
    299     QSize imageSize = getButtonImageSize(size);
    300 
    301     if (imageSize.isNull())
    302         return QPixmap();
    303     static const QString prefix = QLatin1String("$qt-maemo5-") + QLatin1String(metaObject()->className()) + QLatin1String("-combo-");
    304     QString key = prefix + (multiple ? QLatin1String("multiple-") : QLatin1String("simple-"))
    305         + QString::number(imageSize.width()) + QLatin1String("-") + QString::number(imageSize.height())
    306         + QLatin1String("-") + (disabled ? QLatin1String("disabled") : QLatin1String("enabled"));
    307     if (!QPixmapCache::find(key, result)) {
    308         result = QPixmap(imageSize);
    309         result.fill(Qt::transparent);
    310         QPainter painter(&result);
    311         if (multiple)
    312             drawMultipleComboButton(&painter, imageSize, disabled ? Qt::lightGray : Qt::darkGray);
    313         else
    314             drawSimpleComboButton(&painter, imageSize, disabled ? Qt::lightGray : Qt::darkGray);
    315         QPixmapCache::insert(key, result);
    316     }
    317     return result;
    318 }
    319 
    320 void QtMobileWebStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const
    321 {
    322     switch (control) {
    323     case CC_ComboBox: {
    324         bool multiple = false;
    325         const bool disabled = !(option->state & State_Enabled);
    326 
    327         const QStyleOptionComboBox* cmb = 0;
    328         const WebCore::QtStyleOptionWebComboBox* webCombo = static_cast<const WebCore::QtStyleOptionWebComboBox*>(option);
    329 
    330         if (webCombo) {
    331             multiple = webCombo->multiple();
    332             cmb = webCombo;
    333         } else
    334             cmb = qstyleoption_cast<const QStyleOptionComboBox*>(option);
    335 
    336         if (!cmb) {
    337             QWindowsStyle::drawComplexControl(control, option, painter, widget);
    338             break;
    339         }
    340 
    341         if (!(cmb->subControls & SC_ComboBoxArrow))
    342             break;
    343 
    344         QRect rect = option->rect;
    345         QPen pen(Qt::darkGray, 1.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
    346         QLinearGradient linearGradient;
    347         if (disabled) {
    348             linearGradient.setStart(rect.bottomLeft());
    349             linearGradient.setFinalStop(rect.topLeft());
    350             linearGradient.setColorAt(0.0, Qt::gray);
    351             linearGradient.setColorAt(1.0, Qt::white);
    352         } else {
    353             linearGradient.setStart(rect.bottomLeft());
    354             linearGradient.setFinalStop(QPoint(rect.bottomLeft().x(),
    355                         rect.bottomLeft().y() - /* offset limit for gradient */ 20));
    356             linearGradient.setColorAt(0.0, Qt::gray);
    357             linearGradient.setColorAt(0.4, Qt::white);
    358         }
    359 
    360         drawRectangularControlBackground(painter, pen, rect, linearGradient);
    361 
    362         rect = subControlRect(CC_ComboBox, cmb, SC_ComboBoxArrow, widget);
    363         QPixmap pic = findComboButton(rect.size(), multiple, disabled);
    364 
    365         if (pic.isNull())
    366             break;
    367 
    368         int x = (rect.width() - pic.width()) >> 1;
    369         int y = (rect.height() - pic.height()) >> 1;
    370         painter->drawPixmap(rect.x() + x, rect.y() + y, pic);
    371 
    372         painter->setPen(disabled ? Qt::gray : Qt::darkGray);
    373         painter->drawLine(rect.left() - 2, rect.top() + 2, rect.left() - 2, rect.bottom() - 2);
    374 
    375         break;
    376     }
    377     default:
    378         QWindowsStyle::drawComplexControl(control, option, painter, widget);
    379     }
    380 }
    381 
    382