2 ******************************************************************************
4 * @file stylehelper.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
8 * @see The GNU Public License (GPL) Version 3
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "stylehelper.h"
31 #include "hostosinfo.h"
33 #include <QPixmapCache>
35 #include <QApplication>
36 #include <QStyleOption>
39 // Clamps float color values within (0, 255)
40 static int clamp(float x
)
42 const int val
= x
> 255 ? 255 : static_cast<int>(x
);
44 return val
< 0 ? 0 : val
;
47 // Clamps float color values within (0, 255)
49 static int range(float x, int min, int max)
51 int val = x > max ? max : x;
52 return val < min ? min : val;
57 QColor
StyleHelper::mergedColors(const QColor
&colorA
, const QColor
&colorB
, int factor
)
59 const int maxFactor
= 100;
62 tmp
.setRed((tmp
.red() * factor
) / maxFactor
+ (colorB
.red() * (maxFactor
- factor
)) / maxFactor
);
63 tmp
.setGreen((tmp
.green() * factor
) / maxFactor
+ (colorB
.green() * (maxFactor
- factor
)) / maxFactor
);
64 tmp
.setBlue((tmp
.blue() * factor
) / maxFactor
+ (colorB
.blue() * (maxFactor
- factor
)) / maxFactor
);
68 qreal
StyleHelper::sidebarFontSize()
70 return HostOsInfo::isMacHost() ? 10 : 7.5;
73 QPalette
StyleHelper::sidebarFontPalette(const QPalette
&original
)
75 QPalette palette
= original
;
77 palette
.setColor(QPalette::Active
, QPalette::Text
, panelTextColor());
78 palette
.setColor(QPalette::Active
, QPalette::WindowText
, panelTextColor());
79 palette
.setColor(QPalette::Inactive
, QPalette::Text
, panelTextColor().darker());
80 palette
.setColor(QPalette::Inactive
, QPalette::WindowText
, panelTextColor().darker());
84 QColor
StyleHelper::panelTextColor(bool lightColored
)
86 // qApp->palette().highlightedText().color();
94 // Invalid by default, setBaseColor needs to be called at least once
95 QColor
StyleHelper::m_baseColor
;
96 QColor
StyleHelper::m_requestedBaseColor
;
98 QColor
StyleHelper::baseColor(bool lightColored
)
103 return m_baseColor
.lighter(230);
107 QColor
StyleHelper::highlightColor(bool lightColored
)
109 QColor result
= baseColor(lightColored
);
112 result
.setHsv(result
.hue(),
113 clamp(result
.saturation()),
114 clamp(result
.value() * 1.16));
116 result
.setHsv(result
.hue(),
117 clamp(result
.saturation()),
118 clamp(result
.value() * 1.06));
123 QColor
StyleHelper::shadowColor(bool lightColored
)
125 QColor result
= baseColor(lightColored
);
127 result
.setHsv(result
.hue(),
128 clamp(result
.saturation() * 1.1),
129 clamp(result
.value() * 0.70));
133 QColor
StyleHelper::borderColor(bool lightColored
)
135 QColor result
= baseColor(lightColored
);
137 result
.setHsv(result
.hue(),
143 // We try to ensure that the actual color used are within
144 // reasonalbe bounds while generating the actual baseColor
145 // from the users request.
146 void StyleHelper::setBaseColor(const QColor
&newcolor
)
148 m_requestedBaseColor
= newcolor
;
151 color
.setHsv(newcolor
.hue(),
152 newcolor
.saturation() * 0.7,
153 64 + newcolor
.value() / 3);
155 if (color
.isValid() && color
!= m_baseColor
) {
157 foreach(QWidget
* w
, QApplication::topLevelWidgets())
162 static void verticalGradientHelper(QPainter
*p
, const QRect
&spanRect
, const QRect
&rect
, bool lightColored
)
164 QColor highlight
= StyleHelper::highlightColor(lightColored
);
165 QColor shadow
= StyleHelper::shadowColor(lightColored
);
166 QLinearGradient
grad(spanRect
.topRight(), spanRect
.topLeft());
168 grad
.setColorAt(0, highlight
.lighter(117));
169 grad
.setColorAt(1, shadow
.darker(109));
170 p
->fillRect(rect
, grad
);
172 QColor
light(255, 255, 255, 80);
174 p
->drawLine(rect
.topRight() - QPoint(1, 0), rect
.bottomRight() - QPoint(1, 0));
175 QColor
dark(0, 0, 0, 90);
177 p
->drawLine(rect
.topLeft(), rect
.bottomLeft());
180 void StyleHelper::verticalGradient(QPainter
*painter
, const QRect
&spanRect
, const QRect
&clipRect
, bool lightColored
)
182 if (StyleHelper::usePixmapCache()) {
184 QColor keyColor
= baseColor(lightColored
);
185 key
.sprintf("mh_vertical %d %d %d %d %d",
186 spanRect
.width(), spanRect
.height(), clipRect
.width(),
187 clipRect
.height(), keyColor
.rgb());;
190 if (!QPixmapCache::find(key
, pixmap
)) {
191 pixmap
= QPixmap(clipRect
.size());
193 QRect
rect(0, 0, clipRect
.width(), clipRect
.height());
194 verticalGradientHelper(&p
, spanRect
, rect
, lightColored
);
196 QPixmapCache::insert(key
, pixmap
);
199 painter
->drawPixmap(clipRect
.topLeft(), pixmap
);
201 verticalGradientHelper(painter
, spanRect
, clipRect
, lightColored
);
205 static void horizontalGradientHelper(QPainter
*p
, const QRect
&spanRect
, const
206 QRect
&rect
, bool lightColored
)
209 QLinearGradient
shadowGradient(rect
.topLeft(), rect
.bottomLeft());
210 shadowGradient
.setColorAt(0, 0xf0f0f0);
211 shadowGradient
.setColorAt(1, 0xcfcfcf);
212 p
->fillRect(rect
, shadowGradient
);
216 QColor base
= StyleHelper::baseColor(lightColored
);
217 QColor highlight
= StyleHelper::highlightColor(lightColored
);
218 QColor shadow
= StyleHelper::shadowColor(lightColored
);
219 QLinearGradient
grad(rect
.topLeft(), rect
.bottomLeft());
220 grad
.setColorAt(0, highlight
.lighter(120));
221 if (rect
.height() == StyleHelper::navigationWidgetHeight()) {
222 grad
.setColorAt(0.4, highlight
);
223 grad
.setColorAt(0.401, base
);
225 grad
.setColorAt(1, shadow
);
226 p
->fillRect(rect
, grad
);
228 QLinearGradient
shadowGradient(spanRect
.topLeft(), spanRect
.topRight());
229 shadowGradient
.setColorAt(0, QColor(0, 0, 0, 30));
230 QColor lighterHighlight
;
231 lighterHighlight
= highlight
.lighter(130);
232 lighterHighlight
.setAlpha(100);
233 shadowGradient
.setColorAt(0.7, lighterHighlight
);
234 shadowGradient
.setColorAt(1, QColor(0, 0, 0, 40));
235 p
->fillRect(rect
, shadowGradient
);
238 void StyleHelper::horizontalGradient(QPainter
*painter
, const QRect
&spanRect
, const QRect
&clipRect
, bool lightColored
)
240 if (StyleHelper::usePixmapCache()) {
242 QColor keyColor
= baseColor(lightColored
);
243 key
.sprintf("mh_horizontal %d %d %d %d %d %d",
244 spanRect
.width(), spanRect
.height(), clipRect
.width(),
245 clipRect
.height(), keyColor
.rgb(), spanRect
.x());
248 if (!QPixmapCache::find(key
, pixmap
)) {
249 pixmap
= QPixmap(clipRect
.size());
251 QRect rect
= QRect(0, 0, clipRect
.width(), clipRect
.height());
252 horizontalGradientHelper(&p
, spanRect
, rect
, lightColored
);
254 QPixmapCache::insert(key
, pixmap
);
257 painter
->drawPixmap(clipRect
.topLeft(), pixmap
);
259 horizontalGradientHelper(painter
, spanRect
, clipRect
, lightColored
);
263 static void menuGradientHelper(QPainter
*p
, const QRect
&spanRect
, const QRect
&rect
)
265 QLinearGradient
grad(spanRect
.topLeft(), spanRect
.bottomLeft());
266 QColor menuColor
= StyleHelper::mergedColors(StyleHelper::baseColor(), QColor(244, 244, 244), 25);
268 grad
.setColorAt(0, menuColor
.lighter(112));
269 grad
.setColorAt(1, menuColor
);
270 p
->fillRect(rect
, grad
);
273 void StyleHelper::drawArrow(QStyle::PrimitiveElement element
, QPainter
*painter
, const QStyleOption
*option
)
275 // From windowsstyle but modified to enable AA
276 if (option
->rect
.width() <= 1 || option
->rect
.height() <= 1) {
280 QRect r
= option
->rect
;
281 int size
= qMin(r
.height(), r
.width());
284 pixmapName
.sprintf("arrow-%s-%d-%d-%d-%lld",
286 uint(option
->state
), element
,
287 size
, option
->palette
.cacheKey());
288 if (!QPixmapCache::find(pixmapName
, pixmap
)) {
289 int border
= size
/ 5;
290 int sqsize
= 2 * (size
/ 2);
291 QImage
image(sqsize
, sqsize
, QImage::Format_ARGB32
);
292 image
.fill(Qt::transparent
);
293 QPainter
imagePainter(&image
);
294 imagePainter
.setRenderHint(QPainter::Antialiasing
, true);
295 imagePainter
.translate(0.5, 0.5);
298 case QStyle::PE_IndicatorArrowUp
:
299 a
.setPoints(3, border
, sqsize
/ 2, sqsize
/ 2, border
, sqsize
- border
, sqsize
/ 2);
301 case QStyle::PE_IndicatorArrowDown
:
302 a
.setPoints(3, border
, sqsize
/ 2, sqsize
/ 2, sqsize
- border
, sqsize
- border
, sqsize
/ 2);
304 case QStyle::PE_IndicatorArrowRight
:
305 a
.setPoints(3, sqsize
- border
, sqsize
/ 2, sqsize
/ 2, border
, sqsize
/ 2, sqsize
- border
);
307 case QStyle::PE_IndicatorArrowLeft
:
308 a
.setPoints(3, border
, sqsize
/ 2, sqsize
/ 2, border
, sqsize
/ 2, sqsize
- border
);
317 if (option
->state
& QStyle::State_Sunken
) {
318 bsx
= qApp
->style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal
);
319 bsy
= qApp
->style()->pixelMetric(QStyle::PM_ButtonShiftVertical
);
322 QRect bounds
= a
.boundingRect();
323 int sx
= sqsize
/ 2 - bounds
.center().x() - 1;
324 int sy
= sqsize
/ 2 - bounds
.center().y() - 1;
325 imagePainter
.translate(sx
+ bsx
, sy
+ bsy
);
327 if (!(option
->state
& QStyle::State_Enabled
)) {
328 QColor
foreGround(150, 150, 150, 150);
329 imagePainter
.setBrush(option
->palette
.mid().color());
330 imagePainter
.setPen(option
->palette
.mid().color());
332 QColor
shadow(0, 0, 0, 100);
333 imagePainter
.translate(0, 1);
334 imagePainter
.setPen(shadow
);
335 imagePainter
.setBrush(shadow
);
336 QColor
foreGround(255, 255, 255, 210);
337 imagePainter
.drawPolygon(a
);
338 imagePainter
.translate(0, -1);
339 imagePainter
.setPen(foreGround
);
340 imagePainter
.setBrush(foreGround
);
342 imagePainter
.drawPolygon(a
);
344 pixmap
= QPixmap::fromImage(image
);
345 QPixmapCache::insert(pixmapName
, pixmap
);
347 int xOffset
= r
.x() + (r
.width() - size
) / 2;
348 int yOffset
= r
.y() + (r
.height() - size
) / 2;
349 painter
->drawPixmap(xOffset
, yOffset
, pixmap
);
352 void StyleHelper::menuGradient(QPainter
*painter
, const QRect
&spanRect
, const QRect
&clipRect
)
354 if (StyleHelper::usePixmapCache()) {
356 key
.sprintf("mh_menu %d %d %d %d %d",
357 spanRect
.width(), spanRect
.height(), clipRect
.width(),
358 clipRect
.height(), StyleHelper::baseColor().rgb());
361 if (!QPixmapCache::find(key
, pixmap
)) {
362 pixmap
= QPixmap(clipRect
.size());
364 QRect rect
= QRect(0, 0, clipRect
.width(), clipRect
.height());
365 menuGradientHelper(&p
, spanRect
, rect
);
367 QPixmapCache::insert(key
, pixmap
);
370 painter
->drawPixmap(clipRect
.topLeft(), pixmap
);
372 menuGradientHelper(painter
, spanRect
, clipRect
);
376 static qreal
pixmapDevicePixelRatio(const QPixmap
&pixmap
)
378 #if QT_VERSION > 0x050000
379 return pixmap
.devicePixelRatio();
388 // Draws a cached pixmap with shadow
389 void StyleHelper::drawIconWithShadow(const QIcon
&icon
, const QRect
&rect
,
390 QPainter
*p
, QIcon::Mode iconMode
, int dipRadius
, const QColor
&color
, const QPoint
&dipOffset
)
393 QString pixmapName
= QString::fromLatin1("icon %0 %1 %2").arg(icon
.cacheKey()).arg(iconMode
).arg(rect
.height());
395 if (!QPixmapCache::find(pixmapName
, cache
)) {
396 // High-dpi support: The in parameters (rect, radius, offset) are in
397 // device-independent pixels. The call to QIcon::pixmap() below might
398 // return a high-dpi pixmap, which will in that case have a devicePixelRatio
399 // different than 1. The shadow drawing caluculations are done in device
401 QPixmap px
= icon
.pixmap(rect
.size());
402 int devicePixelRatio
= qCeil(pixmapDevicePixelRatio(px
));
403 int radius
= dipRadius
* devicePixelRatio
;
404 QPoint offset
= dipOffset
* devicePixelRatio
;
405 cache
= QPixmap(px
.size() + QSize(radius
* 2, radius
* 2));
406 cache
.fill(Qt::transparent
);
408 QPainter
cachePainter(&cache
);
409 if (iconMode
== QIcon::Disabled
) {
410 QImage im
= px
.toImage().convertToFormat(QImage::Format_ARGB32
);
411 for (int y
= 0; y
< im
.height(); ++y
) {
412 QRgb
*scanLine
= (QRgb
*)im
.scanLine(y
);
413 for (int x
= 0; x
< im
.width(); ++x
) {
414 QRgb pixel
= *scanLine
;
415 char intensity
= qGray(pixel
);
416 *scanLine
= qRgba(intensity
, intensity
, intensity
, qAlpha(pixel
));
420 px
= QPixmap::fromImage(im
);
424 QImage
tmp(px
.size() + QSize(radius
* 2, radius
* 2 + 1), QImage::Format_ARGB32_Premultiplied
);
425 tmp
.fill(Qt::transparent
);
427 QPainter
tmpPainter(&tmp
);
428 tmpPainter
.setCompositionMode(QPainter::CompositionMode_Source
);
429 tmpPainter
.drawPixmap(QRect(radius
, radius
, px
.width(), px
.height()), px
);
432 // blur the alpha channel
433 QImage
blurred(tmp
.size(), QImage::Format_ARGB32_Premultiplied
);
434 blurred
.fill(Qt::transparent
);
435 QPainter
blurPainter(&blurred
);
436 qt_blurImage(&blurPainter
, tmp
, radius
, false, true);
441 // blacken the image...
442 tmpPainter
.begin(&tmp
);
443 tmpPainter
.setCompositionMode(QPainter::CompositionMode_SourceIn
);
444 tmpPainter
.fillRect(tmp
.rect(), color
);
447 tmpPainter
.begin(&tmp
);
448 tmpPainter
.setCompositionMode(QPainter::CompositionMode_SourceIn
);
449 tmpPainter
.fillRect(tmp
.rect(), color
);
452 // draw the blurred drop shadow...
453 cachePainter
.drawImage(QRect(0, 0, cache
.rect().width(), cache
.rect().height()), tmp
);
455 // Draw the actual pixmap...
456 cachePainter
.drawPixmap(QRect(QPoint(radius
, radius
) + offset
, QSize(px
.width(), px
.height())), px
);
457 #if QT_VERSION > 0x050000
458 cache
.setDevicePixelRatio(devicePixelRatio
);
460 QPixmapCache::insert(pixmapName
, cache
);
463 QRect targetRect
= cache
.rect();
464 targetRect
.setSize(targetRect
.size() / pixmapDevicePixelRatio(cache
));
465 targetRect
.moveCenter(rect
.center() - dipOffset
);
466 p
->drawPixmap(targetRect
, cache
);
469 // Draws a CSS-like border image where the defined borders are not stretched
470 void StyleHelper::drawCornerImage(const QImage
&img
, QPainter
*painter
, QRect rect
,
471 int left
, int top
, int right
, int bottom
)
473 QSize size
= img
.size();
475 if (top
> 0) { // top
476 painter
->drawImage(QRect(rect
.left() + left
, rect
.top(), rect
.width() - right
- left
, top
), img
,
477 QRect(left
, 0, size
.width() - right
- left
, top
));
478 if (left
> 0) { // top-left
479 painter
->drawImage(QRect(rect
.left(), rect
.top(), left
, top
), img
,
480 QRect(0, 0, left
, top
));
482 if (right
> 0) { // top-right
483 painter
->drawImage(QRect(rect
.left() + rect
.width() - right
, rect
.top(), right
, top
), img
,
484 QRect(size
.width() - right
, 0, right
, top
));
489 painter
->drawImage(QRect(rect
.left(), rect
.top() + top
, left
, rect
.height() - top
- bottom
), img
,
490 QRect(0, top
, left
, size
.height() - bottom
- top
));
493 painter
->drawImage(QRect(rect
.left() + left
, rect
.top() + top
, rect
.width() - right
- left
,
494 rect
.height() - bottom
- top
), img
,
495 QRect(left
, top
, size
.width() - right
- left
,
496 size
.height() - bottom
- top
));
497 if (right
> 0) { // right
498 painter
->drawImage(QRect(rect
.left() + rect
.width() - right
, rect
.top() + top
, right
, rect
.height() - top
- bottom
), img
,
499 QRect(size
.width() - right
, top
, right
, size
.height() - bottom
- top
));
501 if (bottom
> 0) { // bottom
502 painter
->drawImage(QRect(rect
.left() + left
, rect
.top() + rect
.height() - bottom
,
503 rect
.width() - right
- left
, bottom
), img
,
504 QRect(left
, size
.height() - bottom
,
505 size
.width() - right
- left
, bottom
));
506 if (left
> 0) { // bottom-left
507 painter
->drawImage(QRect(rect
.left(), rect
.top() + rect
.height() - bottom
, left
, bottom
), img
,
508 QRect(0, size
.height() - bottom
, left
, bottom
));
510 if (right
> 0) { // bottom-right
511 painter
->drawImage(QRect(rect
.left() + rect
.width() - right
, rect
.top() + rect
.height() - bottom
, right
, bottom
), img
,
512 QRect(size
.width() - right
, size
.height() - bottom
, right
, bottom
));
517 // Tints an image with tintColor, while preserving alpha and lightness
518 void StyleHelper::tintImage(QImage
&img
, const QColor
&tintColor
)
522 p
.setCompositionMode(QPainter::CompositionMode_Screen
);
524 for (int x
= 0; x
< img
.width(); ++x
) {
525 for (int y
= 0; y
< img
.height(); ++y
) {
526 QRgb rgbColor
= img
.pixel(x
, y
);
527 int alpha
= qAlpha(rgbColor
);
528 QColor c
= QColor(rgbColor
);
532 qreal l
= c
.lightnessF();
533 QColor newColor
= QColor::fromHslF(tintColor
.hslHueF(), tintColor
.hslSaturationF(), l
);
534 newColor
.setAlpha(alpha
);
535 img
.setPixel(x
, y
, newColor
.rgba());
541 QLinearGradient
StyleHelper::statusBarGradient(const QRect
&statusBarRect
)
543 QLinearGradient
grad(statusBarRect
.topLeft(), QPoint(statusBarRect
.center().x(), statusBarRect
.bottom()));
544 QColor startColor
= shadowColor().darker(164);
545 QColor endColor
= baseColor().darker(130);
547 grad
.setColorAt(0, startColor
);
548 grad
.setColorAt(1, endColor
);