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

0001 #ifndef oxygen_style_helper_h
0002 #define oxygen_style_helper_h
0003 
0004 /*
0005  * SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0006  * SPDX-FileCopyrightText: 2008 Long Huynh Huu <long.upcase@googlemail.com>
0007  * SPDX-FileCopyrightText: 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
0008  * SPDX-FileCopyrightText: 2007 Casper Boemann <cbr@boemann.dk>
0009  *
0010  * SPDX-License-Identifier: LGPL-2.0-only
0011  */
0012 
0013 #include "oxygen.h"
0014 #include "oxygenhelper.h"
0015 
0016 #include <KWindowSystem>
0017 
0018 #if OXYGEN_HAVE_X11
0019 #include <xcb/xcb.h>
0020 #endif
0021 
0022 //* helper class
0023 /** contains utility functions used at multiple places in oxygen style */
0024 namespace Oxygen
0025 {
0026 class StyleHelper : public Helper
0027 {
0028 public:
0029     //* constructor
0030     explicit StyleHelper(KSharedConfigPtr config);
0031 
0032     //* destructor
0033     //* clear cache
0034     void invalidateCaches() override;
0035 
0036     //* update maximum cache size
0037     void setMaxCacheSize(int) override;
0038 
0039     //* background gradient
0040     void setUseBackgroundGradient(bool value)
0041     {
0042         _useBackgroundGradient = value;
0043     }
0044 
0045     //* render window background using a given color as a reference
0046     /**
0047     For the widget style, both the gradient and the background pixmap are rendered in the same method.
0048     All the actual rendering is performed by the base class
0049     */
0050     using Helper::renderWindowBackground;
0051     void renderWindowBackground(QPainter *, const QRect &, const QWidget *, const QColor &, int y_shift = -23) override;
0052 
0053     //* set background gradient hint to widget
0054     void setHasBackgroundGradient(WId, bool) const override;
0055 
0056     // render menu background
0057     void renderMenuBackground(QPainter *p, const QRect &clipRect, const QWidget *widget, const QPalette &pal)
0058     {
0059         renderMenuBackground(p, clipRect, widget, pal.color(widget->window()->backgroundRole()));
0060     }
0061 
0062     // render menu background
0063     void renderMenuBackground(QPainter *, const QRect &, const QWidget *, const QColor &);
0064 
0065     //*@name color utilities
0066     //@{
0067 
0068     //* glow color for buttons (mouse-over takes precedence over focus)
0069     QColor buttonGlowColor(const QPalette &palette, StyleOptions options, qreal opacity, AnimationMode mode) const
0070     {
0071         return buttonGlowColor(palette.currentColorGroup(), options, opacity, mode);
0072     }
0073 
0074     //* glow color for frames (focus takes precedence over mouse-over)
0075     QColor frameGlowColor(const QPalette &palette, StyleOptions options, qreal opacity, AnimationMode mode) const
0076     {
0077         return frameGlowColor(palette.currentColorGroup(), options, opacity, mode);
0078     }
0079 
0080     //* glow color for arrows (mouse-over takes precedence over focus)
0081     QColor arrowColor(const QPalette &palette, StyleOptions options, qreal opacity, AnimationMode mode) const;
0082 
0083     //* glow color for buttons (mouse-over takes precedence over focus)
0084     QColor buttonGlowColor(QPalette::ColorGroup, StyleOptions, qreal, AnimationMode) const;
0085 
0086     //* glow color for frames (focus takes precedence over mouse-over)
0087     QColor frameGlowColor(QPalette::ColorGroup, StyleOptions, qreal, AnimationMode) const;
0088 
0089     //* returns menu background color matching position in a given menu widget
0090     QColor menuBackgroundColor(const QColor &color, const QWidget *w, const QPoint &point)
0091     {
0092         if (!(w && w->window()) || checkAutoFillBackground(w))
0093             return color;
0094         else
0095             return menuBackgroundColor(color, w->window()->height(), w->mapTo(w->window(), point).y());
0096     }
0097 
0098     //* returns menu background color matching position in a menu widget of given height
0099     QColor menuBackgroundColor(const QColor &color, int height, int y)
0100     {
0101         return backgroundColor(color, qMin(qreal(1.0), qreal(y) / qMin(200, 3 * height / 4)));
0102     }
0103 
0104     //* color
0105     inline QColor calcMidColor(const QColor &color);
0106 
0107     //* merge active and inactive palettes based on ratio, for smooth enable state change transition
0108     QPalette disabledPalette(const QPalette &, qreal ratio) const;
0109 
0110     //@}
0111 
0112     //* overloaded window decoration buttons for MDI windows
0113     QPixmap dockWidgetButton(const QColor &color, bool pressed, int size = 21);
0114 
0115     //* round corners( used for Menus, combobox drop-down, detached toolbars and dockwidgets
0116     TileSet roundCorner(const QColor &, int size = 5);
0117 
0118     //* groupbox background
0119     TileSet slope(const QColor &, qreal shade, int size = TileSet::DefaultSize);
0120 
0121     //*@name slabs
0122     //@{
0123 
0124     //* inverse (inner-hole) shadow
0125     /** this method must be public because it is used directly by OxygenStyle to draw dials */
0126     void drawInverseShadow(QPainter &, const QColor &, int pad, int size, qreal fuzz) const;
0127 
0128     //* fill a slab of given size with brush set on painter
0129     void fillSlab(QPainter &, const QRect &, int size = TileSet::DefaultSize) const;
0130 
0131     //* linear gradient used to fill buttons
0132     void fillButtonSlab(QPainter &, const QRect &, const QColor &, bool sunken);
0133 
0134     //* default slab
0135     TileSet slab(const QColor &color, qreal shade, int size = TileSet::DefaultSize)
0136     {
0137         return slab(color, QColor(), shade, size);
0138     }
0139 
0140     //* default slab (with glow)
0141     TileSet slab(const QColor &, const QColor &glow, qreal shade, int size = TileSet::DefaultSize);
0142 
0143     //* sunken slab
0144     TileSet slabSunken(const QColor &, int size = TileSet::DefaultSize);
0145 
0146     //* progressbar
0147     TileSet progressBarIndicator(const QPalette &, int);
0148 
0149     //* dial
0150     QPixmap dialSlab(const QColor &color, qreal shade, int size = TileSet::DefaultSize)
0151     {
0152         return dialSlab(color, QColor(), shade, size);
0153     }
0154 
0155     //* dial
0156     QPixmap dialSlab(const QColor &, const QColor &, qreal shade, int size = TileSet::DefaultSize);
0157 
0158     // round slabs
0159     QPixmap roundSlab(const QColor &color, qreal shade, int size = TileSet::DefaultSize)
0160     {
0161         return roundSlab(color, QColor(), shade, size);
0162     }
0163 
0164     // round slab
0165     QPixmap roundSlab(const QColor &, const QColor &glow, qreal shade, int size = TileSet::DefaultSize);
0166 
0167     //* slider slab
0168     QPixmap sliderSlab(const QColor &, const QColor &glow, bool sunken, qreal shade, int size = TileSet::DefaultSize);
0169 
0170     //@}
0171 
0172     //* debug frame
0173     void renderDebugFrame(QPainter *, const QRect &) const;
0174 
0175     //*@name holes
0176     //@{
0177 
0178     void fillHole(QPainter &, const QRect &, int offset = 2) const;
0179 
0180     //* generic hole
0181     void renderHole(QPainter *painter, const QColor &color, const QRect &rect, StyleOptions options = {}, TileSet::Tiles tiles = TileSet::Ring)
0182     {
0183         renderHole(painter, color, rect, options, -1, Oxygen::AnimationNone, tiles);
0184     }
0185 
0186     //* generic hole (with animated glow)
0187     void renderHole(QPainter *, const QColor &, const QRect &, StyleOptions, qreal, Oxygen::AnimationMode, TileSet::Tiles = TileSet::Ring);
0188 
0189     TileSet holeFlat(const QColor &, qreal shade, bool fill = true, int size = TileSet::DefaultSize);
0190 
0191     //* scrollbar hole
0192     TileSet scrollHole(const QColor &, Qt::Orientation orientation, bool smallShadow = false);
0193 
0194     //* scrollbar handle
0195     TileSet scrollHandle(const QColor &, const QColor &, int size = TileSet::DefaultSize);
0196 
0197     //@}
0198 
0199     //* focus rect for flat toolbuttons
0200     TileSet slitFocused(const QColor &);
0201 
0202     //* dock frame
0203     TileSet dockFrame(const QColor &, const QColor &);
0204 
0205     //* selection
0206     TileSet selection(const QColor &, int height, bool custom);
0207 
0208     //* inverse glow
0209     /** this method must be public because it is used directly by OxygenStyle to draw dials */
0210     void drawInverseGlow(QPainter &, const QColor &, int pad, int size, int rsize) const;
0211 
0212     //*@name utility functions
0213 
0214     //* returns true if compositing is active
0215     bool compositingActive(void) const;
0216 
0217     //* returns true if a given widget supports alpha channel
0218     inline bool hasAlphaChannel(const QWidget *) const;
0219 
0220     //* returns true if given widget will get a decoration
0221     bool hasDecoration(const QWidget *) const;
0222 
0223     //@}
0224 
0225 private:
0226     //*@name holes
0227     //@{
0228 
0229     //* holes
0230     TileSet hole(const QColor &color, int size = TileSet::DefaultSize, StyleOptions options = {})
0231     {
0232         return hole(color, QColor(), size, options);
0233     }
0234 
0235     //* holes
0236     TileSet hole(const QColor &, const QColor &glow, int size = TileSet::DefaultSize, StyleOptions = {});
0237 
0238     //@}
0239 
0240     //* generic slab painting (to be stored in tilesets)
0241     void drawSlab(QPainter &, const QColor &, qreal shade);
0242 
0243     // round slabs
0244     void drawRoundSlab(QPainter &, const QColor &, qreal);
0245 
0246     // slider slabs
0247     void drawSliderSlab(QPainter &, const QColor &, bool sunken, qreal);
0248 
0249     //* initialize
0250     void init(void);
0251 
0252     //* background grandient
0253     bool _useBackgroundGradient;
0254 
0255     Cache<QPixmap> _dialSlabCache;
0256     Cache<QPixmap> _roundSlabCache;
0257     Cache<QPixmap> _sliderSlabCache;
0258     Cache<TileSet> _holeCache;
0259     Cache<TileSet> _scrollHandleCache;
0260     Cache<TileSet> _slabCache;
0261 
0262     //* mid color cache
0263     ColorCache _midColorCache;
0264 
0265     //* dock button cache
0266     PixmapCache _dockWidgetButtonCache;
0267 
0268     using TileSetCache = BaseCache<TileSet>;
0269     TileSetCache _slabSunkenCache;
0270     TileSetCache _cornerCache;
0271     TileSetCache _holeFlatCache;
0272     TileSetCache _slopeCache;
0273     TileSetCache _slitCache;
0274     TileSetCache _dockFrameCache;
0275     TileSetCache _scrollHoleCache;
0276     TileSetCache _selectionCache;
0277     TileSetCache _progressBarCache;
0278 
0279 #if OXYGEN_HAVE_X11
0280 
0281     //* atom used for compositing manager
0282     xcb_atom_t _compositingManagerAtom;
0283 
0284 #endif
0285 };
0286 
0287 //____________________________________________________________________
0288 QColor StyleHelper::calcMidColor(const QColor &color)
0289 {
0290     const quint64 key(color.rgba());
0291     if (QColor *cachedColor = _midColorCache.object(key)) {
0292         return *cachedColor;
0293     }
0294 
0295     QColor out = KColorScheme::shade(color, KColorScheme::MidShade, _contrast - 1.0);
0296     _midColorCache.insert(key, new QColor(out));
0297 
0298     return out;
0299 }
0300 
0301 //____________________________________________________________________
0302 bool StyleHelper::hasAlphaChannel(const QWidget *widget) const
0303 {
0304     return compositingActive() && widget && widget->testAttribute(Qt::WA_TranslucentBackground);
0305 }
0306 }
0307 #endif