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