Changeset View
Changeset View
Standalone View
Standalone View
kstyle/breezeshadowhelper.cpp
1 | /************************************************************************* | 1 | /************************************************************************* | ||
---|---|---|---|---|---|
2 | * Copyright (C) 2014 by Hugo Pereira Da Costa <hugo.pereira@free.fr> * | 2 | * Copyright (C) 2014 by Hugo Pereira Da Costa <hugo.pereira@free.fr> * | ||
3 | * Copyright (C) 2018 by Vlad Zagorodniy <vladzzag@gmail.com> * | ||||
3 | * * | 4 | * * | ||
4 | * This program is free software; you can redistribute it and/or modify * | 5 | * This program is free software; you can redistribute it and/or modify * | ||
5 | * it under the terms of the GNU General Public License as published by * | 6 | * it under the terms of the GNU General Public License as published by * | ||
6 | * the Free Software Foundation; either version 2 of the License, or * | 7 | * the Free Software Foundation; either version 2 of the License, or * | ||
7 | * (at your option) any later version. * | 8 | * (at your option) any later version. * | ||
8 | * * | 9 | * * | ||
9 | * This program is distributed in the hope that it will be useful, * | 10 | * This program is distributed in the hope that it will be useful, * | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
12 | * GNU General Public License for more details. * | 13 | * GNU General Public License for more details. * | ||
13 | * * | 14 | * * | ||
14 | * You should have received a copy of the GNU General Public License * | 15 | * You should have received a copy of the GNU General Public License * | ||
15 | * along with this program; if not, write to the * | 16 | * along with this program; if not, write to the * | ||
16 | * Free Software Foundation, Inc., * | 17 | * Free Software Foundation, Inc., * | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * | ||
18 | *************************************************************************/ | 19 | *************************************************************************/ | ||
19 | 20 | | |||
20 | #include "breezeshadowhelper.h" | 21 | #include "breezeshadowhelper.h" | ||
21 | 22 | | |||
22 | #include "breeze.h" | 23 | #include "breeze.h" | ||
23 | #include "breezeboxshadowhelper.h" | 24 | #include "breezeboxshadowrenderer.h" | ||
24 | #include "breezehelper.h" | 25 | #include "breezehelper.h" | ||
25 | #include "breezepropertynames.h" | 26 | #include "breezepropertynames.h" | ||
26 | #include "breezestyleconfigdata.h" | 27 | #include "breezestyleconfigdata.h" | ||
27 | 28 | | |||
28 | #include <QDockWidget> | 29 | #include <QDockWidget> | ||
29 | #include <QEvent> | 30 | #include <QEvent> | ||
30 | #include <QApplication> | 31 | #include <QApplication> | ||
31 | #include <QMenu> | 32 | #include <QMenu> | ||
Show All 15 Lines | |||||
47 | #include <KWayland/Client/surface.h> | 48 | #include <KWayland/Client/surface.h> | ||
48 | #endif | 49 | #endif | ||
49 | 50 | | |||
50 | namespace | 51 | namespace | ||
51 | { | 52 | { | ||
52 | using Breeze::CompositeShadowParams; | 53 | using Breeze::CompositeShadowParams; | ||
53 | using Breeze::ShadowParams; | 54 | using Breeze::ShadowParams; | ||
54 | 55 | | |||
56 | // Parameters for each shadow are computed as follows: | ||||
57 | // * blur-radius = z / tan(alpha) | ||||
58 | // * offset-y = blur-radius * offset-factor | ||||
59 | // * opacity is hand-picked | ||||
60 | // | ||||
61 | // where | ||||
62 | // z is elevation(see value for each shadow size down below), | ||||
63 | // alpha is angle of the light | ||||
64 | // offset-factor how much shadow should be shifted | ||||
65 | // | ||||
66 | // For the directional light(shadow1), alpha and offset-factor | ||||
67 | // have the following values: | ||||
68 | // * alpha = 50deg | ||||
69 | // * offset-factor = 0.5 | ||||
70 | // | ||||
71 | // For the ambient light(shadow2), alpha and offset-factor have | ||||
72 | // the following values: | ||||
73 | // * alpha = 75deg | ||||
74 | // * offset-factor = 0.33 | ||||
75 | // | ||||
76 | // Opacity values are picked as follows: | ||||
77 | // * as elevation increases, the opacity of the directional shadow, | ||||
78 | // i.e. shadow1, increases; | ||||
79 | // * as elevation increases, the opacity of the ambient shadow, | ||||
80 | // i.e. shadow2, decreases. | ||||
81 | // | ||||
82 | // Widget style shadows are slightly lighter than decoration shadows. | ||||
55 | const CompositeShadowParams s_shadowParams[] = { | 83 | const CompositeShadowParams s_shadowParams[] = { | ||
56 | // None | 84 | // None (z: 0) | ||
57 | CompositeShadowParams(), | 85 | CompositeShadowParams(), | ||
58 | // Small | 86 | // Small (z: 12) | ||
59 | CompositeShadowParams( | 87 | CompositeShadowParams( | ||
60 | QPoint(0, 6), | 88 | QPoint(0, 5), | ||
61 | ShadowParams(QPoint(0, 0), 12, 0.2), | 89 | ShadowParams(QPoint(0, 0), 10, 0.2), | ||
62 | ShadowParams(QPoint(0, -3), 6, 0.16)), | 90 | ShadowParams(QPoint(0, -4), 3, 0.16)), | ||
63 | // Medium | 91 | // Medium (z: 16) | ||
92 | CompositeShadowParams( | ||||
93 | QPoint(0, 7), | ||||
94 | ShadowParams(QPoint(0, 0), 13, 0.21), | ||||
95 | ShadowParams(QPoint(0, -6), 4, 0.14)), | ||||
96 | // Large (z: 20) | ||||
64 | CompositeShadowParams( | 97 | CompositeShadowParams( | ||
65 | QPoint(0, 8), | 98 | QPoint(0, 8), | ||
66 | ShadowParams(QPoint(0, 0), 16, 0.21), | 99 | ShadowParams(QPoint(0, 0), 16, 0.23), | ||
67 | ShadowParams(QPoint(0, -4), 6, 0.14)), | 100 | ShadowParams(QPoint(0, -6), 5, 0.12)), | ||
68 | // Large | 101 | // Very Large (z: 24) | ||
69 | CompositeShadowParams( | 102 | CompositeShadowParams( | ||
70 | QPoint(0, 10), | 103 | QPoint(0, 10), | ||
71 | ShadowParams(QPoint(0, 0), 20, 0.23), | 104 | ShadowParams(QPoint(0, 0), 20, 0.26), | ||
72 | ShadowParams(QPoint(0, -5), 8, 0.12)), | 105 | ShadowParams(QPoint(0, -8), 6, 0.12)) | ||
73 | // Very Large | | |||
74 | CompositeShadowParams( | | |||
75 | QPoint(0, 12), | | |||
76 | ShadowParams(QPoint(0, 0), 24, 0.26), | | |||
77 | ShadowParams(QPoint(0, -5), 10, 0.12)) | | |||
78 | }; | 106 | }; | ||
79 | } | 107 | } | ||
80 | 108 | | |||
81 | namespace Breeze | 109 | namespace Breeze | ||
82 | { | 110 | { | ||
83 | 111 | | |||
84 | const char ShadowHelper::netWMShadowAtomName[] ="_KDE_NET_WM_SHADOW"; | 112 | const char ShadowHelper::netWMShadowAtomName[] ="_KDE_NET_WM_SHADOW"; | ||
85 | 113 | | |||
▲ Show 20 Lines • Show All 194 Lines • ▼ Show 20 Line(s) | 301 | { | |||
280 | } | 308 | } | ||
281 | 309 | | |||
282 | auto withOpacity = [](const QColor &color, qreal opacity) -> QColor { | 310 | auto withOpacity = [](const QColor &color, qreal opacity) -> QColor { | ||
283 | QColor c(color); | 311 | QColor c(color); | ||
284 | c.setAlphaF(opacity); | 312 | c.setAlphaF(opacity); | ||
285 | return c; | 313 | return c; | ||
286 | }; | 314 | }; | ||
287 | 315 | | |||
288 | const int shadowSize = qMax(params.shadow1.radius, params.shadow2.radius); | | |||
289 | const QColor color = StyleConfigData::shadowColor(); | 316 | const QColor color = StyleConfigData::shadowColor(); | ||
290 | const qreal strength = static_cast<qreal>(StyleConfigData::shadowStrength()) / 255.0; | 317 | const qreal strength = static_cast<qreal>(StyleConfigData::shadowStrength()) / 255.0; | ||
291 | 318 | | |||
292 | const QRect box( | 319 | const QSize boxSize = BoxShadowRenderer::calculateMinimumBoxSize(params.shadow1.radius) | ||
293 | shadowSize, | 320 | .expandedTo(BoxShadowRenderer::calculateMinimumBoxSize(params.shadow2.radius)); | ||
294 | shadowSize, | | |||
295 | 2 * shadowSize + 1, | | |||
296 | 2 * shadowSize + 1); | | |||
297 | const QRect outerRect = box.adjusted(-shadowSize, -shadowSize, shadowSize, shadowSize); | | |||
298 | 321 | | |||
299 | QPixmap shadow = _helper.highDpiPixmap(outerRect.width(), outerRect.height()); | 322 | #if QT_VERSION >= 0x050300 | ||
300 | shadow.fill(Qt::transparent); | 323 | const qreal dpr = qApp->devicePixelRatio(); | ||
324 | #else | ||||
325 | const qreal dpr = 1.0; | ||||
326 | #endif | ||||
301 | 327 | | |||
302 | QPainter painter(&shadow); | 328 | const qreal frameRadius = _helper.frameRadius(); | ||
303 | painter.setRenderHint(QPainter::Antialiasing); | | |||
304 | 329 | | |||
305 | // Draw the "shape" shadow. | 330 | BoxShadowRenderer shadowRenderer; | ||
306 | BoxShadowHelper::boxShadow( | 331 | shadowRenderer.setBorderRadius(frameRadius); | ||
307 | &painter, | 332 | shadowRenderer.setBoxSize(boxSize); | ||
308 | box, | 333 | shadowRenderer.setDevicePixelRatio(dpr); | ||
309 | params.shadow1.offset, | | |||
310 | params.shadow1.radius, | | |||
311 | withOpacity(color, params.shadow1.opacity * strength)); | | |||
312 | 334 | | |||
313 | // Draw the "contrast" shadow. | 335 | shadowRenderer.addShadow(params.shadow1.offset, params.shadow1.radius, | ||
314 | BoxShadowHelper::boxShadow( | 336 | withOpacity(color, params.shadow1.opacity * strength)); | ||
315 | &painter, | 337 | shadowRenderer.addShadow(params.shadow2.offset, params.shadow2.radius, | ||
316 | box, | | |||
317 | params.shadow2.offset, | | |||
318 | params.shadow2.radius, | | |||
319 | withOpacity(color, params.shadow2.opacity * strength)); | 338 | withOpacity(color, params.shadow2.opacity * strength)); | ||
320 | 339 | | |||
340 | QImage shadowTexture = shadowRenderer.render(); | ||||
341 | | ||||
342 | const QRect outerRect(QPoint(0, 0), shadowTexture.size() / dpr); | ||||
343 | | ||||
344 | QRect boxRect(QPoint(0, 0), boxSize); | ||||
345 | boxRect.moveCenter(outerRect.center()); | ||||
346 | | ||||
321 | // Mask out inner rect. | 347 | // Mask out inner rect. | ||
348 | QPainter painter(&shadowTexture); | ||||
349 | painter.setRenderHint(QPainter::Antialiasing); | ||||
350 | | ||||
322 | const QMargins margins = QMargins( | 351 | const QMargins margins = QMargins( | ||
323 | shadowSize - Metrics::Shadow_Overlap - params.offset.x(), | 352 | boxRect.left() - outerRect.left() - Metrics::Shadow_Overlap - params.offset.x(), | ||
324 | shadowSize - Metrics::Shadow_Overlap - params.offset.y(), | 353 | boxRect.top() - outerRect.top() - Metrics::Shadow_Overlap - params.offset.y(), | ||
325 | shadowSize - Metrics::Shadow_Overlap + params.offset.x(), | 354 | outerRect.right() - boxRect.right() - Metrics::Shadow_Overlap + params.offset.x(), | ||
326 | shadowSize - Metrics::Shadow_Overlap + params.offset.y()); | 355 | outerRect.bottom() - boxRect.bottom() - Metrics::Shadow_Overlap + params.offset.y()); | ||
327 | const qreal frameRadius = _helper.frameRadius(); | | |||
328 | 356 | | |||
329 | painter.setPen(Qt::NoPen); | 357 | painter.setPen(Qt::NoPen); | ||
330 | painter.setBrush(Qt::black); | 358 | painter.setBrush(Qt::black); | ||
331 | painter.setCompositionMode(QPainter::CompositionMode_DestinationOut); | 359 | painter.setCompositionMode(QPainter::CompositionMode_DestinationOut); | ||
332 | painter.drawRoundedRect( | 360 | painter.drawRoundedRect( | ||
333 | #if BREEZE_USE_KDE4 | 361 | #if BREEZE_USE_KDE4 | ||
334 | outerRect.adjusted(margins.left(), margins.top(), -margins.right(), -margins.bottom()), | 362 | outerRect.adjusted(margins.left(), margins.top(), -margins.right(), -margins.bottom()), | ||
335 | #else | 363 | #else | ||
336 | outerRect - margins, | 364 | outerRect - margins, | ||
337 | #endif | 365 | #endif | ||
338 | frameRadius, | 366 | frameRadius, | ||
339 | frameRadius); | 367 | frameRadius); | ||
340 | 368 | | |||
341 | // We're done. | 369 | // We're done. | ||
342 | painter.end(); | 370 | painter.end(); | ||
343 | 371 | | |||
344 | const QPoint innerRectTopLeft = outerRect.center(); | 372 | const QPoint innerRectTopLeft = outerRect.center(); | ||
345 | _shadowTiles = TileSet( | 373 | _shadowTiles = TileSet( | ||
346 | shadow, | 374 | QPixmap::fromImage(shadowTexture), | ||
347 | innerRectTopLeft.x(), | 375 | innerRectTopLeft.x(), | ||
348 | innerRectTopLeft.y(), | 376 | innerRectTopLeft.y(), | ||
349 | 1, 1); | 377 | 1, 1); | ||
350 | 378 | | |||
351 | return _shadowTiles; | 379 | return _shadowTiles; | ||
352 | } | 380 | } | ||
353 | 381 | | |||
354 | 382 | | |||
▲ Show 20 Lines • Show All 213 Lines • ▼ Show 20 Line(s) | |||||
568 | //_______________________________________________________ | 596 | //_______________________________________________________ | ||
569 | QMargins ShadowHelper::shadowMargins( QWidget* widget ) const | 597 | QMargins ShadowHelper::shadowMargins( QWidget* widget ) const | ||
570 | { | 598 | { | ||
571 | const CompositeShadowParams params = lookupShadowParams(StyleConfigData::shadowSize()); | 599 | const CompositeShadowParams params = lookupShadowParams(StyleConfigData::shadowSize()); | ||
572 | if (params.isNone()) { | 600 | if (params.isNone()) { | ||
573 | return QMargins(); | 601 | return QMargins(); | ||
574 | } | 602 | } | ||
575 | 603 | | |||
576 | const int shadowSize = qMax(params.shadow1.radius, params.shadow2.radius); | 604 | const QSize boxSize = BoxShadowRenderer::calculateMinimumBoxSize(params.shadow1.radius) | ||
605 | .expandedTo(BoxShadowRenderer::calculateMinimumBoxSize(params.shadow2.radius)); | ||||
606 | | ||||
607 | const QSize shadowSize = BoxShadowRenderer::calculateMinimumShadowTextureSize(boxSize, params.shadow1.radius, params.shadow1.offset) | ||||
608 | .expandedTo(BoxShadowRenderer::calculateMinimumShadowTextureSize(boxSize, params.shadow2.radius, params.shadow2.offset)); | ||||
609 | | ||||
610 | const QRect shadowRect(QPoint(0, 0), shadowSize); | ||||
611 | | ||||
612 | QRect boxRect(QPoint(0, 0), boxSize); | ||||
613 | boxRect.moveCenter(shadowRect.center()); | ||||
614 | | ||||
577 | QMargins margins( | 615 | QMargins margins( | ||
578 | shadowSize - Metrics::Shadow_Overlap - params.offset.x(), | 616 | boxRect.left() - shadowRect.left() - Metrics::Shadow_Overlap - params.offset.x(), | ||
579 | shadowSize - Metrics::Shadow_Overlap - params.offset.y(), | 617 | boxRect.top() - shadowRect.top() - Metrics::Shadow_Overlap - params.offset.y(), | ||
580 | shadowSize - Metrics::Shadow_Overlap + params.offset.x(), | 618 | shadowRect.right() - boxRect.right() - Metrics::Shadow_Overlap + params.offset.x(), | ||
581 | shadowSize - Metrics::Shadow_Overlap + params.offset.y()); | 619 | shadowRect.bottom() - boxRect.right() - Metrics::Shadow_Overlap + params.offset.y()); | ||
582 | 620 | | |||
583 | if (widget->inherits("QBalloonTip")) { | 621 | if (widget->inherits("QBalloonTip")) { | ||
584 | // Balloon tip needs special margins to deal with the arrow. | 622 | // Balloon tip needs special margins to deal with the arrow. | ||
585 | int top = 0; | 623 | int top = 0; | ||
586 | int bottom = 0; | 624 | int bottom = 0; | ||
587 | widget->getContentsMargins(nullptr, &top, nullptr, &bottom); | 625 | widget->getContentsMargins(nullptr, &top, nullptr, &bottom); | ||
588 | 626 | | |||
589 | // Need to decrement default size further due to extra hard coded round corner. | 627 | // Need to decrement default size further due to extra hard coded round corner. | ||
▲ Show 20 Lines • Show All 69 Lines • Show Last 20 Lines |