Changeset View
Changeset View
Standalone View
Standalone View
kdecoration/breezedecoration.cpp
Show All 23 Lines | |||||
24 | #include "breeze.h" | 24 | #include "breeze.h" | ||
25 | #include "breezesettingsprovider.h" | 25 | #include "breezesettingsprovider.h" | ||
26 | #include "config-breeze.h" | 26 | #include "config-breeze.h" | ||
27 | #include "config/breezeconfigwidget.h" | 27 | #include "config/breezeconfigwidget.h" | ||
28 | 28 | | |||
29 | #include "breezebutton.h" | 29 | #include "breezebutton.h" | ||
30 | #include "breezesizegrip.h" | 30 | #include "breezesizegrip.h" | ||
31 | 31 | | |||
32 | #include "breezeboxshadowhelper.h" | ||||
33 | | ||||
32 | #include <KDecoration2/DecoratedClient> | 34 | #include <KDecoration2/DecoratedClient> | ||
33 | #include <KDecoration2/DecorationButtonGroup> | 35 | #include <KDecoration2/DecorationButtonGroup> | ||
34 | #include <KDecoration2/DecorationSettings> | 36 | #include <KDecoration2/DecorationSettings> | ||
35 | #include <KDecoration2/DecorationShadow> | 37 | #include <KDecoration2/DecorationShadow> | ||
36 | 38 | | |||
37 | #include <KConfigGroup> | 39 | #include <KConfigGroup> | ||
38 | #include <KColorUtils> | 40 | #include <KColorUtils> | ||
39 | #include <KSharedConfig> | 41 | #include <KSharedConfig> | ||
40 | #include <KPluginFactory> | 42 | #include <KPluginFactory> | ||
41 | 43 | | |||
44 | #include <QGuiApplication> | ||||
42 | #include <QPainter> | 45 | #include <QPainter> | ||
46 | #include <QScreen> | ||||
43 | #include <QTextStream> | 47 | #include <QTextStream> | ||
44 | #include <QTimer> | 48 | #include <QTimer> | ||
45 | 49 | | |||
46 | #if BREEZE_HAVE_X11 | 50 | #if BREEZE_HAVE_X11 | ||
47 | #include <QX11Info> | 51 | #include <QX11Info> | ||
48 | #endif | 52 | #endif | ||
49 | 53 | | |||
50 | #include <cmath> | 54 | #include <cmath> | ||
51 | 55 | | |||
52 | K_PLUGIN_FACTORY_WITH_JSON( | 56 | K_PLUGIN_FACTORY_WITH_JSON( | ||
53 | BreezeDecoFactory, | 57 | BreezeDecoFactory, | ||
54 | "breeze.json", | 58 | "breeze.json", | ||
55 | registerPlugin<Breeze::Decoration>(); | 59 | registerPlugin<Breeze::Decoration>(); | ||
56 | registerPlugin<Breeze::Button>(QStringLiteral("button")); | 60 | registerPlugin<Breeze::Button>(QStringLiteral("button")); | ||
57 | registerPlugin<Breeze::ConfigWidget>(QStringLiteral("kcmodule")); | 61 | registerPlugin<Breeze::ConfigWidget>(QStringLiteral("kcmodule")); | ||
58 | ) | 62 | ) | ||
59 | 63 | | |||
64 | namespace | ||||
65 | { | ||||
66 | struct ShadowParams { | ||||
67 | ShadowParams() | ||||
68 | : offset(QPoint(0, 0)) | ||||
69 | , radius(0) | ||||
70 | , opacity(0) {} | ||||
71 | | ||||
72 | ShadowParams(const QPoint &offset, int radius, qreal opacity) | ||||
73 | : offset(offset) | ||||
74 | , radius(radius) | ||||
75 | , opacity(opacity) {} | ||||
76 | | ||||
77 | QPoint offset; | ||||
78 | int radius; | ||||
79 | qreal opacity; | ||||
80 | }; | ||||
81 | | ||||
82 | struct CompositeShadowParams { | ||||
83 | CompositeShadowParams() = default; | ||||
84 | | ||||
85 | CompositeShadowParams( | ||||
86 | const QPoint &offset, | ||||
87 | const ShadowParams &shadow1, | ||||
88 | const ShadowParams &shadow2) | ||||
89 | : offset(offset) | ||||
90 | , shadow1(shadow1) | ||||
91 | , shadow2(shadow2) {} | ||||
92 | | ||||
93 | bool isNone() const { | ||||
94 | return qMax(shadow1.radius, shadow2.radius) == 0; | ||||
95 | } | ||||
96 | | ||||
97 | QPoint offset; | ||||
98 | ShadowParams shadow1; | ||||
99 | ShadowParams shadow2; | ||||
100 | }; | ||||
101 | | ||||
102 | const CompositeShadowParams s_shadowParams[] = { | ||||
103 | // None | ||||
104 | CompositeShadowParams(), | ||||
105 | // Small | ||||
106 | CompositeShadowParams( | ||||
107 | QPoint(0, 6), | ||||
108 | ShadowParams(QPoint(0, 0), 16, 0.9), | ||||
109 | ShadowParams(QPoint(0, 0), 4, 0.1)), | ||||
110 | // Medium | ||||
111 | CompositeShadowParams( | ||||
112 | QPoint(0, 12), | ||||
113 | ShadowParams(QPoint(0, 0), 32, 0.94), | ||||
114 | ShadowParams(QPoint(0, 0), 16, 0.1)), | ||||
115 | // Large | ||||
116 | CompositeShadowParams( | ||||
117 | QPoint(0, 20), | ||||
118 | ShadowParams(QPoint(0, 0), 64, 1.0), | ||||
119 | ShadowParams(QPoint(0, 0), 24, 0.1)), | ||||
120 | // Very large | ||||
121 | CompositeShadowParams( | ||||
122 | QPoint(0, 34), | ||||
123 | ShadowParams(QPoint(0, 0), 96, 1.0), | ||||
124 | ShadowParams(QPoint(0, 0), 28, 0.1)) | ||||
125 | }; | ||||
126 | | ||||
127 | inline CompositeShadowParams lookupShadowParams(int size) | ||||
128 | { | ||||
129 | switch (size) { | ||||
130 | case Breeze::InternalSettings::ShadowNone: | ||||
131 | return s_shadowParams[0]; | ||||
132 | case Breeze::InternalSettings::ShadowSmall: | ||||
133 | return s_shadowParams[1]; | ||||
134 | case Breeze::InternalSettings::ShadowMedium: | ||||
135 | return s_shadowParams[2]; | ||||
136 | case Breeze::InternalSettings::ShadowLarge: | ||||
137 | return s_shadowParams[3]; | ||||
138 | case Breeze::InternalSettings::ShadowVeryLarge: | ||||
139 | return s_shadowParams[4]; | ||||
140 | default: | ||||
141 | // Fallback to the Large size. | ||||
142 | return s_shadowParams[3]; | ||||
143 | } | ||||
144 | } | ||||
145 | } | ||||
146 | | ||||
60 | namespace Breeze | 147 | namespace Breeze | ||
61 | { | 148 | { | ||
62 | 149 | | |||
63 | using KDecoration2::ColorRole; | 150 | using KDecoration2::ColorRole; | ||
64 | using KDecoration2::ColorGroup; | 151 | using KDecoration2::ColorGroup; | ||
65 | 152 | | |||
66 | //________________________________________________________________ | 153 | //________________________________________________________________ | ||
67 | static int g_sDecoCount = 0; | 154 | static int g_sDecoCount = 0; | ||
68 | static int g_shadowSizeEnum = InternalSettings::ShadowLarge; | 155 | static int g_shadowSizeEnum = InternalSettings::ShadowLarge; | ||
69 | static int g_shadowStrength = 90; | 156 | static int g_shadowStrength = 255; | ||
70 | static QColor g_shadowColor = Qt::black; | 157 | static QColor g_shadowColor = Qt::black; | ||
71 | static QSharedPointer<KDecoration2::DecorationShadow> g_sShadow; | 158 | static QSharedPointer<KDecoration2::DecorationShadow> g_sShadow; | ||
72 | 159 | | |||
73 | //________________________________________________________________ | 160 | //________________________________________________________________ | ||
74 | Decoration::Decoration(QObject *parent, const QVariantList &args) | 161 | Decoration::Decoration(QObject *parent, const QVariantList &args) | ||
75 | : KDecoration2::Decoration(parent, args) | 162 | : KDecoration2::Decoration(parent, args) | ||
76 | , m_animation( new QPropertyAnimation( this ) ) | 163 | , m_animation( new QPropertyAnimation( this ) ) | ||
77 | { | 164 | { | ||
▲ Show 20 Lines • Show All 539 Lines • ▼ Show 20 Line(s) | 657 | { | |||
617 | 704 | | |||
618 | } | 705 | } | ||
619 | 706 | | |||
620 | } | 707 | } | ||
621 | 708 | | |||
622 | //________________________________________________________________ | 709 | //________________________________________________________________ | ||
623 | void Decoration::createShadow() | 710 | void Decoration::createShadow() | ||
624 | { | 711 | { | ||
625 | 712 | if (!g_sShadow | |||
626 | // assign global shadow if exists and parameters match | 713 | ||g_shadowSizeEnum != m_internalSettings->shadowSize() | ||
627 | if( | 714 | || g_shadowStrength != m_internalSettings->shadowStrength() | ||
628 | !g_sShadow || | 715 | || g_shadowColor != m_internalSettings->shadowColor()) | ||
629 | g_shadowSizeEnum != m_internalSettings->shadowSize() || | | |||
630 | g_shadowStrength != m_internalSettings->shadowStrength() || | | |||
631 | g_shadowColor != m_internalSettings->shadowColor() | | |||
632 | ) | | |||
633 | { | 716 | { | ||
634 | // assign parameters | | |||
635 | g_shadowSizeEnum = m_internalSettings->shadowSize(); | 717 | g_shadowSizeEnum = m_internalSettings->shadowSize(); | ||
636 | g_shadowStrength = m_internalSettings->shadowStrength(); | 718 | g_shadowStrength = m_internalSettings->shadowStrength(); | ||
637 | g_shadowColor = m_internalSettings->shadowColor(); | 719 | g_shadowColor = m_internalSettings->shadowColor(); | ||
638 | 720 | | |||
639 | // shadow size from enum | 721 | const CompositeShadowParams params = lookupShadowParams(g_shadowSizeEnum); | ||
640 | int shadowSize = 0; | 722 | if (params.isNone()) { | ||
641 | switch( g_shadowSizeEnum ) | 723 | g_sShadow.clear(); | ||
642 | { | 724 | setShadow(g_sShadow); | ||
643 | default: | 725 | return; | ||
644 | case InternalSettings::ShadowLarge: shadowSize = 64; break; | | |||
645 | | ||||
646 | case InternalSettings::ShadowNone: shadowSize = Metrics::Shadow_Overlap + 1; break; | | |||
647 | case InternalSettings::ShadowSmall: shadowSize = 16; break; | | |||
648 | case InternalSettings::ShadowMedium: shadowSize = 32; break; | | |||
649 | case InternalSettings::ShadowVeryLarge: shadowSize = 96; break; | | |||
650 | } | 726 | } | ||
651 | 727 | | |||
652 | // offset | 728 | auto withOpacity = [](const QColor &color, qreal opacity) -> QColor { | ||
653 | int shadowOffset = (g_shadowSizeEnum == InternalSettings::ShadowNone) ? 0 : qMax( 6*shadowSize/16, Metrics::Shadow_Overlap*2 ); | 729 | QColor c(color); | ||
654 | 730 | c.setAlphaF(opacity); | |||
655 | // create image | 731 | return c; | ||
656 | QImage image(2*shadowSize, 2*shadowSize, QImage::Format_ARGB32_Premultiplied); | | |||
657 | image.fill(Qt::transparent); | | |||
658 | | ||||
659 | // painter | | |||
660 | QPainter painter(&image); | | |||
661 | painter.setRenderHint( QPainter::Antialiasing, true ); | | |||
662 | | ||||
663 | // color calculation delta function | | |||
664 | auto gradientStopColor = [](QColor color, int alpha) | | |||
665 | { | | |||
666 | color.setAlpha(alpha); | | |||
667 | return color; | | |||
668 | }; | 732 | }; | ||
669 | 733 | | |||
670 | // create gradient | 734 | // In order to properly render a box shadow with a given radius `shadowSize`, | ||
671 | if( g_shadowSizeEnum != InternalSettings::ShadowNone ) | 735 | // the box size should be at least `2 * QSize(shadowSize, shadowSize)`. | ||
672 | { | 736 | const int shadowSize = qMax(params.shadow1.radius, params.shadow2.radius); | ||
673 | 737 | const QRect box(shadowSize, shadowSize, 2 * shadowSize + 1, 2 * shadowSize + 1); | |||
674 | // gaussian lambda function | 738 | const QRect rect = box.adjusted(-shadowSize, -shadowSize, shadowSize, shadowSize); | ||
675 | auto alpha = [](qreal x) { return std::exp( -x*x/0.15 ); }; | 739 | | ||
676 | 740 | QImage shadow(rect.size(), QImage::Format_ARGB32_Premultiplied); | |||
677 | QRadialGradient radialGradient( shadowSize, shadowSize, shadowSize ); | 741 | shadow.fill(Qt::transparent); | ||
678 | for( int i = 0; i < 10; ++i ) | 742 | | ||
679 | { | 743 | QPainter painter(&shadow); | ||
680 | const qreal x( qreal( i )/9 ); | 744 | painter.setRenderHint(QPainter::Antialiasing); | ||
681 | radialGradient.setColorAt(x, gradientStopColor( g_shadowColor, alpha(x)*g_shadowStrength ) ); | 745 | | ||
682 | } | 746 | const qreal strength = static_cast<qreal>(g_shadowStrength) / 255.0; | ||
683 | 747 | | |||
684 | radialGradient.setColorAt(1, gradientStopColor( g_shadowColor, 0 ) ); | 748 | // Draw the "shape" shadow. | ||
685 | 749 | BoxShadowHelper::boxShadow( | |||
686 | // fill | 750 | &painter, | ||
687 | painter.fillRect( image.rect(), radialGradient); | 751 | box, | ||
752 | params.shadow1.offset, | ||||
753 | params.shadow1.radius, | ||||
754 | withOpacity(g_shadowColor, params.shadow1.opacity * strength)); | ||||
755 | | ||||
756 | // Draw the "contrast" shadow. | ||||
757 | BoxShadowHelper::boxShadow( | ||||
758 | &painter, | ||||
759 | box, | ||||
760 | params.shadow2.offset, | ||||
761 | params.shadow2.radius, | ||||
762 | withOpacity(g_shadowColor, params.shadow2.opacity * strength)); | ||||
763 | | ||||
764 | // Mask out inner rect. | ||||
765 | const QMargins padding = QMargins( | ||||
766 | shadowSize - Metrics::Shadow_Overlap - params.offset.x(), | ||||
767 | shadowSize - Metrics::Shadow_Overlap - params.offset.y(), | ||||
768 | shadowSize - Metrics::Shadow_Overlap + params.offset.x(), | ||||
769 | shadowSize - Metrics::Shadow_Overlap + params.offset.y()); | ||||
770 | const QRect innerRect = rect - padding; | ||||
688 | 771 | | |||
689 | } | | |||
690 | | ||||
691 | // contrast pixel | | |||
692 | QRectF innerRect = QRectF( | | |||
693 | shadowSize - Metrics::Shadow_Overlap, shadowSize - shadowOffset - Metrics::Shadow_Overlap, | | |||
694 | 2*Metrics::Shadow_Overlap, shadowOffset + 2*Metrics::Shadow_Overlap ); | | |||
695 | | ||||
696 | painter.setPen( gradientStopColor( g_shadowColor, (g_shadowSizeEnum == InternalSettings::ShadowNone) ? g_shadowStrength:(g_shadowStrength*0.5) ) ); | | |||
697 | painter.setBrush( Qt::NoBrush ); | | |||
698 | painter.drawRoundedRect( innerRect, -0.5 + Metrics::Frame_FrameRadius, -0.5 + Metrics::Frame_FrameRadius ); | | |||
699 | | ||||
700 | // mask out inner rect | | |||
701 | painter.setPen( Qt::NoPen ); | 772 | painter.setPen(Qt::NoPen); | ||
702 | painter.setBrush( Qt::black ); | 773 | painter.setBrush(Qt::black); | ||
703 | painter.setCompositionMode(QPainter::CompositionMode_DestinationOut ); | 774 | painter.setCompositionMode(QPainter::CompositionMode_DestinationOut); | ||
704 | painter.drawRoundedRect( innerRect, 0.5 + Metrics::Frame_FrameRadius, 0.5 + Metrics::Frame_FrameRadius ); | 775 | painter.drawRoundedRect( | ||
776 | innerRect, | ||||
777 | Metrics::Frame_FrameRadius + 0.5, | ||||
778 | Metrics::Frame_FrameRadius + 0.5); | ||||
779 | | ||||
780 | // Draw outline. | ||||
781 | painter.setPen(withOpacity(g_shadowColor, 0.2 * strength)); | ||||
782 | painter.setBrush(Qt::NoBrush); | ||||
783 | painter.setCompositionMode(QPainter::CompositionMode_SourceOver); | ||||
784 | painter.drawRoundedRect( | ||||
785 | innerRect, | ||||
786 | Metrics::Frame_FrameRadius - 0.5, | ||||
787 | Metrics::Frame_FrameRadius - 0.5); | ||||
705 | 788 | | |||
706 | painter.end(); | 789 | painter.end(); | ||
707 | 790 | | |||
708 | g_sShadow = QSharedPointer<KDecoration2::DecorationShadow>::create(); | 791 | g_sShadow = QSharedPointer<KDecoration2::DecorationShadow>::create(); | ||
709 | g_sShadow->setPadding( QMargins( | 792 | g_sShadow->setPadding(padding); | ||
710 | shadowSize - Metrics::Shadow_Overlap, | 793 | g_sShadow->setInnerShadowRect(QRect(shadow.rect().center(), QSize(1, 1))); | ||
711 | shadowSize - shadowOffset - Metrics::Shadow_Overlap, | 794 | g_sShadow->setShadow(shadow); | ||
712 | shadowSize - Metrics::Shadow_Overlap, | | |||
713 | shadowSize - Metrics::Shadow_Overlap ) ); | | |||
714 | | ||||
715 | g_sShadow->setInnerShadowRect(QRect( shadowSize, shadowSize, 1, 1) ); | | |||
716 | | ||||
717 | // assign image | | |||
718 | g_sShadow->setShadow(image); | | |||
719 | | ||||
720 | } | 795 | } | ||
721 | 796 | | |||
722 | setShadow(g_sShadow); | 797 | setShadow(g_sShadow); | ||
723 | | ||||
724 | } | 798 | } | ||
725 | 799 | | |||
726 | //_________________________________________________________________ | 800 | //_________________________________________________________________ | ||
727 | void Decoration::createSizeGrip() | 801 | void Decoration::createSizeGrip() | ||
728 | { | 802 | { | ||
729 | 803 | | |||
730 | // do nothing if size grip already exist | 804 | // do nothing if size grip already exist | ||
731 | if( m_sizeGrip ) return; | 805 | if( m_sizeGrip ) return; | ||
Show All 33 Lines |