Warning, file /plasma/oxygen-gtk/src/oxygenstylehelper.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 this file is part of the oxygen gtk engine 0003 SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "oxygenstylehelper.h" 0009 #include "oxygencairocontext.h" 0010 #include "oxygencairoutils.h" 0011 #include "oxygencolorutils.h" 0012 #include "oxygenrgba.h" 0013 0014 #include <cmath> 0015 #include <gdk/gdk.h> 0016 0017 namespace Oxygen 0018 { 0019 0020 //__________________________________________________________________ 0021 const double StyleHelper::_slabThickness = 0.45; 0022 const double StyleHelper::_shadowGain = 1.5; 0023 const double StyleHelper::_glowBias = 0.6; 0024 0025 //__________________________________________________________________ 0026 StyleHelper::StyleHelper( void ) 0027 { 0028 #if OXYGEN_DEBUG 0029 std::cerr << "Oxygen::StyleHelper::StyleHelper" << std::endl; 0030 #endif 0031 } 0032 0033 //__________________________________________________________________ 0034 StyleHelper::~StyleHelper( void ) 0035 { 0036 #if OXYGEN_DEBUG 0037 std::cerr << "Oxygen::StyleHelper::~StyleHelper" << std::endl; 0038 #endif 0039 } 0040 0041 //__________________________________________________________________ 0042 void StyleHelper::initializeRefSurface( void ) 0043 { 0044 0045 // make sure that surface is not already initialized 0046 if( _refSurface.isValid() ) return; 0047 0048 /* 0049 create dummy widget, check its associated screen; 0050 if found create surface for it and save as reference surface 0051 */ 0052 GdkScreen* screen( gdk_screen_get_default() ); 0053 GdkWindow* window( screen ? gdk_screen_get_root_window( screen ):0x0 ); 0054 if( screen && window ) 0055 { 0056 0057 #if OXYGEN_DEBUG 0058 std::cerr 0059 << "Oxygen::StyleHelper::initializeRefSurface - " 0060 << " screen: " << screen 0061 << " window: " << window 0062 << std::endl; 0063 #endif 0064 0065 Cairo::Context context( window ); 0066 _refSurface = Cairo::Surface( cairo_surface_create_similar( cairo_get_target( context ), CAIRO_CONTENT_ALPHA, 1, 1 ) ); 0067 0068 } else { 0069 0070 /* 0071 no screen found. 0072 Destroy widget (since gtk_widget_realize would otherwise crash) 0073 Fallback to ImageSurface 0074 */ 0075 #if OXYGEN_DEBUG 0076 std::cerr 0077 << "Oxygen::StyleHelper::initializeRefSurface - " 0078 << " No valid screen found to create X11 surface." 0079 << " Falling back to Cairo Image surface." 0080 << std::endl; 0081 #endif 0082 0083 _refSurface.set( cairo_image_surface_create( CAIRO_FORMAT_ARGB32, 1, 1 ) ); 0084 0085 } 0086 0087 } 0088 0089 //__________________________________________________________________ 0090 void StyleHelper::drawSeparator( Cairo::Context& context, const ColorUtils::Rgba& base, int x, int y, int w, int h, bool vertical ) 0091 { 0092 0093 // get surface 0094 const Cairo::Surface& surface( separator( base, vertical, vertical ? h:w ) ); 0095 if(!surface) return; 0096 0097 // translate 0098 cairo_save( context ); 0099 if( vertical ) { 0100 0101 cairo_translate( context, x+w/2-1, y ); 0102 cairo_rectangle( context, 0, 0, 3, h ); 0103 0104 } else { 0105 0106 cairo_translate( context, x, y+h/2 ); 0107 cairo_rectangle( context, 0, 0, w, 2 ); 0108 0109 } 0110 0111 cairo_set_source_surface( context, surface, 0, 0 ); 0112 cairo_fill( context ); 0113 cairo_restore( context ); 0114 0115 } 0116 0117 //__________________________________________________________________ 0118 const Cairo::Surface& StyleHelper::separator( const ColorUtils::Rgba& base, bool vertical, int size ) 0119 { 0120 0121 const SeparatorKey key( base, vertical, size ); 0122 0123 // try find in cache and return 0124 if( const Cairo::Surface& surface = _separatorCache.value(key) ) 0125 { return surface; } 0126 0127 // for invalid sizes return a null surface 0128 if( size <= 0 ) 0129 { return _separatorCache.insert( key, 0L ); } 0130 0131 // cached not found, create new 0132 Cairo::Surface surface( vertical ? createSurface( 3, size ):createSurface( size, 2 ) ); 0133 0134 int xStart( 0 ); 0135 int yStart( 0 ); 0136 int xStop( vertical ? 0 : size ); 0137 int yStop( vertical ? size : 0 ); 0138 int xOffset( vertical ? 1:0 ); 0139 int yOffset( vertical ? 0:1 ); 0140 0141 Cairo::Context context( surface ); 0142 cairo_set_line_width( context, 1.0 ); 0143 0144 if( vertical ) cairo_translate( context, 0.5, 0 ); 0145 else cairo_translate( context, 0, 0.5 ); 0146 0147 { 0148 ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 0149 Cairo::Pattern pattern( cairo_pattern_create_linear( xStart, yStart, xStop, yStop ) ); 0150 if( vertical ) light.setAlpha( 0.7 ); 0151 0152 cairo_pattern_add_color_stop( pattern, 0.3, light ); 0153 cairo_pattern_add_color_stop( pattern, 0.7, light ); 0154 light.setAlpha( 0 ); 0155 cairo_pattern_add_color_stop( pattern, 0, light ); 0156 cairo_pattern_add_color_stop( pattern, 1, light ); 0157 cairo_set_source( context, pattern ); 0158 0159 if( vertical ) 0160 { 0161 cairo_move_to( context, xStart, yStart ); 0162 cairo_line_to( context, xStop, yStop ); 0163 cairo_move_to( context, xStart+2*xOffset, yStart+2*yOffset ); 0164 cairo_line_to( context, xStop+2*xOffset, yStop+2*yOffset ); 0165 0166 } else { 0167 0168 cairo_move_to( context, xStart+xOffset, yStart+yOffset ); 0169 cairo_line_to( context, xStop+xOffset, yStop+yOffset ); 0170 0171 } 0172 0173 cairo_stroke( context ); 0174 } 0175 0176 { 0177 ColorUtils::Rgba dark( ColorUtils::darkColor( base ) ); 0178 0179 Cairo::Pattern pattern( cairo_pattern_create_linear( xStart, yStart, xStop, yStop ) ); 0180 cairo_pattern_add_color_stop( pattern, 0.3, dark ); 0181 cairo_pattern_add_color_stop( pattern, 0.7, dark ); 0182 dark.setAlpha(0); 0183 cairo_pattern_add_color_stop( pattern, 0, dark ); 0184 cairo_pattern_add_color_stop( pattern, 1, dark ); 0185 cairo_set_source( context, pattern ); 0186 0187 if( vertical ) 0188 { 0189 0190 cairo_move_to( context, xStart+xOffset, yStart+yOffset ); 0191 cairo_line_to( context, xStop+xOffset, yStop+yOffset ); 0192 0193 } else { 0194 0195 cairo_move_to( context, xStart, yStart ); 0196 cairo_line_to( context, xStop, yStop ); 0197 } 0198 0199 cairo_stroke( context ); 0200 } 0201 0202 // note: we can't return the surface directly, because it is a temporary 0203 // we have to return the inserted object instead 0204 return _separatorCache.insert( key, surface ); 0205 0206 } 0207 0208 //______________________________________________________________________________ 0209 const Cairo::Surface& StyleHelper::windecoButton(const ColorUtils::Rgba &base, bool pressed, int size) 0210 { 0211 0212 const WindecoButtonKey key( base, size, pressed ); 0213 0214 // try find in cache and return 0215 if( const Cairo::Surface& surface = _windecoButtonCache.value(key) ) 0216 { return surface; } 0217 0218 // cached not found, create new 0219 Cairo::Surface surface( createSurface( size, size ) ); 0220 0221 // calculate colors 0222 ColorUtils::Rgba light = ColorUtils::lightColor(base); 0223 ColorUtils::Rgba dark = ColorUtils::darkColor(base); 0224 0225 // create cairo context 0226 Cairo::Context context( surface ); 0227 const double u = size/18.0; 0228 cairo_translate( context, 0.5*u, (0.5-0.668)*u ); 0229 0230 { 0231 0232 // plain background 0233 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, u*1.665, 0, u*(12.33+1.665) ) ); 0234 if( pressed ) 0235 { 0236 cairo_pattern_add_color_stop( pattern, 1, light ); 0237 cairo_pattern_add_color_stop( pattern, 0, dark ); 0238 } else { 0239 cairo_pattern_add_color_stop( pattern, 0, light ); 0240 cairo_pattern_add_color_stop( pattern, 1, dark ); 0241 } 0242 0243 cairo_ellipse( context, u*0.5*(17-12.33), u*1.665, u*12.33, u*12.33 ); 0244 cairo_set_source( context, pattern ); 0245 cairo_fill( context ); 0246 0247 } 0248 0249 { 0250 // outline circle 0251 const double penWidth( 0.7 ); 0252 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, u*1.665, 0, u*(2.0*12.33+1.665) ) ); 0253 cairo_pattern_add_color_stop( pattern, 0, light ); 0254 cairo_pattern_add_color_stop( pattern, 1, dark ); 0255 0256 cairo_ellipse( context, u*0.5*(17-12.33+penWidth), u*(1.665+penWidth), u*(12.33-penWidth), u*(12.33-penWidth) ); 0257 cairo_set_source( context, pattern ); 0258 cairo_set_line_width( context, penWidth ); 0259 cairo_stroke( context ); 0260 } 0261 0262 // note: we can't return the surface directly, because it is a temporary 0263 // we have to return the inserted object instead 0264 return _windecoButtonCache.insert( key, surface ); 0265 0266 } 0267 0268 //_______________________________________________________________________ 0269 const Cairo::Surface& StyleHelper::windecoButtonGlow(const ColorUtils::Rgba &base, int size) 0270 { 0271 0272 const WindecoButtonGlowKey key( base, size ); 0273 0274 // try find in cache and return 0275 if( const Cairo::Surface& surface = _windecoButtonGlowCache.value(key) ) 0276 { return surface; } 0277 0278 // cached not found, create new 0279 Cairo::Surface surface( createSurface( size, size ) ); 0280 0281 // right now the same color is used for the two shadows 0282 const ColorUtils::Rgba& light( base ); 0283 const ColorUtils::Rgba& dark( base ); 0284 0285 Cairo::Context context( surface ); 0286 const double u = size/18.0; 0287 cairo_translate( context, 0.5*u, (0.5-0.668)*u ); 0288 0289 { 0290 0291 // outer shadow 0292 Cairo::Pattern pattern( cairo_pattern_create_radial( u*8.5, u*8.5, u*8.5 ) ); 0293 0294 static const int nPoints( 5 ); 0295 double x[5] = { 0.61, 0.72, 0.81, 0.9, 1}; 0296 double values[5] = { 255-172, 255-178, 255-210, 255-250, 0 }; 0297 ColorUtils::Rgba c = dark; 0298 for( int i = 0; i<nPoints; i++ ) 0299 { c.setAlpha( values[i]/255 ); cairo_pattern_add_color_stop( pattern, x[i], c ); } 0300 0301 cairo_set_source( context, pattern ); 0302 cairo_rectangle( context, 0, 0, size, size ); 0303 cairo_fill( context ); 0304 } 0305 0306 { 0307 // inner shadow 0308 Cairo::Pattern pattern( cairo_pattern_create_radial( u*8.5, u*8.5, u*8.5 ) ); 0309 0310 static const int nPoints(6); 0311 const double x[6] = { 0.61, 0.67, 0.7, 0.74, 0.78, 1 }; 0312 const double values[6] = { 255-92, 255-100, 255-135, 255-205, 255-250, 0 }; 0313 ColorUtils::Rgba c( light ); 0314 for( int i = 0; i<nPoints; i++ ) 0315 { c.setAlpha( values[i]/255 ); cairo_pattern_add_color_stop( pattern, x[i], c ); } 0316 0317 cairo_set_source( context, pattern ); 0318 cairo_rectangle( context, 0, 0, size, size ); 0319 cairo_fill( context ); 0320 } 0321 0322 // note: we can't return the surface directly, because it is a temporary 0323 // we have to return the inserted object instead 0324 return _windecoButtonGlowCache.insert( key, surface ); 0325 0326 } 0327 0328 //_________________________________________________ 0329 const Cairo::Surface& StyleHelper::verticalGradient( const ColorUtils::Rgba& base, int height ) 0330 { 0331 0332 const VerticalGradientKey key( base, height ); 0333 0334 // try find in cache and return 0335 if( const Cairo::Surface& surface = _verticalGradientCache.value(key) ) 0336 { return surface; } 0337 0338 // cached not found, create new 0339 Cairo::Surface surface( createSurface( 32, height ) ); 0340 0341 { 0342 ColorUtils::Rgba top( ColorUtils::backgroundTopColor( base ) ); 0343 ColorUtils::Rgba bottom( ColorUtils::backgroundBottomColor( base ) ); 0344 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 0, 0, height ) ); 0345 cairo_pattern_add_color_stop( pattern, 0, top ); 0346 cairo_pattern_add_color_stop( pattern, 0.5, base ); 0347 cairo_pattern_add_color_stop( pattern, 1, bottom ); 0348 0349 Cairo::Context context( surface ); 0350 cairo_set_source( context, pattern ); 0351 cairo_rectangle( context, 0, 0, 32, height ); 0352 cairo_fill( context ); 0353 } 0354 0355 return _verticalGradientCache.insert( key, surface ); 0356 } 0357 0358 //_________________________________________________ 0359 const Cairo::Surface& StyleHelper::radialGradient( const ColorUtils::Rgba& base, int radius ) 0360 { 0361 0362 const RadialGradientKey key( base, radius ); 0363 0364 // try find in cache and return 0365 if( const Cairo::Surface& surface = _radialGradientCache.value(key) ) 0366 { return surface; } 0367 0368 // cached not found, create new 0369 Cairo::Surface surface( createSurface( 2*radius, radius ) ); 0370 0371 { 0372 // create radial pattern 0373 ColorUtils::Rgba radial( ColorUtils::backgroundRadialColor( base ) ); 0374 Cairo::Pattern pattern( cairo_pattern_create_radial( radius, 0, radius ) ); 0375 cairo_pattern_add_color_stop( pattern, 0, radial ); 0376 cairo_pattern_add_color_stop( pattern, 0.5, ColorUtils::alphaColor( radial, 101.0/255 ) ); 0377 cairo_pattern_add_color_stop( pattern, 0.75, ColorUtils::alphaColor( radial, 37.0/255 ) ); 0378 cairo_pattern_add_color_stop( pattern, 1.0, ColorUtils::alphaColor( radial, 0 ) ); 0379 0380 Cairo::Context context( surface ); 0381 cairo_set_source( context, pattern ); 0382 cairo_rectangle( context, 0, 0, 2*radius, radius ); 0383 cairo_fill( context ); 0384 } 0385 0386 return _radialGradientCache.insert( key, surface ); 0387 0388 } 0389 0390 //_________________________________________________ 0391 const TileSet& StyleHelper::slab(const ColorUtils::Rgba& base, const ColorUtils::Rgba& glow, double shade, int size) 0392 { 0393 0394 const SlabKey key( base, glow, shade, size ); 0395 const TileSet& tileSet( _slabCache.value( key ) ); 0396 if( tileSet.isValid() ) return tileSet; 0397 0398 // create surface and initialize 0399 const int w( 2*size ); 0400 const int h( 2*size ); 0401 Cairo::Surface surface( createSurface( w, h ) ); 0402 0403 { 0404 // create cairo context 0405 Cairo::Context context( surface ); 0406 cairo_scale( context, size/7.0, size/7.0 ); 0407 cairo_rectangle( context, 0, 0, 14, 14 ); 0408 cairo_set_source( context, ColorUtils::Rgba::transparent( base ) ); 0409 cairo_fill( context ); 0410 0411 if( base.isValid() ) drawShadow( context, ColorUtils::shadowColor( base ), 14 ); 0412 if( glow.isValid() ) drawOuterGlow( context, glow, 14 ); 0413 if( base.isValid() ) drawSlab( context, base, shade ); 0414 0415 } 0416 0417 // create tileSet 0418 return _slabCache.insert( key, TileSet( surface, size, size, size, size, size-1, size, 2, 1) ); 0419 0420 } 0421 0422 //__________________________________________________________________ 0423 const TileSet& StyleHelper::slabSunken( const ColorUtils::Rgba& base, int size ) 0424 { 0425 0426 const SlabKey key( base, 0.0, size ); 0427 const TileSet& tileSet( _slabSunkenCache.value( key ) ); 0428 if( tileSet.isValid() ) return tileSet; 0429 0430 // create surface and initialize 0431 const int w( 2*size ); 0432 const int h( 2*size ); 0433 Cairo::Surface surface( createSurface( w, h ) ); 0434 0435 { 0436 0437 // create cairo context 0438 Cairo::Context context( surface ); 0439 cairo_set_line_width( context, 1.0 ); 0440 cairo_scale( context, size/7.0, size/7.0 ); 0441 cairo_rectangle( context, 0, 0, 14, 14 ); 0442 cairo_set_source( context, ColorUtils::Rgba::transparent( base ) ); 0443 cairo_fill( context ); 0444 0445 if( base.isValid() ) 0446 { 0447 drawInverseShadow( context, ColorUtils::shadowColor(base), 3, 8, 0.0); 0448 0449 // contrast 0450 { 0451 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 0452 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 2, 0, 16 ) ); 0453 cairo_pattern_add_color_stop( pattern, 0.5, ColorUtils::Rgba::transparent( light ) ); 0454 cairo_pattern_add_color_stop( pattern, 1.0, light ); 0455 cairo_set_source( context, pattern ); 0456 cairo_rounded_rectangle( context, 2.5, 2.5, 9, 9, 4.0 ); 0457 cairo_stroke( context ); 0458 } 0459 0460 } 0461 0462 } 0463 0464 // create tileSet 0465 return _slabSunkenCache.insert( key, TileSet( surface, size, size, size, size, size-1, size, 2, 1) ); 0466 0467 } 0468 0469 //______________________________________________________________________________ 0470 const Cairo::Surface& StyleHelper::roundSlab(const ColorUtils::Rgba& base, const ColorUtils::Rgba& glow, double shade, int size) 0471 { 0472 0473 SlabKey key( base, glow, shade, size ); 0474 0475 // try find in cache and return 0476 if( const Cairo::Surface& surface = _roundSlabCache.value( key ) ) 0477 { return surface; } 0478 0479 // cached not found, create new 0480 const int w( 3*size ); 0481 const int h( 3*size ); 0482 Cairo::Surface surface( createSurface( w, h ) ); 0483 0484 // create cairo context 0485 Cairo::Context context( surface ); 0486 cairo_scale( context, size/7.0, size/7.0 ); 0487 0488 // shadow 0489 if( base.isValid() ) drawShadow( context, ColorUtils::shadowColor(base), 21 ); 0490 if( glow.isValid() ) drawOuterGlow( context, glow, 21 ); 0491 if( base.isValid() ) drawRoundSlab( context, base, shade ); 0492 0493 // note: we can't return the surface directly, because it is a temporary 0494 // we have to return the inserted object instead 0495 return _roundSlabCache.insert( key, surface ); 0496 0497 } 0498 0499 0500 //__________________________________________________________________________________________________________ 0501 const Cairo::Surface& StyleHelper::sliderSlab(const ColorUtils::Rgba& base, const ColorUtils::Rgba& glow, bool sunken, double shade, int size) 0502 { 0503 0504 SliderSlabKey key( base, glow, sunken, shade, size ); 0505 0506 // try find in cache and return 0507 if( const Cairo::Surface& surface = _sliderSlabCache.value( key ) ) 0508 { return surface; } 0509 0510 // cached not found, create new 0511 const int w( 3*size ); 0512 const int h( 3*size ); 0513 Cairo::Surface surface( createSurface( w, h ) ); 0514 0515 { 0516 Cairo::Context context( surface ); 0517 cairo_set_antialias( context, CAIRO_ANTIALIAS_SUBPIXEL ); 0518 0519 cairo_save( context ); 0520 cairo_scale( context, 3.0*size/23, 3.0*size/23 ); 0521 cairo_translate( context, 1, 1 ); 0522 0523 if( base.isValid() ) drawShadow( context, ColorUtils::alphaColor( ColorUtils::shadowColor(base), 0.8 ), 21 ); 0524 if( glow.isValid() ) drawOuterGlow( context, glow, 21 ); 0525 cairo_restore( context ); 0526 0527 cairo_scale( context, 3.0*size/25, 3.0*size/25 ); 0528 cairo_translate( context, 2, 2 ); 0529 drawSliderSlab( context, base, sunken, shade ); 0530 0531 } 0532 0533 return _sliderSlabCache.insert( key, surface ); 0534 0535 } 0536 0537 //________________________________________________________________________________________________________ 0538 const TileSet &StyleHelper::slope( const ColorUtils::Rgba& base, double shade, int size ) 0539 { 0540 0541 const SlabKey key( base, shade, size ); 0542 const TileSet& tileSet( _slopeCache.value( key ) ); 0543 if( tileSet.isValid() ) return tileSet; 0544 0545 const int w( 4*size ); 0546 const int h( 4*size ); 0547 Cairo::Surface surface( createSurface( w, h ) ); 0548 0549 { 0550 Cairo::Context context( surface ); 0551 const TileSet &slabTileSet = slab( base, shade, size ); 0552 slabTileSet.render( context, 0, 0, size*4, size*5, TileSet::Left | TileSet::Right | TileSet::Top ); 0553 0554 } 0555 0556 return _slopeCache.insert( key, TileSet( surface, size, size, size, size, size-1, size, 2, 1) ); 0557 0558 } 0559 0560 //__________________________________________________________________ 0561 void StyleHelper::fillSlab( cairo_t* context, int x, int y, int w, int h, const TileSet::Tiles& tiles ) const 0562 { 0563 0564 const double s( 3.6 + ( 0.5 * _slabThickness ) ); 0565 const double r( s/2 ); 0566 0567 Corners corners( CornersNone ); 0568 if( tiles & TileSet::Top ) 0569 { 0570 if( tiles & TileSet::Left ) corners |= CornersTopLeft; 0571 if( tiles & TileSet::Right ) corners |= CornersTopRight; 0572 } 0573 0574 if( tiles & TileSet::Bottom ) 0575 { 0576 if( tiles & TileSet::Left ) corners |= CornersBottomLeft; 0577 if( tiles & TileSet::Right ) corners |= CornersBottomRight; 0578 } 0579 0580 0581 cairo_rounded_rectangle( context, x+s, y+s, w-2*s, h-2*s, r, corners ); 0582 cairo_fill( context ); 0583 } 0584 0585 //__________________________________________________________________ 0586 GdkPixmap* StyleHelper::roundMask( int w, int h, int radius ) const 0587 { 0588 0589 GdkPixmap* mask( gdk_pixmap_new( 0L, w, h, 1 ) ); 0590 0591 { 0592 Cairo::Context context( GDK_DRAWABLE(mask) ); 0593 0594 // clear the window 0595 cairo_set_operator( context, CAIRO_OPERATOR_SOURCE ); 0596 cairo_set_source( context, ColorUtils::Rgba::transparent() ); 0597 cairo_paint( context ); 0598 0599 // now draw roundrect mask 0600 cairo_set_operator( context, CAIRO_OPERATOR_OVER ); 0601 cairo_set_source( context, ColorUtils::Rgba::black() ); 0602 0603 // FIXME: radius found empirically 0604 cairo_rounded_rectangle( context, 0, 0, w, h, radius ); 0605 cairo_fill( context ); 0606 } 0607 0608 return mask; 0609 0610 } 0611 0612 0613 //______________________________________________________________________________ 0614 const TileSet& StyleHelper::holeFocused( 0615 const ColorUtils::Rgba &base, const ColorUtils::Rgba &fill, const ColorUtils::Rgba &glow, 0616 int size, bool contrast ) 0617 { 0618 0619 const HoleFocusedKey key( base, fill, glow, size, contrast ); 0620 const TileSet& tileSet( _holeFocusedCache.value( key ) ); 0621 if( tileSet.isValid() ) return tileSet; 0622 0623 // first create shadow 0624 const int shadowSize( (size*5)/7 ); 0625 Cairo::Surface shadowSurface( createSurface( 2*shadowSize, 2*shadowSize ) ); 0626 0627 { 0628 Cairo::Context context( shadowSurface ); 0629 cairo_scale( context, 5.0/shadowSize, 5.0/shadowSize ); 0630 0631 // get alpha channel 0632 double alpha( glow.isValid() ? glow.alpha() : 0 ); 0633 if( alpha < 1 ) 0634 { 0635 0636 // shadow 0637 drawInverseShadow( context, ColorUtils::alphaColor( ColorUtils::shadowColor( base ), 1.0 - alpha ), 1, 8, 0.0); 0638 0639 } 0640 0641 if( alpha > 0 ) 0642 { 0643 0644 // glow 0645 drawInverseGlow( context, glow, 1, 8, shadowSize ); 0646 0647 } 0648 0649 } 0650 0651 // create surface 0652 Cairo::Surface surface( createSurface( 2*size, 2*size ) ); 0653 { 0654 0655 Cairo::Context context( surface ); 0656 cairo_scale( context, 7.0/size, 7.0/size ); 0657 cairo_set_line_width( context, 1 ); 0658 0659 // inside 0660 if( fill.isValid() ) 0661 { 0662 cairo_rounded_rectangle( context, 1, 1, 12, 11, 2.5 ); 0663 cairo_set_source( context, fill ); 0664 cairo_fill( context ); 0665 } 0666 0667 // draw shadow 0668 TileSet( 0669 shadowSurface, shadowSize, shadowSize, shadowSize, shadowSize, 0670 shadowSize-1, shadowSize, 2, 1 ). 0671 render( context, 0, 0, size*2, size*2 ); 0672 0673 // contrast pixel 0674 if( contrast ) 0675 { 0676 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 0677 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 0, 0, 18 ) ); 0678 cairo_pattern_add_color_stop( pattern, 0.5, ColorUtils::Rgba::transparent( light ) ); 0679 cairo_pattern_add_color_stop( pattern, 1.0, light ); 0680 cairo_set_source( context, pattern ); 0681 cairo_rounded_rectangle( context, 0.5, 0.5, 13, 13, 4.0 ); 0682 cairo_stroke( context ); 0683 0684 } 0685 0686 } 0687 0688 return _holeFocusedCache.insert( key, TileSet( surface, size, size, size, size, size-1, size, 2, 1 ) ); 0689 0690 } 0691 0692 //________________________________________________________________________________________________________ 0693 const TileSet& StyleHelper::holeFlat( const ColorUtils::Rgba& base, double shade, bool fill, int size ) 0694 { 0695 0696 const HoleFlatKey key( base, shade, fill, size ); 0697 const TileSet& tileSet( _holeFlatCache.value( key ) ); 0698 if( tileSet.isValid() ) return tileSet; 0699 0700 const int w( 2*size ); 0701 const int h( 2*size ); 0702 0703 Cairo::Surface surface( createSurface( w, h ) ); 0704 0705 if( fill ) 0706 { 0707 0708 Cairo::Context context( surface ); 0709 cairo_set_line_width( context, 1.0 ); 0710 0711 cairo_scale( context, 14.0/w, 14.0/h ); 0712 0713 // hole inside 0714 cairo_set_source( context, base ); 0715 cairo_rounded_rectangle( context, 1, 0, 12, 13, 3.0 ); 0716 cairo_fill( context ); 0717 0718 { 0719 // shadow (top) 0720 const ColorUtils::Rgba dark( ColorUtils::shade( ColorUtils::darkColor( base ), shade ) ); 0721 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, -2, 0, 14 ) ); 0722 cairo_pattern_add_color_stop( pattern, 0, dark ); 0723 cairo_pattern_add_color_stop( pattern, 0.4, ColorUtils::Rgba::transparent( dark ) ); 0724 cairo_set_source( context, pattern ); 0725 cairo_rounded_rectangle( context, 1.5, 0.5, 11, 12, 2.5 ); 0726 cairo_stroke( context ); 0727 } 0728 0729 { 0730 // contrast (bottom) 0731 const ColorUtils::Rgba light( ColorUtils::shade( ColorUtils::lightColor( base ), shade ) ); 0732 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 0, 0, 18 ) ); 0733 cairo_pattern_add_color_stop( pattern, 0.5, ColorUtils::Rgba::transparent( light ) ); 0734 cairo_pattern_add_color_stop( pattern, 1.0, light ); 0735 cairo_set_source( context, pattern ); 0736 cairo_rounded_rectangle( context, 0.5, 0.5, 13, 13, 3.5 ); 0737 cairo_stroke( context ); 0738 } 0739 0740 } else { 0741 0742 Cairo::Context context( surface ); 0743 cairo_set_line_width( context, 1.0 ); 0744 0745 cairo_scale( context, 14.0/w, 14.0/h ); 0746 0747 // hole inside 0748 cairo_set_source( context, base ); 0749 cairo_rounded_rectangle( context, 1, 1, 12, 12, 3.0 ); 0750 cairo_fill( context ); 0751 0752 { 0753 // shadow (top) 0754 const ColorUtils::Rgba dark( ColorUtils::shade( ColorUtils::darkColor( base ), shade ) ); 0755 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 1, 0, 12 ) ); 0756 cairo_pattern_add_color_stop( pattern, 0, dark ); 0757 cairo_pattern_add_color_stop( pattern, 0.4, ColorUtils::Rgba::transparent( dark ) ); 0758 cairo_set_source( context, pattern ); 0759 cairo_rounded_rectangle( context, 1.5, 1.5, 11, 11, 2.5 ); 0760 cairo_stroke( context ); 0761 } 0762 0763 { 0764 // contrast (bottom) 0765 const ColorUtils::Rgba light( ColorUtils::shade( ColorUtils::lightColor( base ), shade ) ); 0766 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 1, 0, 12 ) ); 0767 cairo_pattern_add_color_stop( pattern, 0.5, ColorUtils::Rgba::transparent( light ) ); 0768 cairo_pattern_add_color_stop( pattern, 1.0, light ); 0769 cairo_set_source( context, pattern ); 0770 cairo_rounded_rectangle( context, 1.5, 1.5, 11, 11, 2.5 ); 0771 cairo_stroke( context ); 0772 } 0773 0774 0775 } 0776 0777 return _holeFlatCache.insert( key, TileSet( surface, size, size, size, size, size-1, size, 2, 1 ) ); 0778 0779 } 0780 0781 //______________________________________________________________________________ 0782 const TileSet& StyleHelper::scrollHole( const ColorUtils::Rgba& base, bool vertical, bool smallShadow ) 0783 { 0784 0785 const ScrollHoleKey key( base, vertical, smallShadow ); 0786 const TileSet& tileSet( _scrollHoleCache.value( key ) ); 0787 if( tileSet.isValid() ) return tileSet; 0788 0789 // define colors 0790 const ColorUtils::Rgba& dark( ColorUtils::darkColor( base ) ); 0791 const ColorUtils::Rgba& light( ColorUtils::lightColor( base ) ); 0792 const ColorUtils::Rgba& shadow( ColorUtils::shadowColor( base ) ); 0793 0794 // create pixmap 0795 const int w( 15 ); 0796 const int h( 15 ); 0797 Cairo::Surface surface( createSurface( w, h ) ); 0798 0799 { 0800 Cairo::Context context( surface ); 0801 0802 GdkRectangle r = { 0, 0, w, h }; 0803 GdkRectangle rect = { 1, 0, w-2, h-1 }; 0804 0805 // radius 0806 const double radius( smallShadow ? 2.5:3.0 ); 0807 0808 // base 0809 { 0810 cairo_set_source( context, dark ); 0811 gdk_cairo_rounded_rectangle( context, &rect, radius ); 0812 cairo_fill( context ); 0813 } 0814 0815 // light shadow across the whole hole 0816 { 0817 Cairo::Pattern pattern; 0818 if( vertical ) pattern.set( cairo_pattern_create_linear( rect.x, 0, rect.x + rect.width, 0 ) ); 0819 else pattern.set( cairo_pattern_create_linear( 0, rect.y, 0, rect.y + rect.height ) ); 0820 cairo_pattern_add_color_stop( pattern, 0, ColorUtils::alphaColor( shadow, 0.1 ) ); 0821 cairo_pattern_add_color_stop( pattern, 0.6, ColorUtils::Rgba::transparent( shadow ) ); 0822 0823 cairo_set_source( context, pattern ); 0824 gdk_cairo_rounded_rectangle( context, &rect, radius ); 0825 cairo_fill( context ); 0826 } 0827 0828 // first create shadow 0829 const int shadowSize( 5 ); 0830 Cairo::Surface shadowSurface( createSurface( 2*shadowSize, 2*shadowSize ) ); 0831 { 0832 Cairo::Context context( shadowSurface ); 0833 drawInverseShadow( context, ColorUtils::shadowColor( base ), 1, 8, 0.0); 0834 } 0835 0836 // draw shadow 0837 TileSet( 0838 shadowSurface, shadowSize, shadowSize, shadowSize, shadowSize, 0839 shadowSize-1, shadowSize, 2, 1 ). 0840 render( context, 0, -1, w, h+1, TileSet::Full ); 0841 0842 // light bottom border 0843 { 0844 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, r.y, 0, r.y + r.height ) ); 0845 0846 if( smallShadow && vertical ) 0847 { 0848 0849 cairo_pattern_add_color_stop( pattern, 0.8, ColorUtils::Rgba::transparent( light ) ); 0850 cairo_pattern_add_color_stop( pattern, 1, ColorUtils::alphaColor( light, 0.5 ) ); 0851 0852 } else { 0853 0854 cairo_pattern_add_color_stop( pattern, 0.5, ColorUtils::Rgba::transparent( light ) ); 0855 cairo_pattern_add_color_stop( pattern, 1, ColorUtils::alphaColor( light, 0.6 ) ); 0856 0857 } 0858 0859 cairo_set_source( context, pattern ); 0860 cairo_set_line_width( context, 1.0 ); 0861 cairo_rounded_rectangle( context, 0.5+r.x, 0.5+r.y, r.width-1, r.height-1, radius+0.5 ); 0862 cairo_stroke( context ); 0863 } 0864 0865 } 0866 0867 return _scrollHoleCache.insert( key, TileSet( surface, 7, 7, 1, 1 ) ); 0868 0869 } 0870 0871 //______________________________________________________________________________ 0872 const TileSet& StyleHelper::scrollHandle( const ColorUtils::Rgba& base, const ColorUtils::Rgba& glow, int size ) 0873 { 0874 0875 const ScrollHandleKey key( base, glow, size ); 0876 const TileSet& tileSet( _scrollHandleCache.value( key ) ); 0877 if( tileSet.isValid() ) return tileSet; 0878 0879 // create pixmap 0880 const int w( 2*size ); 0881 const int h( 2*size ); 0882 Cairo::Surface surface( createSurface( w, h ) ); 0883 0884 { 0885 Cairo::Context context( surface ); 0886 cairo_scale( context, (2.0*size)/14, (2.0*size)/14 ); 0887 0888 // first create shadow 0889 Cairo::Surface shadowSurface( createSurface( 10, 10 ) ); 0890 { 0891 Cairo::Context context( shadowSurface ); 0892 0893 // shadow/glow 0894 drawOuterGlow( context, glow, 10 ); 0895 0896 } 0897 0898 // draw shadow 0899 TileSet( shadowSurface, 4, 4, 1, 1 ). 0900 render( context, 0, 0, 14, 14, TileSet::Full ); 0901 0902 // outline 0903 { 0904 const ColorUtils::Rgba mid( ColorUtils::midColor( base ) ); 0905 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 3, 0, 11 ) ); 0906 cairo_pattern_add_color_stop( pattern, 0, base ); 0907 cairo_pattern_add_color_stop( pattern, 1, mid ); 0908 cairo_set_source( context, pattern ); 0909 cairo_rounded_rectangle( context, 3, 3, 8, 8, 2.5 ); 0910 cairo_fill( context ); 0911 } 0912 0913 // contrast 0914 { 0915 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 0916 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 3, 0, 11 ) ); 0917 cairo_pattern_add_color_stop( pattern, 0, ColorUtils::alphaColor( light, 0.9 ) ); 0918 cairo_pattern_add_color_stop( pattern, 0.5, ColorUtils::alphaColor( light, 0.44 ) ); 0919 cairo_set_source( context, pattern ); 0920 cairo_rounded_rectangle( context, 3, 3, 8, 8, 2.5 ); 0921 cairo_fill( context ); 0922 } 0923 0924 } 0925 0926 return _scrollHandleCache.insert( key, TileSet( surface, 7, 7, 1, 1 ) ); 0927 0928 } 0929 0930 //________________________________________________________________________________________________________ 0931 const TileSet& StyleHelper::slitFocused( const ColorUtils::Rgba& glow ) 0932 { 0933 0934 const SlitFocusedKey key( glow ); 0935 const TileSet& tileSet( _slitFocusedCache.value( key ) ); 0936 if( tileSet.isValid() ) return tileSet; 0937 0938 // create pixmap 0939 const int w( 9 ); 0940 const int h( 9 ); 0941 Cairo::Surface surface( createSurface( w, h ) ); 0942 { 0943 Cairo::Context context( surface ); 0944 0945 cairo_pattern_t* pattern( cairo_pattern_create_radial( 4.5, 4.5, 3.5 ) ); 0946 cairo_pattern_add_color_stop( pattern, 1.0, ColorUtils::alphaColor( glow, 180.0/255 ) ); 0947 cairo_pattern_add_color_stop( pattern, 0.5, ColorUtils::Rgba::transparent( glow ) ); 0948 0949 cairo_set_source( context, pattern ); 0950 cairo_ellipse( context, 1, 1, 7, 7 ) ; 0951 cairo_fill( context ); 0952 0953 } 0954 0955 return _slitFocusedCache.insert( key, TileSet( surface, 4, 4, 1, 1 ) ); 0956 0957 } 0958 0959 //____________________________________________________________________ 0960 const TileSet& StyleHelper::dockFrame( const ColorUtils::Rgba &top, const ColorUtils::Rgba& bottom ) 0961 { 0962 0963 // key 0964 DockFrameKey key( top, bottom ); 0965 const TileSet& tileSet( _dockFrameCache.value( key ) ); 0966 if( tileSet.isValid() ) return tileSet; 0967 0968 // fixed height 0969 const int size( 13 ); 0970 0971 Cairo::Surface surface( createSurface( size, size ) ); 0972 { 0973 0974 Cairo::Context context( surface ); 0975 cairo_set_line_width( context, 1.0 ); 0976 0977 // local rectangle 0978 const double w( size ); 0979 const double h( size ); 0980 0981 const ColorUtils::Rgba lightTop( ColorUtils::alphaColor( ColorUtils::lightColor( top ), 0.5 ) ); 0982 const ColorUtils::Rgba lightBottom( ColorUtils::alphaColor( ColorUtils::lightColor( bottom ), 0.5 ) ); 0983 const ColorUtils::Rgba darkTop( ColorUtils::alphaColor( ColorUtils::darkColor( top ), 0.5 ) ); 0984 const ColorUtils::Rgba darkBottom( ColorUtils::alphaColor( ColorUtils::darkColor( bottom ), 0.5 ) ); 0985 0986 // dark frame 0987 { 0988 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 0.5, 0, h - 1.5 ) ); 0989 cairo_pattern_add_color_stop( pattern, 0, darkTop ); 0990 cairo_pattern_add_color_stop( pattern, 1, darkBottom ); 0991 cairo_set_source( context, pattern ); 0992 cairo_rounded_rectangle( context, 1.5, 0.5, w-3, h-2, 4 ); 0993 cairo_stroke( context ); 0994 } 0995 0996 // bottom contrast 0997 { 0998 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 0.5, 0, h - 0.5 ) ); 0999 cairo_pattern_add_color_stop( pattern, 0, ColorUtils::Rgba::transparent( lightBottom ) ); 1000 cairo_pattern_add_color_stop( pattern, 1, lightBottom ); 1001 cairo_set_source( context, pattern ); 1002 cairo_rounded_rectangle( context, 0.5, 0.5, w-1, h-1, 4.5 ); 1003 cairo_stroke( context ); 1004 } 1005 1006 // top contrast 1007 { 1008 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 1.5, 0, h - 2.5 ) ); 1009 cairo_pattern_add_color_stop( pattern, 0, lightTop ); 1010 cairo_pattern_add_color_stop( pattern, 1, ColorUtils::Rgba::transparent( lightTop ) ); 1011 cairo_rounded_rectangle( context, 2.5, 1.5, w-5, h-4, 3.5 ); 1012 cairo_set_source( context, pattern ); 1013 cairo_stroke( context ); 1014 } 1015 1016 } 1017 1018 return _dockFrameCache.insert( key, TileSet( surface, (size-1)/2, (size-1)/2, 1, 1 ) ); 1019 } 1020 1021 //____________________________________________________________________ 1022 const Cairo::Surface& StyleHelper::progressBarIndicator(const ColorUtils::Rgba& base, const ColorUtils::Rgba& highlight, int w, int h ) 1023 { 1024 1025 ProgressBarIndicatorKey key( base, highlight, w, h ); 1026 1027 // try find in cache and return 1028 if( const Cairo::Surface& surface = _progressBarIndicatorCache.value( key ) ) 1029 { return surface; } 1030 1031 // cached not found, create new 1032 1033 // local rect 1034 int xl = 0; 1035 int yl = 0; 1036 int wl = w; 1037 int hl = h; 1038 1039 Cairo::Surface surface( createSurface( wl, hl ) ); 1040 Cairo::Context context( surface ); 1041 1042 // colors 1043 const ColorUtils::Rgba lhighlight( ColorUtils::lightColor( highlight ) ); 1044 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 1045 const ColorUtils::Rgba dark( ColorUtils::darkColor( base ) ); 1046 const ColorUtils::Rgba shadow( ColorUtils::shadowColor( base ) ); 1047 1048 { 1049 // shadow 1050 cairo_rounded_rectangle( context, xl+0.5, yl+0.5, wl-1, hl, 3.0 ); 1051 cairo_set_source( context, ColorUtils::alphaColor( shadow, 0.6 ) ); 1052 cairo_set_line_width( context, 0.6 ); 1053 cairo_stroke( context ); 1054 } 1055 1056 xl += 1; 1057 yl += 1; 1058 wl -= 2; 1059 hl -= 1; 1060 1061 { 1062 // filling 1063 cairo_set_source( context, ColorUtils::mix( highlight, dark, 0.2 ) ); 1064 cairo_rounded_rectangle( context, xl, yl, wl, hl, 2.5 ); 1065 cairo_fill( context ); 1066 } 1067 1068 // create pattern pixbuf 1069 { 1070 1071 Cairo::Pattern mask( cairo_pattern_create_linear( 0, 0, wl, 0 ) ); 1072 cairo_pattern_add_color_stop( mask, 0, ColorUtils::Rgba::transparent() ); 1073 cairo_pattern_add_color_stop( mask, 0.4, ColorUtils::Rgba::black() ); 1074 cairo_pattern_add_color_stop( mask, 0.6, ColorUtils::Rgba::black() ); 1075 cairo_pattern_add_color_stop( mask, 1.0, ColorUtils::Rgba::transparent() ); 1076 1077 const ColorUtils::Rgba mix( ColorUtils::mix( lhighlight, light, 0.3 ) ); 1078 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 0, 0, hl ) ); 1079 cairo_pattern_add_color_stop( pattern, 0, mix ); 1080 cairo_pattern_add_color_stop( pattern, 0.5, ColorUtils::Rgba::transparent( mix ) ); 1081 cairo_pattern_add_color_stop( pattern, 0.6, ColorUtils::Rgba::transparent( mix ) ); 1082 cairo_pattern_add_color_stop( pattern, 1.0, mix ); 1083 1084 Cairo::Surface localSurface( createSurface( wl, hl ) ); 1085 Cairo::Context localContext( localSurface ); 1086 cairo_rectangle( localContext, 0, 0, wl, hl ); 1087 cairo_set_source( localContext, pattern ); 1088 cairo_mask( localContext, mask ); 1089 localContext.free(); 1090 1091 cairo_save( context ); 1092 cairo_translate( context, 1, 1 ); 1093 cairo_rectangle( context, 0, 0, wl, hl ); 1094 cairo_set_source_surface( context, localSurface, 0, 0 ); 1095 cairo_fill( context ); 1096 cairo_restore( context ); 1097 1098 } 1099 1100 { 1101 // bevel 1102 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 0, 0, hl ) ); 1103 cairo_pattern_add_color_stop( pattern, 0.0, lhighlight ); 1104 cairo_pattern_add_color_stop( pattern, 0.5, highlight ); 1105 cairo_pattern_add_color_stop( pattern, 1.0, ColorUtils::darkColor(highlight) ); 1106 cairo_set_line_width( context, 1.0 ); 1107 cairo_set_source( context, pattern ); 1108 cairo_rounded_rectangle( context, xl+0.5, yl+0.5, wl-1, hl-1, 2.5 ); 1109 cairo_stroke( context ); 1110 } 1111 1112 { 1113 // bright top edge 1114 Cairo::Pattern pattern( cairo_pattern_create_linear( xl, 0, xl+wl, 0 ) ); 1115 const ColorUtils::Rgba mix( ColorUtils::mix( lhighlight, light, 0.8 ) ); 1116 cairo_pattern_add_color_stop( pattern, 0.0, ColorUtils::Rgba::transparent( mix ) ); 1117 cairo_pattern_add_color_stop( pattern, 0.5, mix ); 1118 cairo_pattern_add_color_stop( pattern, 1.0, ColorUtils::Rgba::transparent( mix ) ); 1119 cairo_set_line_width( context, 1.0 ); 1120 cairo_set_source( context, pattern ); 1121 cairo_move_to( context, xl+0.5, yl+0.5 ); 1122 cairo_line_to( context, xl+wl-0.5, yl+0.5 ); 1123 cairo_stroke( context ); 1124 } 1125 1126 // note: we can't return the surface directly, because it is a temporary 1127 // we have to return the inserted object instead 1128 return _progressBarIndicatorCache.insert( key, surface ); 1129 1130 } 1131 1132 //________________________________________________________________________________________________________ 1133 const TileSet& StyleHelper::groove( const ColorUtils::Rgba &base, int size ) 1134 { 1135 1136 const GrooveKey key( base, size ); 1137 const TileSet& tileSet( _grooveCache.value( key ) ); 1138 if( tileSet.isValid() ) return tileSet; 1139 1140 const int rsize( int( ceil( size * 3.0/7.0 ) ) ); 1141 const int w( rsize*2 ); 1142 const int h( rsize*2 ); 1143 Cairo::Surface surface( createSurface( w, h ) ); 1144 1145 { 1146 1147 Cairo::Context context( surface ); 1148 cairo_scale( context, 6/w, 6/h ); 1149 1150 Cairo::Pattern pattern( inverseShadowGradient( ColorUtils::shadowColor( base ), 1, 4, 0.0 ) ); 1151 cairo_set_source( context, pattern ); 1152 cairo_ellipse( context, 1, 1, 4, 4 ); 1153 cairo_ellipse_negative( context, 2, 2, 2, 2 ); 1154 cairo_fill( context ); 1155 1156 } 1157 1158 return _grooveCache.insert( key, TileSet( surface, rsize, rsize, rsize, rsize, rsize-1, rsize, 2, 1 ) ); 1159 1160 } 1161 1162 //____________________________________________________________________ 1163 const TileSet& StyleHelper::selection( const ColorUtils::Rgba& base, int h, bool custom ) 1164 { 1165 1166 const SelectionKey key( base, h, custom ); 1167 const TileSet& tileSet( _selectionCache.value( key ) ); 1168 if( tileSet.isValid() ) return tileSet; 1169 1170 const int w = 32+16; 1171 Cairo::Surface surface( createSurface( w, h ) ); 1172 1173 { 1174 1175 // adjust height 1176 const int x = 0; 1177 const int y = 0; 1178 const double rounding( 2.5 ); 1179 1180 Cairo::Context context( surface ); 1181 cairo_set_line_width( context, 1.0 ); 1182 1183 { 1184 // filling 1185 const int lightenAmount( custom ? 110 : 130 ); 1186 const ColorUtils::Rgba light( base.light( lightenAmount ) ); 1187 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, y, 0, y+h ) ); 1188 cairo_pattern_add_color_stop( pattern, 0, light ); 1189 cairo_pattern_add_color_stop( pattern, 1, base ); 1190 1191 cairo_rounded_rectangle( context, x, y, w, h, rounding ); 1192 cairo_set_source( context, pattern ); 1193 cairo_fill( context ); 1194 } 1195 1196 { 1197 // contrast 1198 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, y, 0, y+h ) ); 1199 cairo_pattern_add_color_stop( pattern, 0, base ); 1200 cairo_pattern_add_color_stop( pattern, 1, ColorUtils::Rgba::transparent() ); 1201 1202 cairo_rounded_rectangle( context, x+0.5, y+0.5, w-1, h-1, rounding ); 1203 cairo_set_source( context, pattern ); 1204 cairo_stroke( context ); 1205 } 1206 1207 } 1208 1209 return _selectionCache.insert( key, TileSet( surface, 8, 0, 32, h ) ); 1210 1211 } 1212 1213 //____________________________________________________________________ 1214 void StyleHelper::renderDot( cairo_t* context, const ColorUtils::Rgba& base, int x, int y ) const 1215 { 1216 // Reduce diameter to make dots look more like in Oxygen-Qt 1217 const double diameter( 1.8 - 0.35 ); 1218 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 1219 const ColorUtils::Rgba dark( ColorUtils::darkColor( base ).dark(130) ); 1220 1221 cairo_ellipse( context, x + 1.0 - diameter/2, y + 1.0 - diameter/2.0, diameter, diameter ); 1222 cairo_set_source( context, light ); 1223 cairo_fill( context ); 1224 1225 cairo_ellipse( context, x + 0.5 - diameter/2, y + 0.5 - diameter/2.0, diameter, diameter ); 1226 cairo_set_source( context, dark ); 1227 cairo_fill( context ); 1228 } 1229 1230 //______________________________________________________________________________________ 1231 void StyleHelper::drawSlab( Cairo::Context& context, const ColorUtils::Rgba& color, double shade) const 1232 { 1233 1234 const ColorUtils::Rgba light( ColorUtils::shade( lightColor(color), shade ) ); 1235 const ColorUtils::Rgba base( ColorUtils::alphaColor( light, 0.85 ) ); 1236 const ColorUtils::Rgba dark( ColorUtils::shade( darkColor(color), shade ) ); 1237 1238 // bevel, part 1 1239 { 1240 1241 const double y( ColorUtils::luma(base) ); 1242 const double yl( ColorUtils::luma(light) ); 1243 const double yd( ColorUtils::luma(dark) ); 1244 1245 // create pattern 1246 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 7, 0, 11 ) ); 1247 cairo_pattern_add_color_stop( pattern, 0, light ); 1248 if (y < yl && y > yd) 1249 { 1250 // no middle when color is very light/dark 1251 cairo_pattern_add_color_stop( pattern, 0.5, base ); 1252 } 1253 1254 cairo_pattern_add_color_stop( pattern, 0.9, base ); 1255 cairo_set_source( context, pattern ); 1256 cairo_rounded_rectangle( context, 3.0, 3.0, 8, 8, 3.5 ); 1257 cairo_fill( context ); 1258 1259 } 1260 1261 // bevel, part 2 1262 if( _slabThickness > 0.0 ) 1263 { 1264 1265 /* 1266 for some reason need to make ic a bit thicker 1267 this is likely due to differences between cairo and qpainter 1268 as a result, need to make the second pattern brighter 1269 */ 1270 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 6, 0, 19 ) ); 1271 cairo_pattern_add_color_stop( pattern, 0, light ); 1272 cairo_pattern_add_color_stop( pattern, 0.9, base ); 1273 cairo_set_source( context, pattern ); 1274 cairo_ellipse( context, 3.6, 3.6, 6.8, 6.8 ); 1275 cairo_fill( context ); 1276 1277 } 1278 1279 // inside mask 1280 cairo_save( context ); 1281 cairo_set_operator( context, CAIRO_OPERATOR_DEST_OUT ); 1282 cairo_set_source( context, ColorUtils::Rgba::black() ); 1283 1284 const double ic( 3.6 + 0.5*_slabThickness ); 1285 const double is( 14.0 - 2.0*ic ); 1286 cairo_ellipse( context, ic, ic, is, is ); 1287 cairo_fill( context ); 1288 cairo_restore( context ); 1289 1290 } 1291 1292 //___________________________________________________________________________________________ 1293 void StyleHelper::drawShadow( cairo_t* context, const ColorUtils::Rgba& base, int size ) const 1294 { 1295 1296 const double m( 0.5*size-1 ); 1297 const double offset( 0.8 ); 1298 const double k0( (m-4.0) / m ); 1299 1300 const double x(m+1); 1301 const double y(m+offset+1); 1302 1303 Cairo::Pattern pattern( cairo_pattern_create_radial(x, y, m ) ); 1304 for (int i = 0; i < 8; i++) 1305 { 1306 // sinusoidal pattern 1307 const double k1( (k0 * (8 - i) + i) * 0.125 ); 1308 const double a( (cos( M_PI * i * 0.125) + 1.0) * 0.30 ); 1309 cairo_pattern_add_color_stop( pattern, k1, ColorUtils::alphaColor( base, a*_shadowGain ) ); 1310 } 1311 1312 cairo_pattern_add_color_stop( pattern, 1, ColorUtils::Rgba::transparent( base ) ); 1313 cairo_set_source( context, pattern ); 1314 cairo_ellipse( context, 0, 0, size, size ); 1315 cairo_fill( context ); 1316 1317 } 1318 1319 //_______________________________________________________________________ 1320 void StyleHelper::drawOuterGlow( cairo_t* context, const ColorUtils::Rgba& base, int size ) const 1321 { 1322 1323 const double m( size*0.5 ); 1324 const double w( 3 ); 1325 1326 const double bias( _glowBias * 14.0/size ); 1327 1328 // k0 is located at w - bias from the outer edge 1329 const double gm( m + bias - 0.9 ); 1330 const double k0( (m-w+bias) / gm ); 1331 1332 Cairo::Pattern pattern( cairo_pattern_create_radial( m, m, gm ) ); 1333 for (int i = 0; i < 8; i++) 1334 { 1335 // parabolic pattern 1336 const double k1( k0 + i*(1.0-k0)/8.0 ); 1337 const double a( 1.0 - sqrt(i/8.0) ); 1338 cairo_pattern_add_color_stop( pattern, k1, ColorUtils::alphaColor( base, a ) ); 1339 } 1340 1341 cairo_pattern_add_color_stop( pattern, 1, ColorUtils::Rgba::transparent( base ) ); 1342 1343 cairo_set_source( context, pattern ); 1344 cairo_ellipse( context, 0, 0, size, size ); 1345 cairo_fill( context ); 1346 1347 cairo_save( context ); 1348 cairo_set_operator( context, CAIRO_OPERATOR_DEST_OUT ); 1349 cairo_set_source( context, ColorUtils::Rgba::black() ); 1350 cairo_ellipse( context, w+0.5, w+0.5, size - 2*w-1, size - 2*w-1 ); 1351 cairo_fill( context ); 1352 cairo_restore( context ); 1353 1354 } 1355 1356 //________________________________________________________________________________________________________ 1357 void StyleHelper::drawInverseShadow( 1358 Cairo::Context& context, const ColorUtils::Rgba& base, 1359 int pad, int size, double fuzz ) const 1360 { 1361 1362 Cairo::Pattern pattern( inverseShadowGradient( base, pad, size, fuzz ) ); 1363 1364 cairo_set_source( context, pattern ); 1365 cairo_ellipse( context, pad-fuzz, pad-fuzz, size+fuzz*2.0, size+fuzz*2.0 ); 1366 cairo_fill( context ); 1367 1368 } 1369 1370 //________________________________________________________________________________________________________ 1371 void StyleHelper::drawInverseGlow( 1372 Cairo::Context& context, const ColorUtils::Rgba& base, 1373 int pad, int size, int rsize ) const 1374 { 1375 1376 const double m( size*0.5 ); 1377 1378 const double width( 3.5 ); 1379 const double bias( _glowBias*7.0/rsize ); 1380 const double k0( ( m-width )/( m-bias ) ); 1381 Cairo::Pattern pattern( cairo_pattern_create_radial( pad+m, pad+m, m-bias ) ); 1382 for ( int i = 0; i < 8; i++ ) 1383 { 1384 // inverse parabolic gradient 1385 double k1 = ( k0 * i + 8 - i ) * 0.125; 1386 double a = 1.0 - sqrt( i * 0.125 ); 1387 cairo_pattern_add_color_stop( pattern, k1, ColorUtils::alphaColor( base, a ) ); 1388 1389 } 1390 1391 cairo_pattern_add_color_stop( pattern, k0, ColorUtils::Rgba::transparent( base ) ); 1392 cairo_set_source( context, pattern ); 1393 cairo_ellipse( context, pad, pad, size, size ); 1394 cairo_fill( context ); 1395 return; 1396 } 1397 1398 //__________________________________________________________________________________________________________ 1399 void StyleHelper::drawRoundSlab( Cairo::Context& context, const ColorUtils::Rgba& color, double shade ) const 1400 { 1401 1402 // colors 1403 const ColorUtils::Rgba base( ColorUtils::shade(color, shade) ); 1404 const ColorUtils::Rgba light( ColorUtils::shade( ColorUtils::lightColor(color), shade) ); 1405 1406 // bevel, part 1 1407 { 1408 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 10, 0, 18 ) ); 1409 cairo_pattern_add_color_stop( pattern, 0, light ); 1410 cairo_pattern_add_color_stop( pattern, 0.9, ColorUtils::alphaColor( light, 0.85 ) ); 1411 cairo_set_source( context, pattern ); 1412 cairo_ellipse( context, 3, 3, 15, 15 ); 1413 cairo_fill( context ); 1414 } 1415 1416 // bevel, part 2 1417 if( _slabThickness > 0 ) 1418 { 1419 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 7, 0, 28 ) ); 1420 cairo_pattern_add_color_stop( pattern, 0, light ); 1421 cairo_pattern_add_color_stop( pattern, 0.9, base ); 1422 cairo_set_source( context, pattern ); 1423 cairo_ellipse( context, 3.6, 3.6, 13.8, 13.8 ); 1424 cairo_fill( context ); 1425 } 1426 1427 // inside 1428 { 1429 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, -17, 0, 20 ) ); 1430 cairo_pattern_add_color_stop( pattern, 0, light ); 1431 cairo_pattern_add_color_stop( pattern, 1, base ); 1432 cairo_set_source( context, pattern ); 1433 1434 const double ic( 3.6 + _slabThickness ); 1435 const double is( 21 - 2.0*ic ); 1436 cairo_ellipse( context, ic, ic, is, is ); 1437 cairo_fill( context ); 1438 } 1439 1440 return; 1441 1442 } 1443 1444 //__________________________________________________________________________________________________________ 1445 void StyleHelper::drawSliderSlab( Cairo::Context& context, const ColorUtils::Rgba& color, bool sunken, double shade ) const 1446 { 1447 1448 const ColorUtils::Rgba light( ColorUtils::shade( ColorUtils::lightColor(color), shade) ); 1449 const ColorUtils::Rgba dark( ColorUtils::shade( ColorUtils::darkColor( color ), shade) ); 1450 1451 { 1452 //plain background 1453 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 3, 0, 21 ) ); 1454 cairo_pattern_add_color_stop( pattern, 0, light ); 1455 cairo_pattern_add_color_stop( pattern, 1, dark ); 1456 cairo_set_source( context, pattern ); 1457 cairo_ellipse( context, 3, 3, 15, 15 ); 1458 cairo_fill( context ); 1459 1460 } 1461 1462 if( sunken ) 1463 { 1464 1465 //plain background 1466 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 3, 0, 21 ) ); 1467 cairo_pattern_add_color_stop( pattern, 0, dark ); 1468 cairo_pattern_add_color_stop( pattern, 1, light ); 1469 cairo_set_source( context, pattern ); 1470 cairo_ellipse( context, 5, 5, 11, 11 ); 1471 cairo_fill( context ); 1472 1473 1474 } 1475 1476 { 1477 // outline circle 1478 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 3, 0, 30 ) ); 1479 cairo_pattern_add_color_stop( pattern, 0, light ); 1480 cairo_pattern_add_color_stop( pattern, 1, dark ); 1481 cairo_set_source( context, pattern ); 1482 1483 cairo_ellipse( context, 3.5, 3.5, 14, 14 ); 1484 cairo_set_line_width( context, 1.0 ); 1485 cairo_stroke( context ); 1486 } 1487 1488 return; 1489 1490 } 1491 1492 //________________________________________________________________________________________________________ 1493 cairo_pattern_t* StyleHelper::inverseShadowGradient( 1494 const ColorUtils::Rgba& base, 1495 int pad, int size, double fuzz ) const 1496 { 1497 1498 const double m( size*0.5 ); 1499 const double offset( 0.8 ); 1500 const double k0( (m-2) / (m+2.0) ); 1501 1502 const double x(pad+m); 1503 const double y(pad+m+offset); 1504 1505 cairo_pattern_t* pattern( cairo_pattern_create_radial(x, y, m+2 ) ); 1506 for (int i = 0; i < 8; i++) 1507 { 1508 // sinusoidal pattern 1509 const double k1( (8 - i + k0 * i) * 0.125 ); 1510 const double a( (cos(3.14159 * i * 0.125) + 1.0) * 0.25 ); 1511 cairo_pattern_add_color_stop( pattern, k1, ColorUtils::alphaColor( base, a*_shadowGain ) ); 1512 } 1513 1514 cairo_pattern_add_color_stop( pattern, k0, ColorUtils::Rgba::transparent( base ) ); 1515 return pattern; 1516 1517 } 1518 1519 1520 //________________________________________________________________________________________________________ 1521 const Cairo::Surface& StyleHelper::dockWidgetButton(const ColorUtils::Rgba& base, bool pressed, int size) 1522 { 1523 const DockWidgetButtonKey key( base, pressed, size ); 1524 1525 // try find in cache and return 1526 if( const Cairo::Surface& surface = _dockWidgetButtonCache.value(key) ) 1527 { return surface; } 1528 1529 // cached not found, create new 1530 Cairo::Surface surface( createSurface( size, size ) ); 1531 1532 Cairo::Context context( surface ); 1533 cairo_set_source( context, ColorUtils::Rgba::transparent( base ) ); 1534 cairo_paint( context ); 1535 1536 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 1537 const ColorUtils::Rgba dark( ColorUtils::darkColor( base ) ); 1538 1539 const double u( size/18.0 ); 1540 cairo_translate( context, 0.5*u, ( 0.5-0.668 )*u ); 1541 1542 { 1543 // outline circle 1544 double penWidth = 1.2; 1545 Cairo::Pattern lg( cairo_pattern_create_linear( 0, u*( 1.665-penWidth ), 0, u*( 12.33+1.665-penWidth ) ) ); 1546 1547 cairo_pattern_add_color_stop( lg, 0, dark ); 1548 cairo_pattern_add_color_stop( lg, 1, light ); 1549 cairo_set_source( context, lg ); 1550 cairo_set_line_width( context, penWidth*u ); 1551 cairo_ellipse( context, u*0.5*( 17-12.33+penWidth ), u*( 1.665+penWidth ), u*( 12.33-penWidth ), u*( 12.33-penWidth ) ); 1552 cairo_stroke( context ); 1553 } 1554 1555 return _dockWidgetButtonCache.insert(key, surface); 1556 } 1557 1558 1559 }