File indexing completed on 2024-05-19 09:28:04
0001 /* 0002 SPDX-FileCopyrightText: 2013 Hugo Pereira Da Costa <hugo.pereira@free.fr> 0003 SPDX-FileCopyrightText: 2008 Long Huynh Huu <long.upcase@googlemail.com> 0004 SPDX-FileCopyrightText: 2007 Matthew Woehlke <mw_triad@users.sourceforge.net> 0005 SPDX-FileCopyrightText: 2007 Casper Boemann <cbr@boemann.dk> 0006 0007 SPDX-License-Identifier: LGPL-2.0-only 0008 */ 0009 0010 #include "oxygenstylehelper.h" 0011 0012 #include <KColorScheme> 0013 #include <KColorUtils> 0014 0015 #include <QLinearGradient> 0016 #include <QPainter> 0017 #include <QTextStream> 0018 0019 #include <math.h> 0020 0021 #if OXYGEN_HAVE_X11 0022 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0023 #include <QX11Info> 0024 #else 0025 #include <private/qtx11extras_p.h> 0026 #endif 0027 #endif 0028 0029 namespace Oxygen 0030 { 0031 0032 //______________________________________________________________________________ 0033 StyleHelper::StyleHelper(KSharedConfigPtr config) 0034 : Helper(config) 0035 { 0036 init(); 0037 } 0038 0039 //______________________________________________________________________________ 0040 void StyleHelper::invalidateCaches(void) 0041 { 0042 _slabCache.clear(); 0043 _slabSunkenCache.clear(); 0044 _dialSlabCache.clear(); 0045 _roundSlabCache.clear(); 0046 _sliderSlabCache.clear(); 0047 _holeCache.clear(); 0048 0049 _midColorCache.clear(); 0050 0051 _dockWidgetButtonCache.clear(); 0052 _progressBarCache.clear(); 0053 _cornerCache.clear(); 0054 _selectionCache.clear(); 0055 _holeFlatCache.clear(); 0056 _slopeCache.clear(); 0057 _slitCache.clear(); 0058 _dockFrameCache.clear(); 0059 _scrollHoleCache.clear(); 0060 _scrollHandleCache.clear(); 0061 Helper::invalidateCaches(); 0062 } 0063 0064 //____________________________________________________________________ 0065 void StyleHelper::setMaxCacheSize(int value) 0066 { 0067 // base class 0068 Helper::setMaxCacheSize(value); 0069 0070 // assign max cache size 0071 _slabCache.setMaxCacheSize(value); 0072 _slabSunkenCache.setMaxCost(value); 0073 _dialSlabCache.setMaxCacheSize(value); 0074 _roundSlabCache.setMaxCacheSize(value); 0075 _sliderSlabCache.setMaxCacheSize(value); 0076 _holeCache.setMaxCacheSize(value); 0077 _scrollHandleCache.setMaxCacheSize(value); 0078 0079 _dockWidgetButtonCache.setMaxCost(value); 0080 _progressBarCache.setMaxCost(value); 0081 _cornerCache.setMaxCost(value); 0082 _selectionCache.setMaxCost(value); 0083 _holeFlatCache.setMaxCost(value); 0084 _slopeCache.setMaxCost(value); 0085 _slitCache.setMaxCost(value); 0086 _dockFrameCache.setMaxCost(value); 0087 _scrollHoleCache.setMaxCost(value); 0088 } 0089 0090 //____________________________________________________________________ 0091 void StyleHelper::renderWindowBackground(QPainter *painter, const QRect &clipRect, const QWidget *widget, const QColor &color, int y_shift) 0092 { 0093 if (_useBackgroundGradient) { 0094 // normal background gradient 0095 Helper::renderWindowBackground(painter, clipRect, widget, widget->window(), color, y_shift); 0096 0097 } else { 0098 // if background gradient is disabled, simply render flat background 0099 if (clipRect.isValid()) { 0100 painter->setClipRegion(clipRect, Qt::IntersectClip); 0101 } 0102 0103 painter->fillRect(widget->rect(), color); 0104 } 0105 } 0106 0107 //____________________________________________________________________ 0108 void StyleHelper::setHasBackgroundGradient(WId id, bool value) const 0109 { 0110 Helper::setHasBackgroundGradient(id, value && _useBackgroundGradient); 0111 } 0112 0113 //____________________________________________________________________ 0114 void StyleHelper::renderMenuBackground(QPainter *painter, const QRect &clipRect, const QWidget *widget, const QColor &color) 0115 { 0116 // get coordinates relative to the client area 0117 // this is stupid. One could use mapTo if this was taking const QWidget* and not 0118 // QWidget* as argument. 0119 const QWidget *w(widget); 0120 int x(0); 0121 int y(0); 0122 0123 while (!w->isWindow() && w != w->parentWidget()) { 0124 x += w->geometry().x(); 0125 y += w->geometry().y(); 0126 w = w->parentWidget(); 0127 } 0128 0129 if (clipRect.isValid()) { 0130 painter->save(); 0131 painter->setClipRegion(clipRect, Qt::IntersectClip); 0132 } 0133 0134 // calculate upper part height 0135 // special tricks are needed 0136 // to handle both window contents and window decoration 0137 QRect r = w->rect(); 0138 const int height(w->frameGeometry().height()); 0139 const int splitY(qMin(200, (3 * height) / 4)); 0140 0141 const QRect upperRect(QRect(0, 0, r.width(), splitY)); 0142 const QPixmap tile(verticalGradient(color, splitY)); 0143 painter->drawTiledPixmap(upperRect, tile); 0144 0145 const QRect lowerRect(0, splitY, r.width(), r.height() - splitY); 0146 painter->fillRect(lowerRect, backgroundBottomColor(color)); 0147 0148 if (clipRect.isValid()) { 0149 painter->restore(); 0150 } 0151 } 0152 0153 //____________________________________________________________________________________ 0154 QColor StyleHelper::arrowColor(const QPalette &palette, StyleOptions options, qreal opacity, AnimationMode mode) const 0155 { 0156 QColor glow(palette.color(QPalette::WindowText)); 0157 if (mode == AnimationNone || opacity < 0) { 0158 if (options & Hover) 0159 glow = hoverColor(palette); 0160 else if (options & Focus) 0161 glow = focusColor(palette); 0162 0163 } else if (mode == AnimationHover) { 0164 // animated color, hover 0165 if (options & Focus) 0166 glow = focusColor(palette); 0167 if (glow.isValid()) 0168 glow = KColorUtils::mix(glow, hoverColor(palette), opacity); 0169 0170 } else if (mode == AnimationFocus) { 0171 if (options & Hover) 0172 glow = hoverColor(palette); 0173 if (glow.isValid()) 0174 glow = KColorUtils::mix(glow, focusColor(palette), opacity); 0175 } 0176 0177 return glow; 0178 } 0179 0180 //____________________________________________________________________________________ 0181 QColor StyleHelper::buttonGlowColor(QPalette::ColorGroup colorGroup, StyleOptions options, qreal opacity, AnimationMode mode) const 0182 { 0183 QColor glow; 0184 if (mode == AnimationNone || opacity < 0) { 0185 if (options & Hover) 0186 glow = hoverColor(colorGroup); 0187 else if (options & Focus) 0188 glow = focusColor(colorGroup); 0189 0190 } else if (mode == AnimationHover) { 0191 // animated color, hover 0192 if (options & Focus) 0193 glow = focusColor(colorGroup); 0194 if (glow.isValid()) 0195 glow = KColorUtils::mix(glow, hoverColor(colorGroup), opacity); 0196 else 0197 glow = alphaColor(hoverColor(colorGroup), opacity); 0198 0199 } else if (mode == AnimationFocus) { 0200 if (options & Hover) 0201 glow = hoverColor(colorGroup); 0202 if (glow.isValid()) 0203 glow = KColorUtils::mix(glow, focusColor(colorGroup), opacity); 0204 else 0205 glow = alphaColor(focusColor(colorGroup), opacity); 0206 } 0207 0208 return glow; 0209 } 0210 0211 //____________________________________________________________________________________ 0212 QColor StyleHelper::frameGlowColor(QPalette::ColorGroup colorGroup, StyleOptions options, qreal opacity, AnimationMode mode) const 0213 { 0214 QColor glow; 0215 if (mode == AnimationNone || opacity < 0) { 0216 if (options & Focus) 0217 glow = focusColor(colorGroup); 0218 else if (options & Hover) 0219 glow = hoverColor(colorGroup); 0220 0221 } else if (mode == AnimationFocus) { 0222 if (options & Hover) 0223 glow = hoverColor(colorGroup); 0224 if (glow.isValid()) 0225 glow = KColorUtils::mix(glow, focusColor(colorGroup), opacity); 0226 else 0227 glow = alphaColor(focusColor(colorGroup), opacity); 0228 0229 } else if (mode == AnimationHover) { 0230 // animated color, hover 0231 if (options & Focus) 0232 glow = focusColor(colorGroup); 0233 if (glow.isValid()) 0234 glow = KColorUtils::mix(glow, hoverColor(colorGroup), opacity); 0235 else 0236 glow = alphaColor(hoverColor(colorGroup), opacity); 0237 } 0238 0239 return glow; 0240 } 0241 0242 //______________________________________________________________________________ 0243 QPalette StyleHelper::disabledPalette(const QPalette &source, qreal ratio) const 0244 { 0245 QPalette out(source); 0246 out.setColor(QPalette::Window, 0247 KColorUtils::mix(source.color(QPalette::Active, QPalette::Window), source.color(QPalette::Disabled, QPalette::Window), 1.0 - ratio)); 0248 out.setColor(QPalette::Highlight, 0249 KColorUtils::mix(source.color(QPalette::Active, QPalette::Highlight), source.color(QPalette::Disabled, QPalette::Highlight), 1.0 - ratio)); 0250 out.setColor(QPalette::WindowText, 0251 KColorUtils::mix(source.color(QPalette::Active, QPalette::WindowText), source.color(QPalette::Disabled, QPalette::WindowText), 1.0 - ratio)); 0252 out.setColor(QPalette::ButtonText, 0253 KColorUtils::mix(source.color(QPalette::Active, QPalette::ButtonText), source.color(QPalette::Disabled, QPalette::ButtonText), 1.0 - ratio)); 0254 out.setColor(QPalette::Text, 0255 KColorUtils::mix(source.color(QPalette::Active, QPalette::Text), source.color(QPalette::Disabled, QPalette::Text), 1.0 - ratio)); 0256 out.setColor(QPalette::Button, 0257 KColorUtils::mix(source.color(QPalette::Active, QPalette::Button), source.color(QPalette::Disabled, QPalette::Button), 1.0 - ratio)); 0258 return out; 0259 } 0260 0261 //______________________________________________________________________________ 0262 QPixmap StyleHelper::dockWidgetButton(const QColor &color, bool pressed, int size) 0263 { 0264 const quint64 key((colorKey(color) << 32) | (size << 1) | quint64(pressed)); 0265 0266 if (QPixmap *cachedPixmap = _dockWidgetButtonCache.object(key)) { 0267 return *cachedPixmap; 0268 } 0269 0270 QPixmap pixmap(highDpiPixmap(size, size)); 0271 pixmap.fill(Qt::transparent); 0272 0273 const QColor light(calcLightColor(color)); 0274 const QColor dark(calcDarkColor(color)); 0275 0276 QPainter painter(&pixmap); 0277 painter.setRenderHints(QPainter::Antialiasing); 0278 painter.setPen(Qt::NoPen); 0279 const qreal u(size / 18.0); 0280 painter.translate(0.5 * u, (0.5 - 0.668) * u); 0281 0282 { 0283 // outline circle 0284 qreal penWidth = 1.2; 0285 QLinearGradient linearGradient(0, u * (1.665 - penWidth), 0, u * (12.33 + 1.665 - penWidth)); 0286 linearGradient.setColorAt(0, dark); 0287 linearGradient.setColorAt(1, light); 0288 QRectF r(u * 0.5 * (17 - 12.33 + penWidth), u * (1.665 + penWidth), u * (12.33 - penWidth), u * (12.33 - penWidth)); 0289 painter.setPen(QPen(linearGradient, penWidth * u)); 0290 painter.drawEllipse(r); 0291 painter.end(); 0292 } 0293 0294 _dockWidgetButtonCache.insert(key, new QPixmap(pixmap)); 0295 return pixmap; 0296 } 0297 0298 //________________________________________________________________________________________________________ 0299 TileSet StyleHelper::roundCorner(const QColor &color, int size) 0300 { 0301 const quint64 key((colorKey(color) << 32) | size); 0302 if (TileSet *cachedTileSet = _cornerCache.object(key)) { 0303 return *cachedTileSet; 0304 } 0305 0306 QPixmap pixmap = QPixmap(size * 2, size * 2); 0307 pixmap.fill(Qt::transparent); 0308 0309 QPainter painter(&pixmap); 0310 painter.setRenderHint(QPainter::Antialiasing); 0311 painter.setPen(Qt::NoPen); 0312 0313 QLinearGradient linearGradient = QLinearGradient(0.0, size - 4.5, 0.0, size + 4.5); 0314 linearGradient.setColorAt(0.50, calcLightColor(backgroundTopColor(color))); 0315 linearGradient.setColorAt(0.51, backgroundBottomColor(color)); 0316 0317 // draw ellipse. 0318 painter.setBrush(linearGradient); 0319 painter.drawEllipse(QRectF(size - 4, size - 4, 8, 8)); 0320 0321 // mask 0322 painter.setCompositionMode(QPainter::CompositionMode_DestinationOut); 0323 painter.setBrush(Qt::black); 0324 painter.drawEllipse(QRectF(size - 3, size - 3, 6, 6)); 0325 0326 TileSet tileSet(pixmap, size, size, 1, 1); 0327 _cornerCache.insert(key, new TileSet(tileSet)); 0328 0329 return tileSet; 0330 } 0331 0332 //________________________________________________________________________________________________________ 0333 TileSet StyleHelper::slope(const QColor &color, qreal shade, int size) 0334 { 0335 const quint64 key((colorKey(color) << 32) | (quint64(256.0 * shade) << 24) | size); 0336 if (TileSet *cachedTileSet = _slopeCache.object(key)) { 0337 return *cachedTileSet; 0338 } 0339 0340 QPixmap pixmap(highDpiPixmap(size * 4)); 0341 pixmap.fill(Qt::transparent); 0342 0343 QPainter painter(&pixmap); 0344 painter.setPen(Qt::NoPen); 0345 0346 // edges 0347 TileSet slabTileSet = slab(color, shade, size); 0348 slabTileSet.render(QRect(0, 0, size * 4, size * 5), &painter, TileSet::Left | TileSet::Right | TileSet::Top); 0349 0350 int fixedSize(28 * devicePixelRatio(pixmap)); 0351 painter.setWindow(0, 0, fixedSize, fixedSize); 0352 0353 // bottom 0354 QColor light = KColorUtils::shade(calcLightColor(color), shade); 0355 QLinearGradient fillGradient(0, -28, 0, 28); 0356 light.setAlphaF(0.4); 0357 fillGradient.setColorAt(0.0, light); 0358 light.setAlphaF(0.0); 0359 fillGradient.setColorAt(1.0, light); 0360 painter.setBrush(fillGradient); 0361 painter.setCompositionMode(QPainter::CompositionMode_DestinationOver); 0362 painter.drawRect(3, 9, 22, 17); 0363 0364 // fade bottom 0365 QLinearGradient maskGradient(0, 7, 0, 28); 0366 maskGradient.setColorAt(0.0, Qt::black); 0367 maskGradient.setColorAt(1.0, Qt::transparent); 0368 0369 painter.setBrush(maskGradient); 0370 painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); 0371 painter.drawRect(0, 9, 28, 19); 0372 0373 painter.end(); 0374 0375 TileSet tileSet(pixmap, size, size, size * 2, 2); 0376 _slopeCache.insert(key, new TileSet(tileSet)); 0377 return tileSet; 0378 } 0379 0380 //________________________________________________________________________________________________________ 0381 void StyleHelper::drawInverseShadow(QPainter &painter, const QColor &color, int pad, int size, qreal fuzz) const 0382 { 0383 const qreal m(qreal(size) * 0.5); 0384 const qreal offset(0.8); 0385 const qreal k0((m - 2) / qreal(m + 2.0)); 0386 QRadialGradient shadowGradient(pad + m, pad + m + offset, m + 2); 0387 for (int i = 0; i < 8; i++) { 0388 // sinusoidal gradient 0389 const qreal k1((qreal(8 - i) + k0 * qreal(i)) * 0.125); 0390 const qreal a((cos(3.14159 * i * 0.125) + 1.0) * 0.25); 0391 shadowGradient.setColorAt(k1, alphaColor(color, a * _shadowGain)); 0392 } 0393 shadowGradient.setColorAt(k0, alphaColor(color, 0.0)); 0394 painter.setBrush(shadowGradient); 0395 painter.drawEllipse(QRectF(pad - fuzz, pad - fuzz, size + fuzz * 2.0, size + fuzz * 2.0)); 0396 } 0397 0398 //________________________________________________________________________________________________________ 0399 void StyleHelper::fillSlab(QPainter &painter, const QRect &rect, int size) const 0400 { 0401 const qreal s(qreal(size) * (3.6 + (0.5 * _slabThickness)) / 7.0); 0402 const QRectF r(QRectF(rect).adjusted(s, s, -s, -s)); 0403 if (!r.isValid()) 0404 return; 0405 0406 painter.drawRoundedRect(r, s / 2, s / 2); 0407 } 0408 0409 //________________________________________________________________________________________________________ 0410 void StyleHelper::fillButtonSlab(QPainter &painter, const QRect &r, const QColor &color, bool sunken) 0411 { 0412 painter.save(); 0413 painter.setRenderHint(QPainter::Antialiasing); 0414 painter.setPen(Qt::NoPen); 0415 0416 if (sunken && calcShadowColor(color).value() > color.value()) { 0417 QLinearGradient innerGradient(0, r.top(), 0, r.bottom() + r.height()); 0418 innerGradient.setColorAt(0.0, color); 0419 innerGradient.setColorAt(1.0, calcLightColor(color)); 0420 painter.setBrush(innerGradient); 0421 0422 } else if (sunken) { 0423 QLinearGradient innerGradient(0, r.top() - r.height(), 0, r.bottom()); 0424 innerGradient.setColorAt(0.0, calcLightColor(color)); 0425 innerGradient.setColorAt(1.0, color); 0426 painter.setBrush(innerGradient); 0427 0428 } else { 0429 QLinearGradient innerGradient(0, r.top() - 0.2 * r.height(), 0, r.bottom() + 0.4 * r.height()); 0430 innerGradient.setColorAt(0.0, calcLightColor(color)); 0431 innerGradient.setColorAt(0.6, color); 0432 painter.setBrush(innerGradient); 0433 } 0434 0435 fillSlab(painter, r); 0436 painter.restore(); 0437 } 0438 0439 //________________________________________________________________________________________________________ 0440 TileSet StyleHelper::slab(const QColor &color, const QColor &glow, qreal shade, int size) 0441 { 0442 Oxygen::Cache<TileSet>::Value cache(_slabCache.get(color)); 0443 0444 const quint64 key((colorKey(glow) << 32) | (quint64(256.0 * shade) << 24) | size); 0445 if (TileSet *cachedTileSet = cache->object(key)) { 0446 return *cachedTileSet; 0447 } 0448 0449 QPixmap pixmap(highDpiPixmap(size * 2)); 0450 pixmap.fill(Qt::transparent); 0451 0452 QPainter painter(&pixmap); 0453 painter.setRenderHints(QPainter::Antialiasing); 0454 painter.setPen(Qt::NoPen); 0455 0456 const int fixedSize(14 * devicePixelRatio(pixmap)); 0457 painter.setWindow(0, 0, fixedSize, fixedSize); 0458 0459 // draw all components 0460 if (color.isValid()) 0461 drawShadow(painter, calcShadowColor(color), 14); 0462 if (glow.isValid()) 0463 drawOuterGlow(painter, glow, 14); 0464 if (color.isValid()) 0465 drawSlab(painter, color, shade); 0466 0467 painter.end(); 0468 0469 TileSet tileSet(pixmap, size, size, size, size, size - 1, size, 2, 1); 0470 0471 cache->insert(key, new TileSet(tileSet)); 0472 return tileSet; 0473 } 0474 0475 //________________________________________________________________________________________________________ 0476 TileSet StyleHelper::slabSunken(const QColor &color, int size) 0477 { 0478 const quint64 key(colorKey(color) << 32 | size); 0479 if (TileSet *cachedTileSet = _slabSunkenCache.object(key)) { 0480 return *cachedTileSet; 0481 } 0482 0483 QPixmap pixmap(highDpiPixmap(size * 2)); 0484 pixmap.fill(Qt::transparent); 0485 0486 QPainter painter(&pixmap); 0487 painter.setRenderHints(QPainter::Antialiasing); 0488 painter.setPen(Qt::NoPen); 0489 0490 const int fixedSize(14 * devicePixelRatio(pixmap)); 0491 painter.setWindow(0, 0, fixedSize, fixedSize); 0492 0493 // shadow 0494 painter.setCompositionMode(QPainter::CompositionMode_SourceOver); 0495 drawInverseShadow(painter, calcShadowColor(color), 3, 8, 0.0); 0496 0497 // contrast pixel 0498 { 0499 QColor light(calcLightColor(color)); 0500 QLinearGradient blend(0, 2, 0, 16); 0501 blend.setColorAt(0.5, Qt::transparent); 0502 blend.setColorAt(1.0, light); 0503 0504 painter.setBrush(Qt::NoBrush); 0505 painter.setPen(QPen(blend, 1)); 0506 painter.drawRoundedRect(QRectF(2.5, 2.5, 9, 9), 4.0, 4.0); 0507 painter.setPen(Qt::NoPen); 0508 } 0509 0510 painter.end(); 0511 0512 TileSet tileSet(pixmap, size, size, size, size, size - 1, size, 2, 1); 0513 _slabSunkenCache.insert(key, new TileSet(tileSet)); 0514 0515 return tileSet; 0516 } 0517 0518 //__________________________________________________________________________________________________________ 0519 TileSet StyleHelper::progressBarIndicator(const QPalette &pal, int dimension) 0520 { 0521 const QColor highlight(pal.color(QPalette::Highlight)); 0522 const quint64 key((colorKey(highlight) << 32) | dimension); 0523 0524 if (TileSet *cachedTileSet = _progressBarCache.object(key)) { 0525 return *cachedTileSet; 0526 } 0527 0528 QRect local(0, 0, dimension, dimension); 0529 0530 QPixmap pixmap(highDpiPixmap(local.size())); 0531 pixmap.fill(Qt::transparent); 0532 0533 QPainter painter(&pixmap); 0534 painter.setRenderHints(QPainter::Antialiasing); 0535 painter.setBrush(Qt::NoBrush); 0536 0537 const QColor lhighlight(calcLightColor(highlight)); 0538 const QColor color(pal.color(QPalette::Active, QPalette::Window)); 0539 const QColor light(calcLightColor(color)); 0540 const QColor dark(calcDarkColor(color)); 0541 const QColor shadow(calcShadowColor(color)); 0542 0543 // shadow 0544 { 0545 painter.setPen(QPen(alphaColor(shadow, 0.4), 0.6)); 0546 painter.drawRoundedRect(QRectF(local).adjusted(0.5, 0.5, -0.5, 0.5), 3.0, 3.0); 0547 } 0548 0549 // fill 0550 local.adjust(1, 1, -1, 0); 0551 { 0552 painter.setPen(Qt::NoPen); 0553 painter.setBrush(KColorUtils::mix(highlight, dark, 0.2)); 0554 painter.drawRoundedRect(local, 2.5, 2.5); 0555 } 0556 0557 // fake radial gradient 0558 { 0559 QPixmap pixmap(highDpiPixmap(local.size())); 0560 pixmap.fill(Qt::transparent); 0561 { 0562 QRect pixmapRect(QPoint(0, 0), local.size()); 0563 QLinearGradient mask(pixmapRect.topLeft(), pixmapRect.topRight()); 0564 mask.setColorAt(0.0, Qt::transparent); 0565 mask.setColorAt(0.4, Qt::black); 0566 mask.setColorAt(0.6, Qt::black); 0567 mask.setColorAt(1.0, Qt::transparent); 0568 0569 QLinearGradient radial(pixmapRect.topLeft(), pixmapRect.bottomLeft()); 0570 radial.setColorAt(0.0, KColorUtils::mix(lhighlight, light, 0.3)); 0571 radial.setColorAt(0.5, Qt::transparent); 0572 radial.setColorAt(0.6, Qt::transparent); 0573 radial.setColorAt(1.0, KColorUtils::mix(lhighlight, light, 0.3)); 0574 0575 QPainter painter(&pixmap); 0576 painter.fillRect(pixmap.rect(), mask); 0577 painter.setCompositionMode(QPainter::CompositionMode_SourceIn); 0578 painter.fillRect(pixmapRect, radial); 0579 painter.end(); 0580 } 0581 0582 painter.drawPixmap(QPoint(1, 1), pixmap); 0583 } 0584 0585 // bevel 0586 { 0587 QLinearGradient bevel(QPointF(0, 0.5) + local.topLeft(), QPointF(0, -0.5) + local.bottomLeft()); 0588 bevel.setColorAt(0, lhighlight); 0589 bevel.setColorAt(0.5, highlight); 0590 bevel.setColorAt(1, calcDarkColor(highlight)); 0591 painter.setBrush(Qt::NoBrush); 0592 painter.setPen(QPen(bevel, 1)); 0593 painter.drawRoundedRect(QRectF(local).adjusted(0.5, 0.5, -0.5, -0.5), 2.5, 2.5); 0594 } 0595 0596 // bright top edge 0597 { 0598 QLinearGradient lightHl(local.topLeft(), local.topRight()); 0599 lightHl.setColorAt(0, Qt::transparent); 0600 lightHl.setColorAt(0.5, KColorUtils::mix(highlight, light, 0.8)); 0601 lightHl.setColorAt(1, Qt::transparent); 0602 0603 painter.setPen(QPen(lightHl, 1)); 0604 painter.drawLine(QPointF(0.5, 0.5) + local.topLeft(), QPointF(0.5, 0.5) + local.topRight()); 0605 } 0606 0607 painter.end(); 0608 0609 // generate tileSet and save in cache 0610 const int radius = qMin(3, dimension / 2); 0611 TileSet tileSet(pixmap, radius, radius, dimension - 2 * radius, dimension - 2 * radius); 0612 _progressBarCache.insert(key, new TileSet(tileSet)); 0613 0614 return tileSet; 0615 } 0616 0617 //______________________________________________________________________________ 0618 QPixmap StyleHelper::dialSlab(const QColor &color, const QColor &glow, qreal shade, int size) 0619 { 0620 Oxygen::Cache<QPixmap>::Value cache = _dialSlabCache.get(color); 0621 0622 const quint64 key((colorKey(glow) << 32) | (quint64(256.0 * shade) << 24) | size); 0623 if (QPixmap *cachedPixmap = cache->object(key)) { 0624 return *cachedPixmap; 0625 } 0626 0627 QPixmap pixmap(highDpiPixmap(size)); 0628 pixmap.fill(Qt::transparent); 0629 0630 QRectF rect(0, 0, size, size); 0631 0632 QPainter painter(&pixmap); 0633 painter.setPen(Qt::NoPen); 0634 painter.setRenderHints(QPainter::Antialiasing); 0635 0636 // colors 0637 const QColor base(KColorUtils::shade(color, shade)); 0638 const QColor light(KColorUtils::shade(calcLightColor(color), shade)); 0639 const QColor dark(KColorUtils::shade(calcDarkColor(color), shade)); 0640 const QColor mid(KColorUtils::shade(calcMidColor(color), shade)); 0641 const QColor shadow(calcShadowColor(color)); 0642 0643 // shadow 0644 drawShadow(painter, shadow, rect.width()); 0645 0646 if (glow.isValid()) { 0647 drawOuterGlow(painter, glow, rect.width()); 0648 } 0649 0650 const qreal baseOffset(3.5); 0651 { 0652 // plain background 0653 QLinearGradient linearGradient(0, baseOffset - 0.5 * rect.height(), 0, baseOffset + rect.height()); 0654 linearGradient.setColorAt(0, light); 0655 linearGradient.setColorAt(0.8, base); 0656 0657 painter.setBrush(linearGradient); 0658 const qreal offset(baseOffset); 0659 painter.drawEllipse(rect.adjusted(offset, offset, -offset, -offset)); 0660 } 0661 0662 { 0663 // outline circle 0664 const qreal penWidth(0.7); 0665 QLinearGradient linearGradient(0, baseOffset, 0, baseOffset + 2 * rect.height()); 0666 linearGradient.setColorAt(0, light); 0667 linearGradient.setColorAt(1, mid); 0668 painter.setBrush(Qt::NoBrush); 0669 painter.setPen(QPen(linearGradient, penWidth)); 0670 const qreal offset(baseOffset + 0.5 * penWidth); 0671 painter.drawEllipse(rect.adjusted(offset, offset, -offset, -offset)); 0672 } 0673 0674 cache->insert(key, new QPixmap(pixmap)); 0675 0676 return pixmap; 0677 } 0678 0679 //__________________________________________________________________________________________________________ 0680 QPixmap StyleHelper::roundSlab(const QColor &color, const QColor &glow, qreal shade, int size) 0681 { 0682 Oxygen::Cache<QPixmap>::Value cache(_roundSlabCache.get(color)); 0683 0684 const quint64 key((colorKey(glow) << 32) | (quint64(256.0 * shade) << 24) | size); 0685 if (QPixmap *cachedPixmap = cache->object(key)) { 0686 return *cachedPixmap; 0687 } 0688 0689 QPixmap pixmap(highDpiPixmap(size * 3)); 0690 pixmap.fill(Qt::transparent); 0691 0692 QPainter painter(&pixmap); 0693 painter.setRenderHints(QPainter::Antialiasing); 0694 painter.setPen(Qt::NoPen); 0695 0696 const int fixedSize(21 * devicePixelRatio(pixmap)); 0697 painter.setWindow(0, 0, fixedSize, fixedSize); 0698 0699 // draw normal shadow 0700 drawShadow(painter, calcShadowColor(color), 21); 0701 0702 // draw glow. 0703 if (glow.isValid()) { 0704 drawOuterGlow(painter, glow, 21); 0705 } 0706 0707 drawRoundSlab(painter, color, shade); 0708 0709 painter.end(); 0710 cache->insert(key, new QPixmap(pixmap)); 0711 return pixmap; 0712 } 0713 0714 //__________________________________________________________________________________________________________ 0715 QPixmap StyleHelper::sliderSlab(const QColor &color, const QColor &glow, bool sunken, qreal shade, int size) 0716 { 0717 Oxygen::Cache<QPixmap>::Value cache(_sliderSlabCache.get(color)); 0718 0719 const quint64 key((colorKey(glow) << 32) | (quint64(256.0 * shade) << 24) | (sunken << 23) | size); 0720 if (QPixmap *cachedPixmap = cache->object(key)) { 0721 return *cachedPixmap; 0722 } 0723 0724 QPixmap pixmap(highDpiPixmap(size * 3)); 0725 pixmap.fill(Qt::transparent); 0726 0727 QPainter painter(&pixmap); 0728 painter.setRenderHints(QPainter::Antialiasing); 0729 painter.setPen(Qt::NoPen); 0730 0731 if (color.isValid()) 0732 drawShadow(painter, alphaColor(calcShadowColor(color), 0.8), 21); 0733 if (glow.isValid()) 0734 drawOuterGlow(painter, glow, 21); 0735 0736 // draw slab 0737 drawSliderSlab(painter, color, sunken, shade); 0738 0739 painter.end(); 0740 cache->insert(key, new QPixmap(pixmap)); 0741 return pixmap; 0742 } 0743 0744 //______________________________________________________________________________ 0745 void StyleHelper::renderDebugFrame(QPainter *painter, const QRect &rect) const 0746 { 0747 painter->save(); 0748 painter->setRenderHints(QPainter::Antialiasing); 0749 painter->setBrush(Qt::NoBrush); 0750 painter->setPen(Qt::red); 0751 painter->drawRect(QRectF(rect).adjusted(0.5, 0.5, -0.5, -0.5)); 0752 painter->restore(); 0753 } 0754 0755 //________________________________________________________________________________________________________ 0756 void StyleHelper::fillHole(QPainter &painter, const QRect &rect, int offset) const 0757 { 0758 painter.drawRoundedRect(rect.adjusted(offset, offset, -offset, -offset), 4 - offset, 4 - offset); 0759 } 0760 0761 //____________________________________________________________________________________ 0762 void StyleHelper::renderHole(QPainter *painter, 0763 const QColor &base, 0764 const QRect &rect, 0765 StyleOptions options, 0766 qreal opacity, 0767 Oxygen::AnimationMode mode, 0768 TileSet::Tiles tiles) 0769 { 0770 if (!rect.isValid()) 0771 return; 0772 const QColor glow(frameGlowColor(QPalette::Active, options, opacity, mode)); 0773 hole(base, glow, TileSet::DefaultSize, options).render(rect, painter, tiles); 0774 } 0775 0776 //________________________________________________________________________________________________________ 0777 TileSet StyleHelper::holeFlat(const QColor &color, qreal shade, bool fill, int size) 0778 { 0779 const quint64 key((colorKey(color) << 32) | (quint64(256.0 * shade) << 24) | size << 1 | fill); 0780 if (TileSet *cachedTileSet = _holeFlatCache.object(key)) { 0781 return *cachedTileSet; 0782 } 0783 0784 QPixmap pixmap(highDpiPixmap(size * 2)); 0785 pixmap.fill(Qt::transparent); 0786 0787 QPainter painter(&pixmap); 0788 painter.setRenderHints(QPainter::Antialiasing); 0789 painter.setPen(Qt::NoPen); 0790 0791 const int fixedSize(14 * devicePixelRatio(pixmap)); 0792 painter.setWindow(0, 0, fixedSize, fixedSize); 0793 0794 if (fill) { 0795 // hole inside 0796 painter.setBrush(color); 0797 painter.drawRoundedRect(QRectF(1, 0, 12, 13), 3.0, 3.0); 0798 painter.setBrush(Qt::NoBrush); 0799 0800 { 0801 // shadow (top) 0802 const QColor dark(KColorUtils::shade(calcDarkColor(color), shade)); 0803 QLinearGradient gradient(0, -2, 0, 14); 0804 gradient.setColorAt(0.0, dark); 0805 gradient.setColorAt(0.5, Qt::transparent); 0806 0807 painter.setPen(QPen(gradient, 1)); 0808 painter.drawRoundedRect(QRectF(1.5, 0.5, 11, 12), 2.5, 2.5); 0809 } 0810 0811 { 0812 // contrast (bottom) 0813 const QColor light(KColorUtils::shade(calcLightColor(color), shade)); 0814 QLinearGradient gradient(0, 0, 0, 18); 0815 gradient.setColorAt(0.5, Qt::transparent); 0816 gradient.setColorAt(1.0, light); 0817 0818 painter.setPen(QPen(gradient, 1)); 0819 painter.drawRoundedRect(QRectF(0.5, 0.5, 13, 13), 3.5, 3.5); 0820 } 0821 0822 } else { 0823 // hole inside 0824 painter.setBrush(color); 0825 painter.drawRoundedRect(QRectF(2, 2, 10, 10), 3.0, 3.0); 0826 painter.setBrush(Qt::NoBrush); 0827 0828 { 0829 // shadow (top) 0830 const QColor dark(KColorUtils::shade(calcDarkColor(color), shade)); 0831 QLinearGradient gradient(0, 1, 0, 12); 0832 gradient.setColorAt(0.0, dark); 0833 gradient.setColorAt(0.5, Qt::transparent); 0834 0835 painter.setPen(QPen(gradient, 1)); 0836 painter.drawRoundedRect(QRectF(2.5, 2.5, 10, 10), 2.5, 2.5); 0837 } 0838 0839 { 0840 // contrast (bottom) 0841 const QColor light(KColorUtils::shade(calcLightColor(color), shade)); 0842 QLinearGradient gradient(0, 1, 0, 12); 0843 gradient.setColorAt(0.5, Qt::transparent); 0844 gradient.setColorAt(1.0, light); 0845 0846 painter.setPen(QPen(gradient, 1)); 0847 painter.drawRoundedRect(QRectF(2, 1.5, 10, 11), 3.0, 2.5); 0848 } 0849 } 0850 0851 painter.end(); 0852 0853 TileSet tileSet(pixmap, size, size, size, size, size - 1, size, 2, 1); 0854 0855 _holeFlatCache.insert(key, new TileSet(tileSet)); 0856 0857 return tileSet; 0858 } 0859 0860 //______________________________________________________________________________ 0861 TileSet StyleHelper::scrollHole(const QColor &color, Qt::Orientation orientation, bool smallShadow) 0862 { 0863 const quint64 key(colorKey(color) << 32 | (orientation == Qt::Horizontal ? 2 : 0) | (smallShadow ? 1 : 0)); 0864 if (TileSet *cachedTileSet = _scrollHoleCache.object(key)) { 0865 return *cachedTileSet; 0866 } 0867 0868 QPixmap pixmap(highDpiPixmap(15)); 0869 pixmap.fill(Qt::transparent); 0870 0871 QPainter painter(&pixmap); 0872 0873 const QColor dark(calcDarkColor(color)); 0874 const QColor light(calcLightColor(color)); 0875 const QColor shadow(calcShadowColor(color)); 0876 0877 // use space for white border 0878 const QRect pixmapRect(0, 0, 15, 15); 0879 const QRect rect(pixmapRect.adjusted(1, 1, -1, -1)); 0880 0881 painter.setRenderHints(QPainter::Antialiasing); 0882 painter.setBrush(dark); 0883 painter.setPen(Qt::NoPen); 0884 0885 // base 0886 const qreal radius(smallShadow ? 2.5 : 3.0); 0887 painter.drawRoundedRect(rect, radius, radius); 0888 0889 { 0890 // slight shadow across the whole hole 0891 QLinearGradient shadowGradient(rect.topLeft(), orientation == Qt::Horizontal ? rect.bottomLeft() : rect.topRight()); 0892 0893 shadowGradient.setColorAt(0.0, alphaColor(shadow, 0.1)); 0894 shadowGradient.setColorAt(0.6, Qt::transparent); 0895 painter.setBrush(shadowGradient); 0896 painter.drawRoundedRect(rect, radius, radius); 0897 } 0898 0899 // first create shadow 0900 int shadowSize(5); 0901 QPixmap shadowPixmap(highDpiPixmap(shadowSize * 2)); 0902 0903 { 0904 shadowPixmap.fill(Qt::transparent); 0905 0906 QPainter painter(&shadowPixmap); 0907 painter.setRenderHints(QPainter::Antialiasing); 0908 painter.setPen(Qt::NoPen); 0909 0910 // fade-in shadow 0911 QColor shadowColor(calcShadowColor(color)); 0912 if (smallShadow) 0913 shadowColor = alphaColor(shadowColor, 0.6); 0914 drawInverseShadow(painter, shadowColor, 1, 8, 0.0); 0915 0916 painter.end(); 0917 } 0918 0919 // render shadow 0920 TileSet(shadowPixmap, shadowSize, shadowSize, shadowSize, shadowSize, shadowSize - 1, shadowSize, 2, 1) 0921 .render(rect.adjusted(-1, -1, 1, 1), &painter, TileSet::Full); 0922 0923 // light border 0924 QLinearGradient borderGradient(0, pixmapRect.top(), 0, pixmapRect.bottom()); 0925 if (smallShadow && orientation == Qt::Vertical) { 0926 borderGradient.setColorAt(0.8, Qt::transparent); 0927 borderGradient.setColorAt(1.0, alphaColor(light, 0.5)); 0928 0929 } else { 0930 borderGradient.setColorAt(0.5, Qt::transparent); 0931 borderGradient.setColorAt(1.0, alphaColor(light, 0.6)); 0932 } 0933 0934 painter.setPen(QPen(borderGradient, 1.0)); 0935 painter.setBrush(Qt::NoBrush); 0936 painter.drawRoundedRect(QRectF(pixmapRect).adjusted(0.5, 0.5, -0.5, -0.5), radius + 0.5, radius + 0.5); 0937 0938 painter.end(); 0939 TileSet tileSet(pixmap, 7, 7, 1, 1); 0940 0941 _scrollHoleCache.insert(key, new TileSet(tileSet)); 0942 return tileSet; 0943 } 0944 0945 //________________________________________________________________________________________________________ 0946 TileSet StyleHelper::scrollHandle(const QColor &color, const QColor &glow, int size) 0947 { 0948 // get key 0949 Oxygen::Cache<TileSet>::Value cache(_scrollHandleCache.get(glow)); 0950 0951 const quint64 key((colorKey(color) << 32) | size); 0952 if (TileSet *cachedTileSet = cache->object(key)) { 0953 return *cachedTileSet; 0954 } 0955 0956 QPixmap pixmap(highDpiPixmap(2 * size)); 0957 pixmap.fill(Qt::transparent); 0958 0959 QPainter painter(&pixmap); 0960 painter.setRenderHints(QPainter::Antialiasing); 0961 painter.setPen(Qt::NoPen); 0962 0963 const int fixedSize(14 * devicePixelRatio(pixmap)); 0964 painter.setWindow(0, 0, fixedSize, fixedSize); 0965 0966 QPixmap shadowPixmap(highDpiPixmap(10)); 0967 { 0968 shadowPixmap.fill(Qt::transparent); 0969 0970 QPainter painter(&shadowPixmap); 0971 painter.setRenderHints(QPainter::Antialiasing); 0972 painter.setPen(Qt::NoPen); 0973 0974 // shadow/glow 0975 drawOuterGlow(painter, glow, 10); 0976 0977 painter.end(); 0978 } 0979 0980 TileSet(shadowPixmap, 4, 4, 1, 1).render(QRect(0, 0, 14, 14), &painter, TileSet::Full); 0981 0982 // outline 0983 { 0984 const QColor mid(calcMidColor(color)); 0985 QLinearGradient linearGradient(0, 3, 0, 11); 0986 linearGradient.setColorAt(0, color); 0987 linearGradient.setColorAt(1, mid); 0988 painter.setPen(Qt::NoPen); 0989 painter.setBrush(linearGradient); 0990 painter.drawRoundedRect(QRectF(3, 3, 8, 8), 2.5, 2.5); 0991 } 0992 0993 // contrast 0994 { 0995 const QColor light(calcLightColor(color)); 0996 QLinearGradient linearGradient(0, 3, 0, 11); 0997 linearGradient.setColorAt(0., alphaColor(light, 0.9)); 0998 linearGradient.setColorAt(0.5, alphaColor(light, 0.44)); 0999 painter.setBrush(linearGradient); 1000 painter.drawRoundedRect(QRectF(3, 3, 8, 8), 2.5, 2.5); 1001 } 1002 1003 painter.end(); 1004 1005 // create tileset and return 1006 TileSet tileSet(pixmap, size - 1, size, 1, 1); 1007 cache->insert(key, new TileSet(tileSet)); 1008 1009 return tileSet; 1010 } 1011 1012 //________________________________________________________________________________________________________ 1013 TileSet StyleHelper::slitFocused(const QColor &glow) 1014 { 1015 const quint64 key((colorKey(glow) << 32)); 1016 if (TileSet *cachedTileSet = _slitCache.object(key)) { 1017 return *cachedTileSet; 1018 } 1019 1020 QPixmap pixmap(highDpiPixmap(9)); 1021 pixmap.fill(Qt::transparent); 1022 1023 QPainter painter(&pixmap); 1024 painter.setRenderHints(QPainter::Antialiasing); 1025 painter.setPen(glow); 1026 painter.drawRoundedRect(QRectF(1.5, 1.5, 6, 6), 2.5, 2.5); 1027 painter.end(); 1028 1029 TileSet tileSet(pixmap, 4, 4, 1, 1); 1030 _slitCache.insert(key, new TileSet(tileSet)); 1031 return tileSet; 1032 } 1033 1034 //____________________________________________________________________ 1035 TileSet StyleHelper::dockFrame(const QColor &top, const QColor &bottom) 1036 { 1037 const quint64 key(colorKey(top) << 32 | colorKey(bottom)); 1038 if (TileSet *cachedTileSet = _dockFrameCache.object(key)) { 1039 return *cachedTileSet; 1040 } 1041 1042 int size(13); 1043 QPixmap pm(size, size); 1044 pm.fill(Qt::transparent); 1045 1046 QPainter painter(&pm); 1047 painter.setRenderHints(QPainter::Antialiasing); 1048 painter.setBrush(Qt::NoBrush); 1049 1050 const QColor lightTop = alphaColor(calcLightColor(top), 0.5); 1051 const QColor lightBottom = alphaColor(calcLightColor(bottom), 0.5); 1052 const QColor darkTop = alphaColor(calcDarkColor(top), 0.6); 1053 const QColor darkBottom = alphaColor(calcDarkColor(bottom), 0.6); 1054 1055 // dark frame 1056 { 1057 QLinearGradient linearGradient(0, 0.5, 0, size - 1.5); 1058 linearGradient.setColorAt(0.0, darkTop); 1059 linearGradient.setColorAt(1.0, darkBottom); 1060 1061 painter.setPen(QPen(linearGradient, 1)); 1062 painter.drawRoundedRect(QRectF(1.5, 0.5, size - 3, size - 2), 4, 4); 1063 } 1064 1065 // bottom contrast 1066 { 1067 QLinearGradient linearGradient(0, 0.5, 0, size - 0.5); 1068 linearGradient.setColorAt(0.0, Qt::transparent); 1069 linearGradient.setColorAt(1.0, lightBottom); 1070 painter.setPen(QPen(linearGradient, 1.0)); 1071 painter.drawRoundedRect(QRectF(0.5, 0.5, size - 1, size - 1), 4.5, 4.5); 1072 } 1073 1074 // top contrast 1075 { 1076 QLinearGradient linearGradient(0, 1.5, 0, size - 2.5); 1077 linearGradient.setColorAt(0.0, lightTop); 1078 linearGradient.setColorAt(1.0, Qt::transparent); 1079 painter.setPen(QPen(linearGradient, 1.0)); 1080 painter.drawRoundedRect(QRectF(2.5, 1.5, size - 5, size - 4), 3.5, 3.5); 1081 } 1082 1083 painter.end(); 1084 TileSet tileSet(pm, (size - 1) / 2, (size - 1) / 2, 1, 1); 1085 1086 _dockFrameCache.insert(key, new TileSet(tileSet)); 1087 return tileSet; 1088 } 1089 1090 //____________________________________________________________________ 1091 TileSet StyleHelper::selection(const QColor &color, int height, bool custom) 1092 { 1093 const quint64 key((colorKey(color) << 32) | (height << 1) | custom); 1094 if (TileSet *cachedTileSet = _selectionCache.object(key)) { 1095 return *cachedTileSet; 1096 } 1097 1098 const qreal rounding(2.5); 1099 1100 QPixmap pixmap(highDpiPixmap(32 + 16, height)); 1101 pixmap.fill(Qt::transparent); 1102 1103 QRectF r(0, 0, 32 + 16, height); 1104 1105 QPainter painter(&pixmap); 1106 painter.setRenderHint(QPainter::Antialiasing); 1107 1108 // items with custom background brushes always have their background drawn 1109 // regardless of whether they are hovered or selected or neither so 1110 // the gradient effect needs to be more subtle 1111 1112 { 1113 // fill 1114 const int lightenAmount(custom ? 110 : 130); 1115 QLinearGradient gradient(0, 0, 0, r.bottom()); 1116 gradient.setColorAt(0, color.lighter(lightenAmount)); 1117 gradient.setColorAt(1, color); 1118 1119 painter.setPen(Qt::NoPen); 1120 painter.setBrush(gradient); 1121 painter.drawRoundedRect(r, rounding + 0.5, rounding + 0.5); 1122 } 1123 1124 { 1125 // contrast 1126 QLinearGradient gradient(0, 0, 0, r.bottom()); 1127 gradient.setColorAt(0, color); 1128 gradient.setColorAt(1, Qt::transparent); 1129 1130 r.adjust(0.5, 0.5, -0.5, -0.5); 1131 painter.setPen(QPen(color, 1)); 1132 painter.setBrush(Qt::NoBrush); 1133 painter.drawRoundedRect(r, rounding, rounding); 1134 } 1135 1136 TileSet tileSet(pixmap, 8, 0, 32, height); 1137 _selectionCache.insert(key, new TileSet(tileSet)); 1138 return tileSet; 1139 } 1140 1141 //________________________________________________________________________________________________________ 1142 void StyleHelper::drawInverseGlow(QPainter &painter, const QColor &color, int pad, int size, int rsize) const 1143 { 1144 const QRectF r(pad, pad, size, size); 1145 const qreal m(qreal(size) * 0.5); 1146 1147 const qreal width(3.5); 1148 const qreal bias(_glowBias * 7.0 / rsize); 1149 const qreal k0((m - width) / (m - bias)); 1150 QRadialGradient glowGradient(pad + m, pad + m, m - bias); 1151 for (int i = 0; i < 8; i++) { 1152 // inverse parabolic gradient 1153 qreal k1 = (k0 * qreal(i) + qreal(8 - i)) * 0.125; 1154 qreal a = 1.0 - sqrt(i * 0.125); 1155 glowGradient.setColorAt(k1, alphaColor(color, a)); 1156 } 1157 1158 glowGradient.setColorAt(k0, alphaColor(color, 0.0)); 1159 painter.setBrush(glowGradient); 1160 painter.drawEllipse(r); 1161 } 1162 1163 //________________________________________________________________________________________________________ 1164 bool StyleHelper::compositingActive(void) const 1165 { 1166 #if OXYGEN_HAVE_X11 1167 if (isX11()) { 1168 return QX11Info::isCompositingManagerRunning(QX11Info::appScreen()); 1169 } 1170 #endif 1171 return true; 1172 } 1173 1174 //________________________________________________________________________________________________________ 1175 bool StyleHelper::hasDecoration(const QWidget *widget) const 1176 { 1177 if (!widget->isTopLevel()) 1178 return false; 1179 if (widget->windowFlags() & (Qt::X11BypassWindowManagerHint | Qt::FramelessWindowHint)) { 1180 return false; 1181 } 1182 return true; 1183 } 1184 1185 //________________________________________________________________________________________________________ 1186 TileSet StyleHelper::hole(const QColor &color, const QColor &glow, int size, StyleOptions options) 1187 { 1188 // get key 1189 Oxygen::Cache<TileSet>::Value cache(_holeCache.get(glow)); 1190 1191 const quint64 key((colorKey(color) << 32) | (size << 4) | options); 1192 if (TileSet *cachedTileSet = cache->object(key)) { 1193 return *cachedTileSet; 1194 } 1195 1196 // first create shadow 1197 const int shadowSize((size * 5) / 7); 1198 QPixmap shadowPixmap(highDpiPixmap(shadowSize * 2)); 1199 1200 // calc alpha channel and fade 1201 const int alpha(glow.isValid() ? glow.alpha() : 0); 1202 1203 { 1204 shadowPixmap.fill(Qt::transparent); 1205 1206 QPainter painter(&shadowPixmap); 1207 painter.setRenderHints(QPainter::Antialiasing); 1208 painter.setPen(Qt::NoPen); 1209 const int fixedSize(10 * devicePixelRatio(shadowPixmap)); 1210 painter.setWindow(0, 0, fixedSize, fixedSize); 1211 1212 // fade-in shadow 1213 if (alpha < 255) { 1214 QColor shadowColor(calcShadowColor(color)); 1215 shadowColor.setAlpha(255 - alpha); 1216 drawInverseShadow(painter, shadowColor, 1, 8, 0.0); 1217 } 1218 1219 // fade-out glow 1220 if (alpha > 0) { 1221 drawInverseGlow(painter, glow, 1, 8, shadowSize); 1222 } 1223 1224 painter.end(); 1225 } 1226 1227 // create pixmap 1228 QPixmap pixmap(highDpiPixmap(size * 2)); 1229 pixmap.fill(Qt::transparent); 1230 1231 QPainter painter(&pixmap); 1232 painter.setRenderHints(QPainter::Antialiasing); 1233 painter.setPen(Qt::NoPen); 1234 const int fixedSize(14 * devicePixelRatio(pixmap)); 1235 painter.setWindow(0, 0, fixedSize, fixedSize); 1236 1237 // hole mask 1238 painter.setCompositionMode(QPainter::CompositionMode_DestinationOut); 1239 painter.setBrush(Qt::black); 1240 1241 painter.drawRoundedRect(QRectF(1, 1, 12, 12), 2.5, 2.5); 1242 painter.setCompositionMode(QPainter::CompositionMode_SourceOver); 1243 1244 // render shadow 1245 TileSet(shadowPixmap, shadowSize, shadowSize, shadowSize, shadowSize, shadowSize - 1, shadowSize, 2, 1) 1246 .render(QRect(QPoint(0, 0), pixmap.size() / devicePixelRatio(pixmap)), &painter); 1247 1248 if ((options & HoleOutline) && alpha < 255) { 1249 QColor dark(calcDarkColor(color)); 1250 dark.setAlpha(255 - alpha); 1251 QLinearGradient blend(0, 0, 0, 14); 1252 blend.setColorAt(0, Qt::transparent); 1253 blend.setColorAt(0.8, dark); 1254 1255 painter.setBrush(Qt::NoBrush); 1256 painter.setPen(QPen(blend, 1)); 1257 painter.drawRoundedRect(QRectF(1.5, 1.5, 11, 11), 3.0, 3.0); 1258 painter.setPen(Qt::NoPen); 1259 } 1260 1261 if (options & HoleContrast) { 1262 QColor light(calcLightColor(color)); 1263 QLinearGradient blend(0, 0, 0, 18); 1264 blend.setColorAt(0.5, Qt::transparent); 1265 blend.setColorAt(1.0, light); 1266 1267 painter.setBrush(Qt::NoBrush); 1268 painter.setPen(QPen(blend, 1)); 1269 painter.drawRoundedRect(QRectF(0.5, 0.5, 13, 13), 4.0, 4.0); 1270 painter.setPen(Qt::NoPen); 1271 } 1272 1273 painter.end(); 1274 1275 // create tileset and return 1276 TileSet tileSet(pixmap, size, size, size, size, size - 1, size, 2, 1); 1277 cache->insert(key, new TileSet(tileSet)); 1278 return tileSet; 1279 } 1280 1281 //______________________________________________________________________________________ 1282 void StyleHelper::drawSlab(QPainter &painter, const QColor &color, qreal shade) 1283 { 1284 const QColor light(KColorUtils::shade(calcLightColor(color), shade)); 1285 const QColor base(alphaColor(light, 0.85)); 1286 const QColor dark(KColorUtils::shade(calcDarkColor(color), shade)); 1287 1288 // bevel, part 1 1289 painter.save(); 1290 const qreal y(KColorUtils::luma(base)); 1291 const qreal yl(KColorUtils::luma(light)); 1292 const qreal yd(KColorUtils::luma(dark)); 1293 QLinearGradient bevelGradient1(0, 7, 0, 11); 1294 bevelGradient1.setColorAt(0.0, light); 1295 if (y < yl && y > yd) { 1296 // no middle when color is very light/dark 1297 bevelGradient1.setColorAt(0.5, base); 1298 } 1299 1300 bevelGradient1.setColorAt(0.9, base); 1301 painter.setBrush(bevelGradient1); 1302 painter.drawRoundedRect(QRectF(3.0, 3.0, 8.0, 8.0), 3.5, 3.5); 1303 1304 // bevel, part 2 1305 if (_slabThickness > 0.0) { 1306 QLinearGradient bevelGradient2(0, 6, 0, 19); 1307 bevelGradient2.setColorAt(0.0, light); 1308 bevelGradient2.setColorAt(0.9, base); 1309 painter.setBrush(bevelGradient2); 1310 painter.drawEllipse(QRectF(3.6, 3.6, 6.8, 6.8)); 1311 } 1312 1313 // inside mask 1314 painter.setCompositionMode(QPainter::CompositionMode_DestinationOut); 1315 painter.setBrush(Qt::black); 1316 1317 const qreal ic(3.6 + 0.5 * _slabThickness); 1318 const qreal is(14.0 - 2.0 * ic); 1319 painter.drawEllipse(QRectF(ic, ic, is, is)); 1320 painter.restore(); 1321 } 1322 1323 //__________________________________________________________________________________________________________ 1324 void StyleHelper::drawRoundSlab(QPainter &painter, const QColor &color, qreal shade) 1325 { 1326 painter.save(); 1327 1328 // colors 1329 const QColor base(KColorUtils::shade(color, shade)); 1330 const QColor light(KColorUtils::shade(calcLightColor(color), shade)); 1331 1332 // bevel, part 1 1333 QLinearGradient bevelGradient1(0, 10, 0, 18); 1334 bevelGradient1.setColorAt(0.0, light); 1335 bevelGradient1.setColorAt(0.9, alphaColor(light, 0.85)); 1336 painter.setBrush(bevelGradient1); 1337 painter.drawEllipse(QRectF(3.0, 3.0, 15.0, 15.0)); 1338 1339 // bevel, part 2 1340 if (_slabThickness > 0.0) { 1341 QLinearGradient bevelGradient2(0, 7, 0, 28); 1342 bevelGradient2.setColorAt(0.0, light); 1343 bevelGradient2.setColorAt(0.9, base); 1344 painter.setBrush(bevelGradient2); 1345 painter.drawEllipse(QRectF(3.6, 3.6, 13.8, 13.8)); 1346 } 1347 1348 // inside 1349 QLinearGradient innerGradient(0, -17, 0, 20); 1350 innerGradient.setColorAt(0, light); 1351 innerGradient.setColorAt(1, base); 1352 painter.setBrush(innerGradient); 1353 const qreal ic(3.6 + _slabThickness); 1354 const qreal is(21.0 - 2.0 * ic); 1355 painter.drawEllipse(QRectF(ic, ic, is, is)); 1356 1357 painter.restore(); 1358 } 1359 1360 //__________________________________________________________________________________________________________ 1361 void StyleHelper::drawSliderSlab(QPainter &painter, const QColor &color, bool sunken, qreal shade) 1362 { 1363 painter.save(); 1364 1365 const QColor light(KColorUtils::shade(calcLightColor(color), shade)); 1366 const QColor dark(KColorUtils::shade(calcDarkColor(color), shade)); 1367 1368 painter.setPen(Qt::NoPen); 1369 1370 { 1371 // plain background 1372 QLinearGradient linearGradient(0, 3, 0, 21); 1373 linearGradient.setColorAt(0, light); 1374 linearGradient.setColorAt(1, dark); 1375 1376 const QRectF r(3, 3, 15, 15); 1377 painter.setBrush(linearGradient); 1378 painter.drawEllipse(r); 1379 } 1380 1381 if (sunken) { 1382 // plain background 1383 QLinearGradient linearGradient(0, 3, 0, 21); 1384 linearGradient.setColorAt(0, dark); 1385 linearGradient.setColorAt(1, light); 1386 1387 const QRectF r(5, 5, 11, 11); 1388 painter.setBrush(linearGradient); 1389 painter.drawEllipse(r); 1390 } 1391 1392 { 1393 // outline circle 1394 const qreal penWidth(1); 1395 QLinearGradient linearGradient(0, 3, 0, 30); 1396 linearGradient.setColorAt(0, light); 1397 linearGradient.setColorAt(1, dark); 1398 1399 const QRectF r(3.5, 3.5, 14, 14); 1400 painter.setPen(QPen(linearGradient, penWidth)); 1401 painter.setBrush(Qt::NoBrush); 1402 painter.drawEllipse(r); 1403 } 1404 1405 painter.restore(); 1406 } 1407 1408 //______________________________________________________________________________ 1409 void StyleHelper::init(void) 1410 { 1411 _useBackgroundGradient = true; 1412 1413 #if OXYGEN_HAVE_X11 1414 if (isX11()) { 1415 // create compositing screen 1416 const QString atomName(QStringLiteral("_NET_WM_CM_S%1").arg(QX11Info::appScreen())); 1417 _compositingManagerAtom = createAtom(atomName); 1418 } 1419 #endif 1420 } 1421 }