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