File indexing completed on 2024-05-19 09:27:57

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