File indexing completed on 2024-05-19 09:28:04

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