File indexing completed on 2024-05-05 05:35:25

0001 #ifndef oxygenframeshadow_h
0002 #define oxygenframeshadow_h
0003 
0004 //////////////////////////////////////////////////////////////////////////////
0005 // oxygenframeshadow.h
0006 // handle frames' shadows and rounded corners
0007 // -------------------
0008 //
0009 // SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0010 //
0011 // Largely inspired from skulpture widget style
0012 // SPDX-FileCopyrightText: 2007-2009 Christoph Feck <christoph@maxiom.de>
0013 //
0014 // SPDX-License-Identifier: MIT
0015 //////////////////////////////////////////////////////////////////////////////
0016 
0017 #include "oxygenaddeventfilter.h"
0018 #include "oxygenstylehelper.h"
0019 
0020 #include <QEvent>
0021 #include <QObject>
0022 #include <QSet>
0023 
0024 #include <KColorScheme>
0025 #include <QPaintEvent>
0026 #include <QWidget>
0027 
0028 namespace Oxygen
0029 {
0030 //* shadow manager
0031 class FrameShadowFactory : public QObject
0032 {
0033     Q_OBJECT
0034 
0035 public:
0036     //* constructor
0037     explicit FrameShadowFactory(QObject *parent)
0038         : QObject(parent)
0039     {
0040     }
0041 
0042     //* register widget
0043     bool registerWidget(QWidget *, StyleHelper &);
0044 
0045     //* unregister
0046     void unregisterWidget(QWidget *);
0047 
0048     //* true if widget is registered
0049     bool isRegistered(const QWidget *widget) const
0050     {
0051         return _registeredWidgets.contains(widget);
0052     }
0053 
0054     //* event filter
0055     bool eventFilter(QObject *, QEvent *) override;
0056 
0057     //* set contrast
0058     void setHasContrast(const QWidget *widget, bool) const;
0059 
0060     //* update state
0061     void updateState(const QWidget *, bool focus, bool hover, qreal opacity, AnimationMode) const;
0062 
0063     //* update shadows geometry
0064     void updateShadowsGeometry(const QObject *, QRect) const;
0065 
0066 private Q_SLOTS:
0067 
0068     //* triggered by object destruction
0069     void widgetDestroyed(QObject *);
0070 
0071 private:
0072     //* install shadows on given widget
0073     void installShadows(QWidget *, StyleHelper &, bool flat = false);
0074 
0075     //* update shadows geometry
0076     void updateShadowsGeometry(QObject *) const;
0077 
0078     //* remove shadows from widget
0079     void removeShadows(QWidget *);
0080 
0081     //* raise shadows
0082     void raiseShadows(QObject *) const;
0083 
0084     //* update shadows
0085     void update(QObject *) const;
0086 
0087     //* install shadow on given side
0088     void installShadow(QWidget *, StyleHelper &, ShadowArea, bool flat = false) const;
0089 
0090     //* needed to block ChildAdded events when creating shadows
0091     AddEventFilter _addEventFilter;
0092 
0093     //* set of registered widgets
0094     QSet<const QObject *> _registeredWidgets;
0095 };
0096 
0097 //* frame shadow
0098 /** this allows the shadow to be painted over the widgets viewport */
0099 class FrameShadowBase : public QWidget
0100 {
0101     Q_OBJECT
0102 
0103 public:
0104     //* constructor
0105     explicit FrameShadowBase(ShadowArea area)
0106         : _area(area)
0107     {
0108     }
0109 
0110     //* shadow area
0111     void setShadowArea(ShadowArea area)
0112     {
0113         _area = area;
0114     }
0115 
0116     //* shadow area
0117     const ShadowArea &shadowArea() const
0118     {
0119         return _area;
0120     }
0121 
0122     //* set contrast
0123     void setHasContrast(bool value)
0124     {
0125         if (_contrast == value)
0126             return;
0127         _contrast = value;
0128     }
0129 
0130     //* true if contrast pixel is enabled
0131     bool hasContrast(void) const
0132     {
0133         return _contrast;
0134     }
0135 
0136     //* update geometry
0137     virtual void updateGeometry(void) = 0;
0138 
0139     //* update geometry
0140     virtual void updateGeometry(QRect) = 0;
0141 
0142     //* update state
0143     virtual void updateState(bool, bool, qreal, AnimationMode)
0144     {
0145     }
0146 
0147 protected:
0148     //* initialization
0149     virtual void init();
0150 
0151     //* return viewport associated to parent widget
0152     virtual QWidget *viewport(void) const;
0153 
0154     //* parent margins
0155     /** offsets between update rect and parent widget rect. It is set via updateGeometry */
0156     const QMargins &margins(void) const
0157     {
0158         return _margins;
0159     }
0160 
0161     //* margins
0162     /** offsets between update rect and parent widget rect. It is set via updateGeometry */
0163     void setMargins(const QMargins &margins)
0164     {
0165         _margins = margins;
0166     }
0167 
0168 private:
0169     //* shadow area
0170     ShadowArea _area;
0171 
0172     //* margins
0173     /** offsets between update rect and parent widget rect. It is set via updateGeometry */
0174     QMargins _margins;
0175 
0176     //* contrast pixel
0177     bool _contrast = false;
0178 };
0179 
0180 //* frame shadow
0181 /** this allows the shadow to be painted over the widgets viewport */
0182 class SunkenFrameShadow : public FrameShadowBase
0183 {
0184     Q_OBJECT
0185 
0186 public:
0187     //* constructor
0188     SunkenFrameShadow(ShadowArea area, StyleHelper &helper)
0189         : FrameShadowBase(area)
0190         , _helper(helper)
0191     {
0192         init();
0193     }
0194 
0195     //* update geometry
0196     /** nothing is done. Rect must be passed explicitly */
0197     void updateGeometry(void) override
0198     {
0199     }
0200 
0201     //* update geometry
0202     void updateGeometry(QRect) override;
0203 
0204     //* update state
0205     void updateState(bool focus, bool hover, qreal opacity, AnimationMode) override;
0206 
0207 protected:
0208     //* painting
0209     void paintEvent(QPaintEvent *) override;
0210 
0211 private:
0212     //* helper
0213     StyleHelper &_helper;
0214 
0215     //*@name widget state
0216     //@{
0217     bool _hasFocus = false;
0218     bool _mouseOver = false;
0219     qreal _opacity = -1;
0220     AnimationMode _mode = AnimationNone;
0221 };
0222 
0223 //* frame shadow
0224 /** this allows the shadow to be painted over the widgets viewport */
0225 class FlatFrameShadow : public FrameShadowBase
0226 {
0227     Q_OBJECT
0228 
0229 public:
0230     //* constructor
0231     FlatFrameShadow(ShadowArea area, StyleHelper &helper)
0232         : FrameShadowBase(area)
0233         , _helper(helper)
0234     {
0235         init();
0236     }
0237 
0238     //* update geometry
0239     void updateGeometry(void) override;
0240 
0241     //* update geometry
0242     void updateGeometry(QRect) override;
0243 
0244 protected:
0245     //* painting
0246     void paintEvent(QPaintEvent *) override;
0247 
0248 private:
0249     //* helper
0250     StyleHelper &_helper;
0251 };
0252 }
0253 
0254 #endif