1 | #ifndef oxygen_helper_h |
2 | #define oxygen_helper_h |
3 | |
4 | /* |
5 | * Copyright 2009-2010 Hugo Pereira Da Costa <hugo.pereira@free.fr> |
6 | * Copyright 2008 Long Huynh Huu <long.upcase@googlemail.com> |
7 | * Copyright 2007 Matthew Woehlke <mw_triad@users.sourceforge.net> |
8 | * Copyright 2007 Casper Boemann <cbr@boemann.dk> |
9 | * Copyright 2007 Fredrik Höglund <fredrik@kde.org> |
10 | * |
11 | * This library is free software; you can redistribute it and/or |
12 | * modify it under the terms of the GNU Library General Public |
13 | * License version 2 as published by the Free Software Foundation. |
14 | * |
15 | * This library is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | * Library General Public License for more details. |
19 | * |
20 | * You should have received a copy of the GNU Library General Public License |
21 | * along with this library; see the file COPYING.LIB. If not, write to |
22 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
23 | * Boston, MA 02110-1301, USA. |
24 | */ |
25 | |
26 | #include "oxygentileset.h" |
27 | |
28 | #include <KSharedConfig> |
29 | #include <KComponentData> |
30 | #include <KColorScheme> |
31 | |
32 | #include <QtGui/QColor> |
33 | #include <QtGui/QPixmap> |
34 | #include <QtGui/QWidget> |
35 | #include <QtGui/QLinearGradient> |
36 | #include <QtCore/QCache> |
37 | |
38 | #ifdef Q_WS_X11 |
39 | #include <X11/Xdefs.h> |
40 | #endif |
41 | |
42 | namespace Oxygen |
43 | { |
44 | |
45 | template<typename T> class BaseCache: public QCache<quint64, T> |
46 | { |
47 | |
48 | public: |
49 | |
50 | //! constructor |
51 | BaseCache( int maxCost ): |
52 | QCache<quint64, T>( maxCost ), |
53 | _enabled( true ) |
54 | {} |
55 | |
56 | //! constructor |
57 | explicit BaseCache( void ): |
58 | _enabled( true ) |
59 | {} |
60 | |
61 | //! destructor |
62 | ~BaseCache( void ) |
63 | {} |
64 | |
65 | //! enable |
66 | void setEnabled( bool value ) |
67 | { _enabled = value; } |
68 | |
69 | //! enable state |
70 | bool enabled( void ) const |
71 | { return _enabled; } |
72 | |
73 | //! access |
74 | T* object( const quint64& key ) |
75 | { return _enabled ? QCache<quint64, T>::object( key ) : 0; } |
76 | |
77 | //! max cost |
78 | void setMaxCost( int cost ) |
79 | { |
80 | if( cost <= 0 ) { |
81 | |
82 | QCache<quint64, T>::clear(); |
83 | QCache<quint64, T>::setMaxCost( 1 ); |
84 | setEnabled( false ); |
85 | |
86 | } else { |
87 | |
88 | setEnabled( true ); |
89 | QCache<quint64, T>::setMaxCost( cost ); |
90 | |
91 | } |
92 | } |
93 | |
94 | private: |
95 | |
96 | //! enable flag |
97 | bool _enabled; |
98 | |
99 | }; |
100 | |
101 | template<typename T> class Cache |
102 | { |
103 | |
104 | public: |
105 | |
106 | //! constructor |
107 | Cache() |
108 | {} |
109 | |
110 | //! destructor |
111 | ~Cache() |
112 | {} |
113 | |
114 | //! return cache matching a given key |
115 | //typedef QCache<quint64, T> Value; |
116 | typedef BaseCache<T> Value; |
117 | Value* get( const QColor& color ) |
118 | { |
119 | const quint64 key = ( color.isValid() ? color.rgba():0 ); |
120 | Value* cache = data_.object( key ); |
121 | |
122 | if ( !cache ) |
123 | { |
124 | cache = new Value( data_.maxCost() ); |
125 | data_.insert( key, cache ); |
126 | } |
127 | |
128 | return cache; |
129 | } |
130 | |
131 | //! clear |
132 | void clear( void ) |
133 | { data_.clear(); } |
134 | |
135 | //! max cache size |
136 | void setMaxCacheSize( int value ) |
137 | { |
138 | data_.setMaxCost( value ); |
139 | foreach( quint64 key, data_.keys() ) |
140 | { data_.object( key )->setMaxCost( value ); } |
141 | } |
142 | |
143 | private: |
144 | |
145 | //! data |
146 | BaseCache<Value> data_; |
147 | |
148 | }; |
149 | |
150 | //! oxygen style helper class. |
151 | /*! contains utility functions used at multiple places in both oxygen style and oxygen window decoration */ |
152 | class OXYGEN_EXPORT Helper |
153 | { |
154 | public: |
155 | |
156 | //! constructor |
157 | explicit Helper( const QByteArray& componentName ); |
158 | |
159 | //! destructor |
160 | virtual ~Helper() |
161 | {} |
162 | |
163 | //! reload configuration |
164 | virtual void reloadConfig(); |
165 | |
166 | //! pointer to shared config |
167 | KSharedConfigPtr config() const; |
168 | |
169 | //! reset all caches |
170 | virtual void invalidateCaches(); |
171 | |
172 | //! update maximum cache size |
173 | virtual void setMaxCacheSize( int ); |
174 | |
175 | //!@name window background gradients |
176 | //@{ |
177 | /*! |
178 | \par y_shift: shift the background gradient upwards, to fit with the windec |
179 | \par gradientHeight: the height of the generated gradient. |
180 | for different heights, the gradient is translated so that it is always at the same position from the bottom |
181 | */ |
182 | virtual void renderWindowBackground( QPainter* p, const QRect& clipRect, const QWidget* widget, const QPalette& pal, int y_shift=-23, int gradientHeight = 20 ) |
183 | { renderWindowBackground( p, clipRect, widget, pal.color( widget->window()->backgroundRole() ), y_shift, gradientHeight ); } |
184 | |
185 | /*! |
186 | y_shift: shift the background gradient upwards, to fit with the windec |
187 | gradientHeight: the height of the generated gradient. |
188 | for different heights, the gradient is translated so that it is always at the same position from the bottom |
189 | */ |
190 | virtual void renderWindowBackground( QPainter* p, const QRect& clipRect, const QWidget* widget, const QWidget* window, const QPalette& pal, int y_shift=-23, int gradientHeight = 20 ) |
191 | { renderWindowBackground( p, clipRect, widget, window, pal.color( window->backgroundRole() ), y_shift, gradientHeight ); } |
192 | |
193 | //! render window background using a given color as a reference |
194 | virtual void renderWindowBackground( QPainter* p, const QRect& clipRect, const QWidget* widget, const QColor& color, int y_shift=-23, int gradientHeight = 20 ) |
195 | { renderWindowBackground( p, clipRect, widget, widget->window(), color, y_shift, gradientHeight ); } |
196 | |
197 | //! render window background using a given color as a reference |
198 | virtual void renderWindowBackground( QPainter* p, const QRect& clipRect, const QWidget* widget, const QWidget* window, const QColor& color, int y_shift=-23, int gradientHeight = 20 ); |
199 | |
200 | //! background pixmap |
201 | bool hasBackgroundPixmap( void ) const |
202 | { return !_backgroundPixmap.isNull(); } |
203 | |
204 | //! background pixmap |
205 | void setBackgroundPixmap( const QPixmap& pixmap ) |
206 | { _backgroundPixmap = pixmap; } |
207 | |
208 | //! offset |
209 | void setBackgroundPixmapOffset( const QPoint& offset ) |
210 | { _backgroundPixmapOffset = offset; } |
211 | |
212 | //! render window background using a given color as a reference |
213 | virtual void renderBackgroundPixmap( QPainter* p, const QRect& clipRect, const QWidget* widget, const QWidget* window, int y_shift=-23, int gradientHeight = 20 ); |
214 | |
215 | //@} |
216 | |
217 | //! dots |
218 | void renderDot( QPainter*, const QPoint&, const QColor& ); |
219 | |
220 | //! returns true for too 'dark' colors |
221 | bool lowThreshold( const QColor& color ); |
222 | |
223 | //! returns true for too 'light' colors |
224 | bool highThreshold( const QColor& color ); |
225 | |
226 | //! add alpha channel multiplier to color |
227 | static QColor alphaColor( QColor color, qreal alpha ); |
228 | |
229 | //! calculated light color from argument |
230 | virtual const QColor& calcLightColor( const QColor& color ); |
231 | |
232 | //! calculated dark color from argument |
233 | virtual const QColor& calcDarkColor( const QColor& color ); |
234 | |
235 | //! calculated shadow color from argument |
236 | virtual const QColor& calcShadowColor( const QColor& color ); |
237 | |
238 | //! returns menu background color matching position in a given top level widget |
239 | virtual const QColor& backgroundColor( const QColor& color, const QWidget* w, const QPoint& point ) |
240 | { |
241 | if( !( w && w->window() ) || checkAutoFillBackground( w ) ) return color; |
242 | else return backgroundColor( color, w->window()->height(), w->mapTo( w->window(), point ).y() ); |
243 | } |
244 | |
245 | //! returns menu background color matching position in a top level widget of given height |
246 | virtual const QColor& backgroundColor( const QColor& color, int height, int y ) |
247 | { return backgroundColor( color, qMin( qreal( 1.0 ), qreal( y )/qMin( 300, 3*height/4 ) ) ); } |
248 | |
249 | //! color used for background radial gradient |
250 | virtual const QColor& backgroundRadialColor( const QColor& color ); |
251 | |
252 | //! color used at the top of window background |
253 | virtual const QColor& backgroundTopColor( const QColor& color ); |
254 | |
255 | //! color used at the bottom of window background |
256 | virtual const QColor& backgroundBottomColor( const QColor& color ); |
257 | |
258 | //! vertical gradient for window background |
259 | virtual QPixmap verticalGradient( const QColor& color, int height, int offset = 0 ); |
260 | |
261 | //! radial gradient for window background |
262 | virtual QPixmap radialGradient( const QColor& color, int width, int height = 20 ); |
263 | |
264 | //! merge background and front color for check marks, arrows, etc. using _contrast |
265 | virtual const QColor& decoColor( const QColor& background, const QColor& color ); |
266 | |
267 | //! returns a region matching given rect, with rounded corners, based on the multipliers |
268 | /*! setting any of the multipliers to zero will result in no corners shown on the corresponding side */ |
269 | virtual QRegion roundedMask( const QRect&, int left = 1, int right = 1, int top = 1, int bottom = 1 ) const; |
270 | |
271 | //! draw frame that mimics some sort of shadows around a panel |
272 | /*! it is used for menus, detached dock panels and toolbar, as well as window decoration when compositing is disabled */ |
273 | virtual void drawFloatFrame( |
274 | QPainter* p, const QRect r, const QColor& color, |
275 | bool drawUglyShadow=true, bool isActive=false, |
276 | const QColor& frameColor=QColor(), |
277 | TileSet::Tiles tiles = TileSet::Ring |
278 | ); |
279 | |
280 | //! draw dividing line |
281 | virtual void drawSeparator( QPainter*, const QRect&, const QColor&, Qt::Orientation ); |
282 | |
283 | //! default slab |
284 | virtual TileSet* slab( const QColor& color, qreal shade, int size = 7 ) |
285 | { return slab( color, QColor(), shade, size ); } |
286 | |
287 | //! default slab (with glow) |
288 | virtual TileSet* slab( const QColor&, const QColor& glow, qreal shade, int size = 7 ); |
289 | |
290 | //! sunken slab |
291 | virtual TileSet *slabSunken( const QColor&, int size = 7 ); |
292 | |
293 | //! fill a slab of given size with brush set on painter |
294 | void fillSlab( QPainter&, const QRect&, int size = 7 ) const; |
295 | |
296 | //! linear gradient used to fill buttons |
297 | virtual void fillButtonSlab( QPainter&, const QRect&, const QColor&, bool sunken ); |
298 | |
299 | //! inverse (inner-hole) shadow |
300 | /*! this method must be public because it is used directly by OxygenStyle to draw dials */ |
301 | void drawInverseShadow( QPainter&, const QColor&, int pad, int size, qreal fuzz ) const; |
302 | |
303 | //! focus brush |
304 | const KStatefulBrush& viewFocusBrush( void ) const |
305 | { return _viewFocusBrush; } |
306 | |
307 | //! hover brush |
308 | const KStatefulBrush& viewHoverBrush( void ) const |
309 | { return _viewHoverBrush; } |
310 | |
311 | //! negative text brush ( used for close button hover ) |
312 | const KStatefulBrush& viewNegativeTextBrush( void ) const |
313 | { return _viewNegativeTextBrush; } |
314 | |
315 | /*! |
316 | returns first widget in parent chain that sets autoFillBackground to true, |
317 | or NULL if none |
318 | */ |
319 | const QWidget* checkAutoFillBackground( const QWidget* ) const; |
320 | |
321 | //!@name background gradient XProperty |
322 | //@{ |
323 | |
324 | //! set background gradient hint to widget |
325 | virtual void setHasBackgroundGradient( WId, bool ) const; |
326 | |
327 | //! true if background gradient hint is set |
328 | virtual bool hasBackgroundGradient( WId ) const; |
329 | |
330 | //! set background pixmap hint to widget |
331 | virtual void setHasBackgroundPixmap( WId, bool ) const; |
332 | |
333 | //! true if background pixmap hint is set |
334 | virtual bool hasBackgroundPixmap( WId ) const; |
335 | |
336 | //@} |
337 | |
338 | protected: |
339 | |
340 | //! return color key for a given color, properly accounting for invalid colors |
341 | quint64 colorKey( const QColor& color ) const |
342 | { return color.isValid() ? color.rgba():0; } |
343 | |
344 | //! generic slab painting (to be stored in tilesets) |
345 | virtual void drawSlab( QPainter&, const QColor&, qreal shade ); |
346 | |
347 | //! generic outer shadow (to be stored in tilesets) |
348 | virtual void drawShadow( QPainter&, const QColor&, int size ); |
349 | |
350 | //! generic outer glow (to be stored in tilesets) |
351 | virtual void drawOuterGlow( QPainter&, const QColor&, int size ); |
352 | |
353 | //! return background adjusted color matching relative vertical position in window |
354 | const QColor& backgroundColor( const QColor&, qreal ratio ); |
355 | |
356 | //!@name global configuration parameters |
357 | //@{ |
358 | |
359 | static const qreal _glowBias; |
360 | static const qreal _slabThickness; |
361 | static const qreal _shadowGain; |
362 | qreal _contrast; |
363 | |
364 | //@} |
365 | |
366 | //! shortcut to color caches |
367 | /*! it is made protected because it is also used in the style helper */ |
368 | typedef BaseCache<QColor> ColorCache; |
369 | |
370 | //! shortcut to pixmap cache |
371 | typedef BaseCache<QPixmap> PixmapCache; |
372 | |
373 | private: |
374 | |
375 | //!@name tileset caches |
376 | //!@{ |
377 | |
378 | //! slabs |
379 | Oxygen::Cache<TileSet> _slabCache; |
380 | |
381 | //! sunken slabs |
382 | BaseCache<TileSet> _slabSunkenCache; |
383 | |
384 | //@} |
385 | |
386 | //!@name brushes |
387 | //@{ |
388 | KStatefulBrush _viewFocusBrush; |
389 | KStatefulBrush _viewHoverBrush; |
390 | KStatefulBrush _viewNegativeTextBrush; |
391 | //@} |
392 | |
393 | KComponentData _componentData; |
394 | KSharedConfigPtr _config; |
395 | qreal _bgcontrast; |
396 | |
397 | //!@name color caches |
398 | //@{ |
399 | ColorCache _decoColorCache; |
400 | ColorCache _lightColorCache; |
401 | ColorCache _darkColorCache; |
402 | ColorCache _shadowColorCache; |
403 | ColorCache _backgroundTopColorCache; |
404 | ColorCache _backgroundBottomColorCache; |
405 | ColorCache _backgroundRadialColorCache; |
406 | ColorCache _backgroundColorCache; |
407 | //@} |
408 | |
409 | PixmapCache _backgroundCache; |
410 | PixmapCache _dotCache; |
411 | |
412 | //! high threshold colors |
413 | typedef QMap<quint32, bool> ColorMap; |
414 | ColorMap _highThreshold; |
415 | ColorMap _lowThreshold; |
416 | |
417 | //! background pixmap |
418 | QPixmap _backgroundPixmap; |
419 | |
420 | //! background pixmap offsets |
421 | QPoint _backgroundPixmapOffset; |
422 | |
423 | #ifdef Q_WS_X11 |
424 | |
425 | //! set value for given hint |
426 | void setHasHint( WId, Atom, bool ) const; |
427 | |
428 | //! value for given hint |
429 | bool hasHint( WId, Atom ) const; |
430 | |
431 | //! background gradient hint atom |
432 | Atom _backgroundGradientAtom; |
433 | |
434 | //! background gradient hint atom |
435 | Atom _backgroundPixmapAtom; |
436 | |
437 | #endif |
438 | }; |
439 | |
440 | } |
441 | |
442 | #endif |
443 | |