Warning, file /plasma/oxygen-gtk/src/oxygenstyle.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 SPDX-FileCopyrightText: 2010 Ruslan Kabatsayev <b7.10110111@gmail.com> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "oxygenstyle.h" 0010 #include "oxygencairocontext.h" 0011 #include "oxygencairoutils.h" 0012 #include "oxygencolorutils.h" 0013 #include "oxygenfontinfo.h" 0014 #include "oxygengtkutils.h" 0015 #include "oxygenmetrics.h" 0016 #include "oxygenwindecobutton.h" 0017 #include "oxygenwindowshadow.h" 0018 0019 #include "oxygengtktypenames.h" 0020 0021 #include <algorithm> 0022 #include <cmath> 0023 0024 #ifdef GDK_WINDOWING_X11 0025 #include <X11/Xatom.h> 0026 #endif 0027 0028 namespace Oxygen 0029 { 0030 0031 //__________________________________________________________________ 0032 Style* Style::_instance = 0; 0033 Style& Style::instance( void ) 0034 { 0035 if( !_instance ) 0036 { 0037 #if OXYGEN_DEBUG 0038 std::cerr << "Oxygen::Style::instance - creating new style." << std::endl; 0039 #endif 0040 0041 _instance = new Style(); 0042 } 0043 0044 return *_instance; 0045 } 0046 0047 //__________________________________________________________________ 0048 Style::Style( void ) 0049 { 0050 #ifdef GDK_WINDOWING_X11 0051 _blurAtom = None; 0052 #endif 0053 } 0054 0055 //__________________________________________________________________ 0056 bool Style::initialize( unsigned int flags ) 0057 { 0058 0059 // initialize ref surface 0060 _helper.initializeRefSurface(); 0061 0062 // reinitialize settings 0063 if( !_settings.initialize( flags ) ) return false; 0064 0065 // reset caches if colors have changed 0066 if( flags&QtSettings::Colors ) 0067 { 0068 _helper.clearCaches(); 0069 ColorUtils::clearCaches(); 0070 } 0071 0072 // connect files 0073 QtSettings::FileMap& monitoredFiles( _settings.monitoredFiles() ); 0074 for( QtSettings::FileMap::iterator iter = monitoredFiles.begin(); iter != monitoredFiles.end(); ++iter ) 0075 { 0076 if( !iter->second.signal.isConnected() ) 0077 { iter->second.signal.connect( G_OBJECT( iter->second.monitor ), "changed", G_CALLBACK(fileChanged), this ); } 0078 } 0079 0080 // reinitialize animations 0081 _animations.initialize( _settings ); 0082 0083 if( flags&QtSettings::Oxygen ) 0084 { 0085 0086 // widget explorer 0087 _widgetExplorer.setEnabled( _settings.widgetExplorerEnabled() ); 0088 0089 // pass window drag mode to window manager 0090 if( !_settings.windowDragEnabled() ) _windowManager.setDragMode( WindowManager::Disabled ); 0091 else if( _settings.windowDragMode() == QtSettings::WD_MINIMAL ) _windowManager.setDragMode( WindowManager::Minimal ); 0092 else _windowManager.setDragMode( WindowManager::Full ); 0093 0094 // use window manager to handle window drag 0095 _windowManager.setUseWMMoveResize( _settings.useWMMoveResize() ); 0096 0097 } 0098 0099 if( flags&QtSettings::KdeGlobals ) 0100 { 0101 // pass drag distance and delay to window manager 0102 _windowManager.setDragDistance( _settings.startDragDist() ); 0103 _windowManager.setDragDelay( _settings.startDragTime() ); 0104 } 0105 0106 // background surface 0107 if( !_settings.backgroundPixmap().empty() ) setBackgroundSurface( _settings.backgroundPixmap() ); 0108 0109 // create window shadow 0110 WindowShadow shadow( _settings, _helper ); 0111 _shadowHelper.setSupported( _settings.isWMShadowsSupported() ); 0112 _shadowHelper.setApplicationName( _settings.applicationName() ); 0113 _shadowHelper.initialize( _settings.palette().color(Palette::Window), shadow ); 0114 0115 #ifdef GDK_WINDOWING_X11 0116 if( _blurAtom == None ) 0117 { 0118 0119 GdkDisplay *display( gdk_display_get_default() ); 0120 if( display ) 0121 { _blurAtom = XInternAtom(GDK_DISPLAY_XDISPLAY( display ),"_KDE_NET_WM_BLUR_BEHIND_REGION",False); } 0122 0123 } 0124 0125 #endif 0126 0127 return true; 0128 0129 } 0130 0131 //__________________________________________________________________ 0132 Cairo::Surface Style::tabCloseButton( const StyleOptions& options ) 0133 { 0134 0135 // active tab 0136 if( options&Focus ) 0137 { 0138 // create button 0139 if( !_tabCloseButtons.active ) 0140 { 0141 const std::string filename( std::string(GTK_THEME_DIR)+ "/special-icons/standardbutton-closetab-down-16.png" ); 0142 _tabCloseButtons.active = Cairo::Surface( cairo_image_surface_create_from_png( filename.c_str() ) ); 0143 } 0144 0145 return _tabCloseButtons.active; 0146 } 0147 0148 // prelight 0149 if( options&Hover ) 0150 { 0151 // create button 0152 if( !_tabCloseButtons.prelight ) 0153 { 0154 const std::string filename( std::string(GTK_THEME_DIR) + "/special-icons/standardbutton-closetab-hover-16.png" ); 0155 _tabCloseButtons.prelight = Cairo::Surface( cairo_image_surface_create_from_png( filename.c_str() ) ); 0156 } 0157 0158 return _tabCloseButtons.prelight; 0159 0160 } 0161 0162 // normal or inactive 0163 if( !_tabCloseButtons.normal ) 0164 { 0165 const std::string filename( std::string(GTK_THEME_DIR) + "/special-icons/standardbutton-closetab-16.png" ); 0166 _tabCloseButtons.normal = Cairo::Surface( cairo_image_surface_create_from_png( filename.c_str() ) ); 0167 } 0168 0169 // inactive 0170 if( (options&Disabled) && _tabCloseButtons.normal ) 0171 { 0172 0173 if( !_tabCloseButtons.inactive ) 0174 { 0175 0176 // make deep copy of the normal image 0177 _tabCloseButtons.inactive = Cairo::Surface( cairo_surface_copy( _tabCloseButtons.normal ) ); 0178 cairo_surface_add_alpha( _tabCloseButtons.inactive, 0.5 ); 0179 cairo_image_surface_saturate( _tabCloseButtons.inactive, 0.1 ); 0180 0181 } 0182 0183 return _tabCloseButtons.inactive; 0184 0185 } 0186 0187 // fallback to normal 0188 return _tabCloseButtons.normal; 0189 0190 } 0191 0192 //____________________________________________________________________________________ 0193 bool Style::hasBackgroundSurface( void ) const 0194 { 0195 if( !_backgroundSurface.isValid() ) return false; 0196 const cairo_status_t status( cairo_surface_status( _backgroundSurface ) ); 0197 return 0198 status != CAIRO_STATUS_NO_MEMORY && 0199 status != CAIRO_STATUS_FILE_NOT_FOUND && 0200 status != CAIRO_STATUS_READ_ERROR; 0201 } 0202 0203 //__________________________________________________________________ 0204 void Style::fill( GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h, const ColorUtils::Rgba& color ) const 0205 { 0206 0207 // define colors 0208 Cairo::Context context( window, clipRect ); 0209 cairo_rectangle( context, x, y, w, h ); 0210 cairo_set_source( context, color ); 0211 cairo_fill( context ); 0212 0213 } 0214 0215 //__________________________________________________________________ 0216 void Style::outline( GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h, const ColorUtils::Rgba& color ) const 0217 { 0218 0219 // define colors 0220 Cairo::Context context( window, clipRect ); 0221 cairo_rectangle( context, 0.5+x, 0.5+y, w-1, h-1 ); 0222 cairo_set_line_width( context, 1 ); 0223 cairo_set_source( context, color ); 0224 cairo_stroke( context ); 0225 0226 } 0227 0228 //__________________________________________________________________ 0229 void Style::drawSeparator( GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h, const StyleOptions& options ) 0230 { 0231 0232 // define colors 0233 ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 0234 if( options & Blend ) 0235 { 0236 0237 gint wh, wy; 0238 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 0239 if( wh > 0 ) 0240 { 0241 if( options & Menu ) base = ColorUtils::menuBackgroundColor( _settings.palette().color( Palette::Window ), wh, y+wy+h/2 ); 0242 else base = ColorUtils::backgroundColor( _settings.palette().color( Palette::Window ), wh, y+wy+h/2 ); 0243 } 0244 0245 } 0246 0247 Cairo::Context context( window, clipRect ); 0248 _helper.drawSeparator( context, base, x, y, w, h, (options&Vertical) ); 0249 0250 } 0251 0252 //__________________________________________________________________ 0253 bool Style::renderWindowBackground( 0254 cairo_t* context, GdkWindow* window, GtkWidget* widget, 0255 GdkRectangle* clipRect, gint x, gint y, gint w, gint h, 0256 const StyleOptions& options, 0257 bool isMaximized ) 0258 { 0259 if( _settings.useBackgroundGradient() ) 0260 { 0261 0262 if( !renderBackgroundGradient( context, window, widget, clipRect, x, y, w, h, options, isMaximized ) ) 0263 { return false; } 0264 0265 } else { 0266 0267 ColorUtils::Rgba base( color( Palette::Window, options ) ); 0268 const bool needToDestroyContext( !context ); 0269 if( !context ) 0270 { 0271 0272 // create context 0273 context = gdk_cairo_create(window); 0274 0275 // set clip rect 0276 if( clipRect ) 0277 { 0278 cairo_rectangle(context,clipRect->x,clipRect->y,clipRect->width,clipRect->height); 0279 cairo_clip(context); 0280 } 0281 0282 } else cairo_save( context ); 0283 0284 cairo_set_source(context,base); 0285 cairo_rectangle(context,x,y,w,h); 0286 cairo_fill(context); 0287 0288 if( needToDestroyContext ) 0289 { 0290 cairo_destroy(context); 0291 context = 0; 0292 } 0293 else cairo_restore(context); 0294 0295 } 0296 0297 // background pixmap 0298 if( hasBackgroundSurface() ) 0299 { renderBackgroundPixmap( context, window, widget, clipRect, x, y, w, h, isMaximized ); } 0300 0301 return true; 0302 0303 } 0304 0305 //__________________________________________________________________ 0306 bool Style::renderBackgroundGradient( 0307 cairo_t* context, GdkWindow* window, GtkWidget* widget, 0308 GdkRectangle* clipRect, gint x, gint y, gint w, gint h, 0309 const StyleOptions& options, 0310 bool isMaximized ) 0311 { 0312 0313 // define colors 0314 ColorUtils::Rgba base( color( Palette::Window, options ) ); 0315 bool renderingWindeco(context && !window); 0316 0317 // the hard-coded metrics are copied for 0318 // kdebase/workspace/libs/oxygen/oxygenhelper.cpp 0319 // vertical shift to account for window decoration 0320 const int yShift = 23; 0321 0322 // toplevel window information and relative positioning 0323 gint ww(0), wh(0); 0324 gint wx(0), wy(0); 0325 0326 // if we aren't going to draw window decorations... 0327 bool needToDestroyContext( false ); 0328 if( renderingWindeco ) 0329 { 0330 // drawing window decorations, so logic is simplified 0331 ww=w; 0332 wh=h; 0333 cairo_save(context); 0334 cairo_translate(context,x,y); 0335 x=0; 0336 y=0; 0337 0338 } else { 0339 0340 0341 if( !context ) 0342 { 0343 // create context and translate to toplevel coordinates 0344 // make it the old good way since context is cairo_t* instead Cairo::Context 0345 context = gdk_cairo_create(window); 0346 needToDestroyContext=true; 0347 0348 if( clipRect ) 0349 { 0350 cairo_rectangle(context,clipRect->x,clipRect->y,clipRect->width,clipRect->height); 0351 cairo_clip(context); 0352 } 0353 0354 } else cairo_save( context ); 0355 0356 // get window dimension and position 0357 // paint flat background when mapping failed 0358 if( !Gtk::gdk_map_to_toplevel( window, widget, &wx, &wy, &ww, &wh, true ) ) 0359 { 0360 0361 #if OXYGEN_DEBUG 0362 std::cerr << "Oxygen::Style::renderBackgroundGradient - map_to_toplevel failed" << std::endl; 0363 std::cerr << "original xywh: ("<<x<<","<<y<<","<<w<<","<<h<<")\n"; 0364 #endif 0365 0366 if( _settings.applicationName().isOpenOffice() && GTK_IS_WINDOW(widget)) 0367 { 0368 gtk_window_get_size(GTK_WINDOW(widget),&ww,&wh); 0369 wx=0; 0370 wy=0; 0371 cairo_translate(context,x,y); 0372 if(clipRect) 0373 { 0374 #if OXYGEN_DEBUG 0375 std::cerr << "original clipRect: " << *clipRect << std::endl; 0376 #endif 0377 clipRect->x-=x; 0378 clipRect->y-=y; 0379 clipRect->width-=x; 0380 clipRect->height-=y; 0381 } 0382 x=y=0; 0383 #if OXYGEN_DEBUG 0384 std::cerr <<"Oxygen::Style::renderBackgroundGradient - setting openoffice-specific coords:"<<wx<<","<<wy<<","<<ww<<","<<wh<<"\n\n"; 0385 #endif 0386 } 0387 else 0388 { 0389 // flat painting for all other apps 0390 cairo_set_source(context,base); 0391 cairo_rectangle(context,x,y,w,h); 0392 cairo_fill(context); 0393 if( needToDestroyContext ) cairo_destroy(context); 0394 else cairo_restore(context); 0395 return false; 0396 } 0397 0398 } 0399 0400 // translate to toplevel coordinates 0401 wy += yShift; 0402 x+=wx; 0403 y+=wy; 0404 0405 // no sense in context saving since it will be destroyed 0406 cairo_translate( context, -wx, -wy ); 0407 0408 } 0409 0410 if(options&DrawAlphaChannel) 0411 { 0412 base.setAlpha(_settings.backgroundOpacity()/255.); 0413 cairo_set_operator(context,CAIRO_OPERATOR_SOURCE); 0414 } 0415 0416 // split 0417 const int splitY( std::min(300, 3*wh/4 ) ); 0418 0419 // store rectangle 0420 GdkRectangle rect = { x, y, w, h }; 0421 0422 /* 0423 if there is a valid clipRect, 0424 intersects it with painting Rect, for performances 0425 */ 0426 if( clipRect ) 0427 { 0428 0429 GdkRectangle localClip( *clipRect ); 0430 localClip.x += wx; 0431 localClip.y += wy; 0432 gdk_rectangle_intersect( &rect, &localClip, &rect ); 0433 0434 } 0435 0436 // upper rect 0437 GdkRectangle upperRect = { 0, 0, ww, splitY }; 0438 if( gdk_rectangle_intersect( &rect, &upperRect, &upperRect ) ) 0439 { 0440 0441 const Cairo::Surface& surface( _helper.verticalGradient( base, splitY ) ); 0442 cairo_set_source_surface( context, surface, 0, 0 ); 0443 cairo_pattern_set_extend( cairo_get_source( context ), CAIRO_EXTEND_REPEAT ); 0444 gdk_cairo_rectangle( context, &upperRect ); 0445 cairo_fill( context ); 0446 0447 } 0448 0449 // fill lower rect 0450 GdkRectangle lowerRect = { 0, splitY, ww, wh - splitY + yShift }; 0451 if( gdk_rectangle_intersect( &rect, &lowerRect, &lowerRect ) ) 0452 { 0453 0454 ColorUtils::Rgba bottom( ColorUtils::backgroundBottomColor( base ) ); 0455 gdk_cairo_rectangle( context, &lowerRect ); 0456 cairo_set_source( context, bottom ); 0457 cairo_fill( context ); 0458 0459 } 0460 0461 // gradient should be rendered with full opacity 0462 base.setAlpha(1); 0463 cairo_set_operator(context,CAIRO_OPERATOR_OVER); 0464 0465 // radial pattern 0466 const int patternHeight = 64; 0467 const int radialW( std::min(600, ww ) ); 0468 0469 GdkRectangle radialRect = { (ww - radialW)/2, 0, radialW, patternHeight }; 0470 if( gdk_rectangle_intersect( &rect, &radialRect, &radialRect ) ) 0471 { 0472 0473 const Cairo::Surface& surface( _helper.radialGradient( base, 64 ) ); 0474 cairo_set_source_surface( context, surface, 0, 0 ); 0475 0476 // add matrix transformation 0477 cairo_matrix_t transformation; 0478 cairo_matrix_init_identity( &transformation ); 0479 cairo_matrix_scale( &transformation, 128.0/radialW, 1.0 ); 0480 cairo_matrix_translate( &transformation, -(ww - radialW)/2, 0 ); 0481 cairo_pattern_set_matrix( cairo_get_source( context ), &transformation ); 0482 0483 gdk_cairo_rectangle( context, &radialRect ); 0484 cairo_fill( context ); 0485 0486 } 0487 0488 if(needToDestroyContext) cairo_destroy(context); 0489 else cairo_restore(context); 0490 0491 return true; 0492 0493 } 0494 0495 //__________________________________________________________________ 0496 bool Style::renderBackgroundPixmap( 0497 cairo_t* context, GdkWindow* window, GtkWidget* widget, 0498 GdkRectangle* clipRect, gint x, gint y, gint w, gint h, 0499 bool isMaximized ) 0500 { 0501 0502 // define colors 0503 bool renderingWindeco(context && !window); 0504 0505 // the hard-coded metrics are copied for 0506 // kdebase/workspace/libs/oxygen/oxygenhelper.cpp 0507 // vertical shift to account for window decoration 0508 const int yShift = 23; 0509 0510 // toplevel window information and relative positioning 0511 gint ww(0), wh(0); 0512 gint wx(0), wy(0); 0513 0514 // if we aren't going to draw window decorations... 0515 bool needToDestroyContext( false ); 0516 if( renderingWindeco ) 0517 { 0518 // drawing window decorations, so logic is simplified 0519 ww=w; 0520 wh=h; 0521 cairo_save(context); 0522 cairo_translate(context,x,y); 0523 x=0; 0524 y=0; 0525 0526 } else { 0527 0528 if( !context ) 0529 { 0530 // create context and translate to toplevel coordinates 0531 // make it the old good way since context is cairo_t* instead Cairo::Context 0532 context = gdk_cairo_create(window); 0533 needToDestroyContext=true; 0534 0535 if( clipRect ) 0536 { 0537 cairo_rectangle(context,clipRect->x,clipRect->y,clipRect->width,clipRect->height); 0538 cairo_clip(context); 0539 } 0540 0541 } else cairo_save( context ); 0542 0543 // get window dimension and position 0544 // paint flat background when mapping failed 0545 if( !Gtk::gdk_map_to_toplevel( window, widget, &wx, &wy, &ww, &wh, true ) ) 0546 { 0547 if( needToDestroyContext ) cairo_destroy(context); 0548 else cairo_restore(context); 0549 return false; 0550 } 0551 0552 // translate to toplevel coordinates 0553 wy += yShift; 0554 x+=wx; 0555 y+=wy; 0556 0557 // no sense in context saving since it will be destroyed 0558 cairo_translate( context, -wx, -wy ); 0559 0560 } 0561 0562 // store rectangle 0563 GdkRectangle rect = { x, y, w, h }; 0564 0565 /* 0566 if there is a valid clipRect, 0567 intersects it with painting Rect, for performances 0568 */ 0569 if( clipRect ) 0570 { 0571 0572 GdkRectangle localClip( *clipRect ); 0573 localClip.x += wx; 0574 localClip.y += wy; 0575 gdk_rectangle_intersect( &rect, &localClip, &rect ); 0576 0577 } 0578 0579 // Additional clip constraint so that no extra space is filled (important for LibreOffice) 0580 cairo_rectangle(context,x,y,w,h); 0581 cairo_clip(context); 0582 0583 if(renderingWindeco) 0584 { 0585 // Take border sizes into account 0586 int bgShiftX=isMaximized?0:WinDeco::getMetric(WinDeco::BorderLeft); 0587 int bgShiftY=WinDeco::getMetric(WinDeco::BorderTop)-yShift; 0588 cairo_translate(context,bgShiftX,bgShiftY); 0589 } 0590 0591 // no sense in context saving since it will be either destroyed or restored to earlier state 0592 cairo_translate( context, -40, -(48-20) ); 0593 cairo_set_source_surface( context, _backgroundSurface, 0, 0 ); 0594 cairo_rectangle( context, 0, 0, ww + wx + 40, wh + wy + 48 - 20 ); 0595 cairo_fill( context ); 0596 0597 if(needToDestroyContext) cairo_destroy(context); 0598 else cairo_restore(context); 0599 0600 return true; 0601 0602 } 0603 0604 //__________________________________________________________________ 0605 bool Style::renderGroupBoxBackground( 0606 cairo_t* context, 0607 GdkWindow* window, GtkWidget* widget, 0608 GdkRectangle* clipRect, gint x, gint y, gint w, gint h, 0609 const StyleOptions& options, 0610 TileSet::Tiles tiles ) 0611 { 0612 0613 // find groupbox parent 0614 GtkWidget* parent( Gtk::gtk_parent_groupbox( widget ) ); 0615 if( !( parent && _animations.groupBoxEngine().contains( parent ) ) ) return false; 0616 0617 // toplevel window information and relative positioning 0618 gint ww(0), wh(0); 0619 gint wx(0), wy(0); 0620 0621 // map to parent 0622 if( !Gtk::gtk_widget_map_to_parent( widget, parent, &wx, &wy, &ww, &wh ) ) 0623 { return false; } 0624 0625 // create context and translate 0626 bool needToDestroyContext( false ); 0627 if( !context ) 0628 { 0629 // create context and translate to toplevel coordinates 0630 // make it the old good way since context is cairo_t* instead Cairo::Context 0631 context = gdk_cairo_create(window); 0632 needToDestroyContext=true; 0633 0634 if( clipRect ) 0635 { 0636 cairo_rectangle(context,clipRect->x,clipRect->y,clipRect->width,clipRect->height); 0637 cairo_clip(context); 0638 } 0639 0640 } else cairo_save( context ); 0641 0642 const int margin( 1 ); 0643 wh += 2*margin; 0644 ww += 2*margin; 0645 x+=wx; 0646 y+=wy; 0647 cairo_translate( context, -wx, -wy ); 0648 0649 // define colors 0650 ColorUtils::Rgba base; 0651 if( options&Blend ) 0652 { 0653 0654 gint wwh, wwy; 0655 Gtk::gtk_widget_map_to_toplevel( parent, 0L, &wwy, 0L, &wwh ); 0656 base = ColorUtils::backgroundColor( _settings.palette().color( Palette::Window ), wwh, wwy-1+wh/2 ); 0657 0658 } else { 0659 0660 base = _settings.palette().color( Palette::Window ); 0661 0662 } 0663 0664 const int xGroupBox = x - wx - margin; 0665 const int yGroupBox = y - wy - margin; 0666 renderGroupBox( context, base, xGroupBox, yGroupBox, ww, wh, options ); 0667 0668 if(needToDestroyContext) cairo_destroy(context); 0669 else cairo_restore(context); 0670 0671 return true; 0672 0673 } 0674 0675 //__________________________________________________________________ 0676 bool Style::renderMenuBackground( GdkWindow* window, Cairo::Context& context, gint x, gint y, gint w, gint h, const StyleOptions& options ) const 0677 { 0678 // define colors 0679 ColorUtils::Rgba base( color( Palette::Window, options ) ); 0680 ColorUtils::Rgba top( ColorUtils::backgroundTopColor( base ) ); 0681 ColorUtils::Rgba bottom( ColorUtils::backgroundBottomColor( base ) ); 0682 0683 // get window dimension and position 0684 gint ww, wh; 0685 gint wx, wy; 0686 if( !Gtk::gdk_map_to_toplevel( window, 0L, &wx, &wy, &ww, &wh, true ) ) 0687 { return false; } 0688 0689 // translate to toplevel coordinates 0690 x+=wx; 0691 y+=wy; 0692 0693 cairo_translate( context, -wx, -wy ); 0694 const bool hasAlpha( options&Alpha ); 0695 const bool isMenu( options&Menu ); 0696 const bool round( options&Round ); 0697 0698 GdkRectangle rect = { x, y, w, h }; 0699 0700 // paint translucent first 0701 if( hasAlpha ) 0702 { 0703 cairo_rectangle( context, 0, 0, ww, wh ); 0704 cairo_set_operator( context, CAIRO_OPERATOR_SOURCE ); 0705 cairo_set_source( context, ColorUtils::alphaColor( base, 0 ) ); 0706 cairo_fill( context ); 0707 0708 if(_settings.backgroundOpacity()<255) 0709 { 0710 double opacity(_settings.backgroundOpacity()/255.); 0711 top.setAlpha(opacity); 0712 bottom.setAlpha(opacity); 0713 } 0714 } 0715 0716 const int splitY( std::min(200, 3*wh/4 ) ); 0717 const int verticalOffset( (isMenu && round) ? Menu_VerticalOffset:0 ); 0718 0719 GdkRectangle upperRect = { 0, verticalOffset, ww, splitY - verticalOffset }; 0720 if( gdk_rectangle_intersect( &rect, &upperRect, &upperRect ) ) 0721 { 0722 // upper rect 0723 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 0, 0, splitY ) ); 0724 cairo_pattern_add_color_stop( pattern, 0, top ); 0725 cairo_pattern_add_color_stop( pattern, 1, bottom ); 0726 0727 gdk_cairo_rounded_rectangle( context, &upperRect, 3.5, round ? CornersTop:CornersNone ); 0728 cairo_set_source( context, pattern ); 0729 cairo_fill( context ); 0730 0731 } 0732 0733 GdkRectangle lowerRect = { 0, splitY, ww, wh-splitY - verticalOffset }; 0734 if( gdk_rectangle_intersect( &rect, &lowerRect, &lowerRect ) ) 0735 { 0736 0737 // lower part 0738 gdk_cairo_rounded_rectangle( context, &lowerRect, 3.5, round ? CornersBottom:CornersNone ); 0739 cairo_set_source( context, bottom ); 0740 cairo_fill( context ); 0741 0742 } 0743 0744 return true; 0745 0746 } 0747 0748 //__________________________________________________________________ 0749 void Style::renderTooltipBackground( GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h, const StyleOptions& options ) const 0750 { 0751 0752 // define colors 0753 ColorUtils::Rgba base(_settings.palette().color( Palette::Tooltip ) ); 0754 ColorUtils::Rgba top( ColorUtils::backgroundTopColor( base ) ); 0755 ColorUtils::Rgba bottom( ColorUtils::backgroundBottomColor( base ) ); 0756 0757 // create context and translate 0758 Cairo::Context context( window, clipRect ); 0759 cairo_translate( context, x, y ); 0760 0761 // paint translucent first 0762 const bool hasAlpha( (options&Alpha) ); 0763 bool round( GDK_IS_WINDOW( window ) && (options&Round) ); 0764 0765 if( hasAlpha ) 0766 { 0767 if( _settings.tooltipTransparent() ) 0768 { 0769 top.setAlpha( 0.86 ); 0770 bottom.setAlpha( 0.86 ); 0771 } 0772 0773 cairo_rectangle( context, 0, 0, w, h ); 0774 cairo_set_operator( context, CAIRO_OPERATOR_SOURCE ); 0775 cairo_set_source( context, ColorUtils::alphaColor( base, 0 ) ); 0776 cairo_fill( context ); 0777 } 0778 0779 // fill 0780 { 0781 GdkRectangle rect = { 0, 0, w, h }; 0782 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 0, 0, h ) ); 0783 cairo_pattern_add_color_stop( pattern, 0, top ); 0784 cairo_pattern_add_color_stop( pattern, 1, bottom ); 0785 0786 gdk_cairo_rounded_rectangle( context, &rect, 3.5, round ? CornersAll:CornersNone ); 0787 cairo_set_source( context, pattern ); 0788 cairo_fill( context ); 0789 0790 } 0791 0792 // contrast pixel 0793 { 0794 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 0, 0, h ) ); 0795 cairo_pattern_add_color_stop( pattern, 0.5, ColorUtils::lightColor( bottom ) ); 0796 cairo_pattern_add_color_stop( pattern, 0.9, bottom ); 0797 0798 cairo_rounded_rectangle( context, 0.5, 0.5, w-1, h-1, 3.5, round ? CornersAll:CornersNone ); 0799 cairo_set_line_width( context, 1.0 ); 0800 cairo_set_source( context, pattern ); 0801 cairo_stroke( context ); 0802 } 0803 0804 return; 0805 0806 } 0807 0808 //__________________________________________________________________ 0809 void Style::renderHeaderBackground( GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h ) 0810 { 0811 0812 // load color 0813 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 0814 0815 // render normal window background 0816 renderWindowBackground( window, clipRect, x, y, w, h ); 0817 0818 // render lines 0819 renderHeaderLines( window, clipRect, x, y, w, h ); 0820 0821 // render side dots 0822 Cairo::Context context( window, clipRect ); 0823 int yCenter( y + h/2 ); 0824 int xDots( x + w - 1 ); 0825 _helper.renderDot( context, base, xDots, yCenter - 3 ); 0826 _helper.renderDot( context, base, xDots, yCenter ); 0827 _helper.renderDot( context, base, xDots, yCenter + 3 ); 0828 0829 } 0830 0831 0832 //__________________________________________________________________ 0833 void Style::renderHeaderLines( GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h ) const 0834 { 0835 0836 // add horizontal lines 0837 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 0838 const ColorUtils::Rgba dark( ColorUtils::darkColor( base ) ); 0839 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 0840 0841 Cairo::Context context( window, clipRect ); 0842 cairo_set_line_width( context, 1.0 ); 0843 0844 // dark line 0845 cairo_set_source( context, dark ); 0846 cairo_move_to( context, x, y+h-0.5 ); 0847 cairo_line_to( context, x+w, y+h-0.5 ); 0848 cairo_stroke( context ); 0849 0850 // light line 0851 cairo_set_source( context, light ); 0852 cairo_move_to( context, x, y+h-1.5 ); 0853 cairo_line_to( context, x+w, y+h-1.5 ); 0854 cairo_stroke( context ); 0855 0856 } 0857 0858 //____________________________________________________________________________________ 0859 void Style::renderTreeLines( GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h, const Gtk::CellInfoFlags& cellFlags, const StyleOptions& options ) const 0860 { 0861 0862 // define pen color 0863 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 0864 const ColorUtils::Rgba base( ColorUtils::mix( 0865 _settings.palette().color( group, Palette::Text ), 0866 _settings.palette().color( group, Palette::Window ), 0867 0.8 ) ); 0868 0869 Cairo::Context context( window, clipRect ); 0870 cairo_set_source( context, base ); 0871 cairo_set_line_width( context, 1.0 ); 0872 0873 const bool reversed( cellFlags._flags & Gtk::CellInfoFlags::Reversed ); 0874 0875 int cellIndent( cellFlags._levelIndent + cellFlags._expanderSize + 4 ); 0876 int xStart( x + cellIndent/2 ); 0877 0878 if( reversed ) { 0879 0880 xStart += w - cellIndent; 0881 cellIndent *= -1; 0882 0883 } 0884 0885 for( unsigned int i=0; i< cellFlags._depth; ++i ) 0886 { 0887 0888 const bool isLastCell( cellFlags._isLast[i] ); 0889 const bool last( i == cellFlags._depth -1 ); 0890 double xCenter = xStart; 0891 0892 if( last ) 0893 { 0894 0895 double yCenter = int(y+h/2); 0896 const bool hasChildren( cellFlags._flags & Gtk::CellInfoFlags::HasChildren ); 0897 0898 if( hasChildren ) 0899 { 0900 // first vertical line 0901 cairo_move_to( context, xCenter + 0.5 , y ); 0902 cairo_line_to( context, xCenter + 0.5, yCenter - int(cellFlags._expanderSize/3 )-1 ); 0903 0904 // second vertical line 0905 if( !isLastCell ) 0906 { 0907 0908 cairo_move_to( context, xCenter + 0.5, y+h ); 0909 cairo_line_to( context, xCenter + 0.5, yCenter + int( cellFlags._expanderSize/3 )+2 ); 0910 } 0911 0912 // horizontal line 0913 if( reversed ) 0914 { 0915 0916 cairo_move_to( context, xCenter - 1 - int( cellFlags._expanderSize/3 ), yCenter + 0.5 ); 0917 cairo_line_to( context, xCenter + 1 - cellFlags._expanderSize*2/3, yCenter + 0.5 ); 0918 0919 } else { 0920 0921 cairo_move_to( context, xCenter + 2 + int( cellFlags._expanderSize/3 ), yCenter + 0.5 ); 0922 cairo_line_to( context, xCenter + cellFlags._expanderSize*2/3, yCenter + 0.5 ); 0923 0924 } 0925 0926 } else { 0927 0928 // vertical line 0929 cairo_move_to( context, xCenter + 0.5, y ); 0930 if( isLastCell ) cairo_line_to( context, xCenter + 0.5, yCenter ); 0931 else cairo_line_to( context, xCenter + 0.5, y+h ); 0932 0933 // horizontal line 0934 if( reversed ) 0935 { 0936 0937 cairo_move_to( context, xCenter + 1 , yCenter + 0.5 ); 0938 cairo_line_to( context, xCenter + 1 - cellFlags._expanderSize*2/3, yCenter + 0.5 ); 0939 0940 } else { 0941 0942 cairo_move_to( context, xCenter, yCenter + 0.5 ); 0943 cairo_line_to( context, xCenter + cellFlags._expanderSize*2/3, yCenter + 0.5 ); 0944 0945 } 0946 0947 } 0948 0949 } else if( !isLastCell ) { 0950 0951 0952 // vertical line 0953 cairo_move_to( context, xCenter + 0.5, y ); 0954 cairo_line_to( context, xCenter + 0.5, y + h ); 0955 0956 } 0957 0958 // render 0959 cairo_stroke( context ); 0960 0961 // increment 0962 xStart += cellIndent; 0963 0964 } 0965 0966 return; 0967 } 0968 0969 //____________________________________________________________________________________ 0970 void Style::renderHoleBackground( 0971 GdkWindow* window, 0972 GtkWidget* widget, 0973 GdkRectangle* clipRect, 0974 gint x, gint y, gint w, gint h, const StyleOptions& options, TileSet::Tiles tiles, 0975 gint sideMargin ) 0976 { 0977 0978 // do nothing if not enough room 0979 if( w < 14 || h < 14 ) return; 0980 0981 // add hole mask 0982 Cairo::Context context( window, clipRect ); 0983 renderHoleMask( context, x, y, w, h, tiles, sideMargin ); 0984 0985 if( (options&Flat) || _settings.applicationName().useFlatBackground( widget ) ) 0986 { 0987 0988 // create a rounded-rect antimask for renderHoleBackground 0989 cairo_set_source( context, _settings.palette().color( Palette::Window ) ); 0990 cairo_rectangle( context, x, y, w, h ); 0991 cairo_fill( context ); 0992 0993 } else if( GtkWidget* parent = _animations.flatWidgetEngine().flatParent( widget ) ) { 0994 0995 // get background color and fill 0996 if( Gtk::gtk_widget_style_is_modified( parent, GTK_STATE_NORMAL, GTK_RC_BG ) ) 0997 { 0998 0999 cairo_set_source( context, Gtk::gdk_get_color( gtk_widget_get_modifier_style( parent )->bg[GTK_STATE_NORMAL] ) ); 1000 1001 } else { 1002 1003 cairo_set_source( context, _settings.palette().color( Palette::Window ) ); 1004 1005 } 1006 1007 cairo_rectangle( context, x, y, w, h ); 1008 cairo_fill( context ); 1009 1010 } else { 1011 1012 // normal window background 1013 renderWindowBackground( context, window, 0L, clipRect, x, y, w, h, options, tiles); 1014 1015 // possible groupbox background 1016 // Pass NoFill option in order not to render the surrounding frame 1017 if( widget ) 1018 { renderGroupBoxBackground( context, window, widget, clipRect, x, y, w, h, options | Blend | NoFill, tiles ); } 1019 1020 } 1021 1022 } 1023 1024 //__________________________________________________________________ 1025 void Style::renderSplitter( 1026 GdkWindow* window, GdkRectangle* clipRect, 1027 gint x, gint y, gint w, gint h, 1028 const StyleOptions& options, 1029 const AnimationData& data ) const 1030 { 1031 1032 // orientation 1033 const bool vertical( options&Vertical ); 1034 1035 // colors 1036 const ColorUtils::Rgba& base( _settings.palette().color( Palette::Window ) ); 1037 1038 // context 1039 Cairo::Context context( window, clipRect ); 1040 1041 // hover color 1042 ColorUtils::Rgba highlight; 1043 if( data._mode == AnimationHover ) 1044 { 1045 1046 highlight = ColorUtils::alphaColor( ColorUtils::lightColor( base ), 0.5*data._opacity ); 1047 1048 } else if( options&Hover ) { 1049 1050 highlight = ColorUtils::alphaColor( ColorUtils::lightColor( base ), 0.5 ); 1051 1052 } 1053 1054 // render hover rect 1055 if( highlight.isValid() ) 1056 { 1057 1058 Cairo::Context context( window, clipRect ); 1059 Cairo::Pattern pattern; 1060 double a(0.1); 1061 if( vertical ) 1062 { 1063 1064 if( w > 30 ) a = 10.0/w; 1065 pattern.set( cairo_pattern_create_linear( x, 0, x+w, 0 ) ); 1066 1067 } else { 1068 1069 if( h>30 ) a = 10.0/h; 1070 pattern.set( cairo_pattern_create_linear( 0, y, 0, y+h ) ); 1071 1072 } 1073 1074 cairo_pattern_add_color_stop( pattern, 0, ColorUtils::alphaColor( highlight, 0 ) ); 1075 cairo_pattern_add_color_stop( pattern, a, highlight ); 1076 cairo_pattern_add_color_stop( pattern, 1.0-a, highlight ); 1077 cairo_pattern_add_color_stop( pattern, 1.0, ColorUtils::alphaColor( highlight, 0 ) ); 1078 1079 cairo_set_source( context, pattern ); 1080 cairo_rectangle( context, x, y, w, h ); 1081 cairo_fill( context ); 1082 } 1083 1084 // dots 1085 if( vertical ) 1086 { 1087 1088 y += h/2; 1089 const int ngroups( std::max( 1, w/250 ) ); 1090 int center = ( w-( ngroups-1 )*250 )/2 + x; 1091 for( int k = 0; k < ngroups; k++, center += 250 ) 1092 { 1093 _helper.renderDot( context, base, center-3, y ); 1094 _helper.renderDot( context, base, center, y ); 1095 _helper.renderDot( context, base, center+3, y ); 1096 } 1097 1098 } else { 1099 1100 x += w/2; 1101 const int ngroups( std::max( 1, h/250 ) ); 1102 int center = ( h-( ngroups-1 )*250 )/2 + y; 1103 for( int k = 0; k < ngroups; k++, center += 250 ) 1104 { 1105 _helper.renderDot( context, base, x, center-3 ); 1106 _helper.renderDot( context, base, x, center ); 1107 _helper.renderDot( context, base, x, center+3 ); 1108 } 1109 1110 } 1111 1112 } 1113 1114 //____________________________________________________________________________________ 1115 void Style::renderProgressBarHole( 1116 GdkWindow* window, 1117 GdkRectangle* clipRect, 1118 gint x, gint y, gint w, gint h, const StyleOptions& options ) 1119 { 1120 1121 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 1122 const ColorUtils::Rgba base(_settings.palette().color( group, Palette::Window ) ); 1123 1124 Cairo::Context context( window, clipRect ); 1125 renderScrollBarHole( context, x, y, w, h, base, (options&Vertical) ); 1126 1127 } 1128 1129 //____________________________________________________________________________________ 1130 void Style::renderProgressBarHandle( 1131 GdkWindow* window, 1132 GdkRectangle* clipRect, 1133 gint x, gint y, gint w, gint h, const StyleOptions& options ) 1134 { 1135 1136 // colors 1137 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 1138 const ColorUtils::Rgba base( _settings.palette().color( Palette::Active, Palette::Window ) ); 1139 const ColorUtils::Rgba glow( _settings.palette().color( group, Palette::Selected ) ); 1140 1141 // context 1142 Cairo::Context context( window, clipRect ); 1143 1144 // validate rect 1145 if(w<0 || h<0) return; 1146 1147 // make sure that width is large enough 1148 const int indicatorSize( (options&Vertical ? h:w ) ); 1149 1150 if( indicatorSize >= 3 && w > 0 && h > 1 ) 1151 { 1152 // get surface 1153 const Cairo::Surface& surface( _helper.progressBarIndicator( base, glow, w, h-1 ) ); 1154 cairo_translate( context, x, y ); 1155 cairo_rectangle( context, 0, 0, w, h-1 ); 1156 cairo_set_source_surface( context, surface, 0, 0 ); 1157 cairo_fill( context ); 1158 } 1159 1160 } 1161 1162 //____________________________________________________________________________________ 1163 void Style::renderScrollBarHole( 1164 GdkWindow* window, 1165 GdkRectangle* clipRect, 1166 gint x, gint y, gint w, gint h, const StyleOptions& options ) 1167 { 1168 1169 // colors 1170 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 1171 const ColorUtils::Rgba base(_settings.palette().color( group, Palette::Window ) ); 1172 1173 // context 1174 Cairo::Context context( window, clipRect ); 1175 renderScrollBarHole( context, x, y, w, h, base, options&Vertical ); 1176 1177 } 1178 1179 //____________________________________________________________________________________ 1180 void Style::renderHoleMask( cairo_t* context, gint x, gint y, gint w, gint h, TileSet::Tiles tiles, gint sideMargin ) 1181 { 1182 1183 GdkRectangle mask = {x+2, y+1, w-4, h-3 }; 1184 const double maskRadius = 3.5; 1185 Corners corners( CornersNone ); 1186 if( tiles & TileSet::Left ) 1187 { 1188 mask.x += sideMargin; 1189 mask.width -= sideMargin; 1190 if( tiles & TileSet::Top ) corners |= CornersTopLeft; 1191 if( tiles & TileSet::Bottom ) corners |= CornersBottomLeft; 1192 } 1193 1194 if( tiles & TileSet::Right ) 1195 { 1196 mask.width -= sideMargin; 1197 if( tiles & TileSet::Top ) corners |= CornersTopRight; 1198 if( tiles & TileSet::Bottom ) corners |= CornersBottomRight; 1199 } 1200 1201 // set clipping mask 1202 gdk_cairo_rounded_rectangle_negative(context,&mask,maskRadius,CornersAll); 1203 cairo_rectangle(context,x,y,w,h); 1204 cairo_clip(context); 1205 1206 return; 1207 1208 } 1209 1210 //____________________________________________________________________________________ 1211 void Style::renderScrollBarHandle( 1212 GdkWindow* window, 1213 GdkRectangle* clipRect, 1214 gint x, gint y, gint w, gint h, 1215 const StyleOptions& options, 1216 const AnimationData& data ) 1217 { 1218 1219 // vertical 1220 const bool vertical( options&Vertical ); 1221 1222 const double xf( vertical ? x+3 : x+4 ); 1223 const double yf( vertical ? y+3 : y+2 ); 1224 const double wf( vertical ? w-6 : w-8 ); 1225 const double hf( vertical ? h-6 : h-5 ); 1226 1227 // const double xf( vertical ? x+2 : x+3 ); 1228 // const double yf( vertical ? y+2 : y+1 ); 1229 // const double wf( vertical ? w-4 : w-6 ); 1230 // const double hf( vertical ? h-4 : h-3 ); 1231 1232 if( wf <= 0 || hf <= 0 ) return; 1233 1234 // context 1235 Cairo::Context context( window, clipRect ); 1236 1237 // store colors 1238 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 1239 const ColorUtils::Rgba color( _settings.palette().color( group, Palette::Button ) ); 1240 1241 const double radius( 3.5 ); 1242 1243 // glow color 1244 ColorUtils::Rgba glow; 1245 const ColorUtils::Rgba shadow( ColorUtils::alphaColor( ColorUtils::shadowColor( color ), 0.4 ) ); 1246 const ColorUtils::Rgba hovered( _settings.palette().color( Palette::Hover ) ); 1247 if( data._mode == AnimationHover ) glow = ColorUtils::mix( shadow, hovered, data._opacity ); 1248 else if( options&Hover ) glow = hovered; 1249 else glow = shadow; 1250 1251 _helper.scrollHandle( color, glow ).render( context, xf-3, yf-3, wf+6, hf+6, TileSet::Full ); 1252 1253 // contents 1254 const ColorUtils::Rgba mid( ColorUtils::midColor( color ) ); 1255 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, yf, 0, yf+hf ) ); 1256 cairo_pattern_add_color_stop( pattern, 0, color ); 1257 cairo_pattern_add_color_stop( pattern, 1, mid ); 1258 cairo_set_source( context, pattern ); 1259 cairo_rounded_rectangle( context, xf+1, yf+1, wf-2, hf-2, radius - 2 ); 1260 cairo_fill( context ); 1261 1262 // bevel pattern 1263 { 1264 const ColorUtils::Rgba light( ColorUtils::lightColor( color ) ); 1265 Cairo::Pattern pattern; 1266 if( vertical ) pattern.set( cairo_pattern_create_linear( 0, 0, 0, 30 ) ); 1267 else pattern.set( cairo_pattern_create_linear( 0, 0, 30, 0 ) ); 1268 cairo_pattern_set_extend( pattern, CAIRO_EXTEND_REFLECT ); 1269 1270 cairo_pattern_add_color_stop( pattern, 0, ColorUtils::Rgba::transparent() ); 1271 cairo_pattern_add_color_stop( pattern, 1.0, ColorUtils::alphaColor( light, 0.1 ) ); 1272 1273 cairo_set_source( context, pattern ); 1274 if( vertical ) cairo_rectangle( context, xf+3, yf, wf-6, hf ); 1275 else cairo_rectangle( context, xf, yf+3, wf, hf-6 ); 1276 cairo_fill( context ); 1277 } 1278 1279 } 1280 1281 //____________________________________________________________________________________ 1282 void Style::renderToolBarHandle( 1283 GdkWindow* window, 1284 GdkRectangle* clipRect, 1285 gint x, gint y, gint w, gint h, const StyleOptions& options ) const 1286 { 1287 1288 const bool vertical( options & Vertical ); 1289 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 1290 1291 Cairo::Context context( window, clipRect ); 1292 int counter(0); 1293 if( vertical ) 1294 { 1295 1296 const int xcenter( x+w/2 ); 1297 for( int ycenter = y+2; ycenter <= y+h-3; ycenter+=3, ++counter ) 1298 { 1299 if( counter%2 == 0 ) _helper.renderDot( context, base, xcenter+1, ycenter ); 1300 else _helper.renderDot( context, base, xcenter-2, ycenter ); 1301 } 1302 1303 } else { 1304 1305 const int ycenter( y + h/2 ); 1306 for( int xcenter = x+2; xcenter < x+w-3; xcenter+=3, ++counter ) 1307 { 1308 if( counter%2 == 0 ) _helper.renderDot( context, base, xcenter, ycenter+1 ); 1309 else _helper.renderDot( context, base, xcenter, ycenter-2 ); 1310 } 1311 1312 } 1313 1314 return; 1315 1316 } 1317 1318 //__________________________________________________________________ 1319 void Style::drawFloatFrame( cairo_t* context, GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h, const StyleOptions& options, Palette::Role role ) const 1320 { 1321 1322 // define colors 1323 ColorUtils::Rgba base(_settings.palette().color( role ) ); 1324 ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 1325 ColorUtils::Rgba dark( ColorUtils::darkColor( ColorUtils::backgroundBottomColor( base ) ) ); 1326 1327 const bool hasAlpha( options&Alpha ); 1328 const bool isMenu( options&Menu ); 1329 const bool drawUglyShadow( !hasAlpha ); 1330 const bool rounded( options&Round ); 1331 1332 // if we aren't drawing window decoration 1333 if( !context ) 1334 { 1335 // create context 1336 // make it the old good way since context is cairo_t* instead Cairo::Context 1337 context=gdk_cairo_create(window); 1338 if(clipRect) 1339 { 1340 cairo_rectangle(context,clipRect->x,clipRect->y,clipRect->width,clipRect->height); 1341 cairo_clip(context); 1342 } 1343 } 1344 1345 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, double(y)+0.5, 0, y+h-1 ) ); 1346 1347 // add vertical offset 1348 if( isMenu && rounded ) 1349 { 1350 y += Menu_VerticalOffset; 1351 h -= 2*Menu_VerticalOffset; 1352 } 1353 1354 if( drawUglyShadow ) 1355 { 1356 1357 // adjust rectangle 1358 x++; 1359 y++; 1360 w-=2; 1361 h-=2; 1362 1363 cairo_set_line_width(context,1); 1364 1365 if( options&Focus ) 1366 { 1367 1368 // window is active - it's a glow, not a shadow 1369 const ColorUtils::Rgba frameColor( _settings.palette().color( Palette::ActiveWindowBackground ) ); 1370 const ColorUtils::Rgba glow = ColorUtils::mix(ColorUtils::Rgba(0.5,0.5,0.5),frameColor,0.7); 1371 cairo_set_source(context,glow); 1372 1373 const double radius( 11*0.5 ); 1374 cairo_move_to( context, x+4, y-0.5 ); cairo_line_to( context, x+w-4, y-0.5 ); 1375 cairo_stroke( context ); 1376 1377 cairo_arc_negative( context, x-0.5+radius, y-0.5+radius, radius, -0.5*M_PI, -M_PI ); 1378 cairo_stroke( context ); 1379 cairo_arc_negative( context, x+w-11+0.5+radius, y-0.5+radius, radius, 0, -0.5*M_PI ); 1380 cairo_stroke( context ); 1381 1382 cairo_move_to( context, x-0.5, y+4 ); cairo_line_to( context, x-0.5, y+h-4 ); 1383 cairo_move_to( context, x+w+0.5, y+4 ); cairo_line_to( context, x+w+0.5, y+h-4 ); 1384 cairo_stroke( context ); 1385 1386 cairo_arc_negative( context, x-0.5+radius, y+h-11+0.5+radius, radius, -M_PI, -1.5*M_PI ); 1387 cairo_stroke( context ); 1388 cairo_arc_negative( context, x+w-11+0.5+radius, y+h-11+0.5+radius, radius, 0.5*M_PI, 0 ); 1389 cairo_stroke( context ); 1390 1391 cairo_move_to( context, x+4, y+h+0.5 ); cairo_line_to( context, x+w-4, y+h+0.5 ); 1392 cairo_stroke( context ); 1393 1394 1395 light=ColorUtils::mix(light, frameColor); 1396 dark=ColorUtils::mix(dark,frameColor); 1397 1398 } else { 1399 1400 // window inactive - draw something resembling shadow 1401 // fully desaturate 1402 ColorUtils::Rgba shadow( ColorUtils::darken( base, 0., 0. ) ); 1403 1404 if(rounded) 1405 { 1406 const double radius( 11*0.5 ); 1407 cairo_set_source( context, ColorUtils::darken( shadow, 0.2 )); 1408 cairo_move_to( context, x+4, y-0.5 ); cairo_line_to( context, x+w-4, y-0.5 ); 1409 cairo_stroke( context ); 1410 1411 cairo_arc_negative( context, x-0.5+radius, y-0.5+radius, radius, -0.5*M_PI, -M_PI ); 1412 cairo_stroke( context ); 1413 cairo_arc_negative( context, x+w-11+0.5+radius, y-0.5+radius, radius, 0, -0.5*M_PI ); 1414 cairo_stroke( context ); 1415 1416 cairo_set_source( context, ColorUtils::darken( shadow, 0.35 )); 1417 cairo_move_to( context, x-0.5, y+4 ); cairo_line_to( context, x-0.5, y+h-4 ); 1418 cairo_move_to( context, x+w+0.5, y+4 ); cairo_line_to( context, x+w+0.5, y+h-4 ); 1419 cairo_stroke( context ); 1420 1421 cairo_set_source( context, ColorUtils::darken( shadow, 0.45 )); 1422 cairo_arc_negative( context, x-0.5+radius, y+h-11+0.5+radius, radius, -M_PI, -1.5*M_PI ); 1423 cairo_stroke( context ); 1424 cairo_arc_negative( context, x+w-11+0.5+radius, y+h-11+0.5+radius, radius, 0.5*M_PI, 0 ); 1425 cairo_stroke( context ); 1426 1427 cairo_set_source( context, ColorUtils::darken( shadow, 0.6 )); 1428 cairo_move_to( context, x+4, y+h+0.5 ); cairo_line_to( context, x+w-4, y+h+0.5 ); 1429 cairo_stroke( context ); 1430 1431 } else { 1432 1433 cairo_set_source( context, ColorUtils::darken( shadow, 0.2 )); 1434 cairo_move_to( context, x-0.5, y-0.5 ); cairo_line_to( context, x+w+0.5, y-0.5 ); 1435 cairo_stroke( context ); 1436 1437 cairo_set_source( context, ColorUtils::darken( shadow, 0.35 )); 1438 cairo_move_to( context, x-0.5, y-0.5 ); cairo_line_to( context, x-0.5, y+h+0.5 ); 1439 cairo_move_to( context, x+w+0.5, y-0.5 ); cairo_line_to( context, x+w+0.5, y+h+0.5 ); 1440 cairo_stroke( context ); 1441 1442 cairo_set_source( context, ColorUtils::darken( shadow, 0.6 )); 1443 cairo_move_to( context, x-0.5, y+h+0.5 ); cairo_line_to( context, x+w+0.5, y+h+0.5 ); 1444 cairo_stroke( context ); 1445 1446 } 1447 } 1448 } 1449 1450 cairo_pattern_add_color_stop( pattern, 0, light ); 1451 1452 if( !rounded ) 1453 { 1454 1455 cairo_pattern_add_color_stop( pattern, 1, ColorUtils::alphaColor( dark, 0 ) ); 1456 1457 } else { 1458 1459 if( h > 20.5 ) cairo_pattern_add_color_stop( pattern, std::max( 0.0, 1.0 - 12.0/( double(h)-5.5 ) ), ColorUtils::alphaColor( light, 0.5 ) ); 1460 else if( h > 8.5 ) cairo_pattern_add_color_stop( pattern, std::max( 0.0, 3.0/( double(h)-5.5 ) ), ColorUtils::alphaColor( light, 0.5 ) ); 1461 cairo_pattern_add_color_stop( pattern, 1, ColorUtils::Rgba::transparent( light ) ); 1462 1463 } 1464 1465 cairo_rounded_rectangle( context, x+0.5, y+0.5, w-1, h-1, 3.5, rounded ? CornersAll : CornersNone ); 1466 1467 cairo_set_source( context, pattern ); 1468 cairo_set_line_width( context, 0.8 ); 1469 cairo_stroke( context ); 1470 } 1471 1472 //__________________________________________________________________ 1473 void Style::renderButtonSlab( 1474 GdkWindow* window, 1475 GdkRectangle* clipRect, 1476 gint x, gint y, gint w, gint h, 1477 const StyleOptions& options, 1478 const AnimationData& animationData, 1479 TileSet::Tiles tiles 1480 ) 1481 { 1482 1483 // flat buttons are only rendered with a simple Rect, and only when either focused or sunken 1484 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 1485 1486 // glow color (depending on hover/glow 1487 const ColorUtils::Rgba glow( slabShadowColor( options, animationData ) ); 1488 1489 if( options & Flat ) 1490 { 1491 if( options & Sunken ) 1492 { 1493 1494 Cairo::Context context( window, clipRect ); 1495 const ColorUtils::Rgba base( color( group, Palette::Window, options ) ); 1496 1497 const double bias( 0.75 ); 1498 double opacity( 1.0 ); 1499 if( glow.isValid() ) opacity -= bias*glow.alpha(); 1500 1501 // fill hole 1502 ColorUtils::Rgba color( ColorUtils::midColor( base ) ); 1503 color = ColorUtils::alphaColor( color, opacity ); 1504 cairo_save( context ); 1505 cairo_set_source( context, color ); 1506 cairo_rounded_rectangle( context, x+1, y+1, w-2, h-2, 3.5 ); 1507 cairo_fill( context ); 1508 cairo_restore( context ); 1509 1510 if( glow.isValid() ) _helper.holeFocused( base, glow, 7, true ).render( context, x, y, w, h ); 1511 else _helper.hole( base, 7, true ).render( context, x, y, w, h ); 1512 1513 } else if( glow.isValid() ) { 1514 1515 Cairo::Context context( window, clipRect ); 1516 _helper.slitFocused( glow ).render( context, x, y, w, h, tiles ); 1517 1518 } 1519 1520 return; 1521 1522 } 1523 1524 // forces minimum size to 14x14 1525 if( w < 14 || h < 14 ) 1526 { 1527 GdkRectangle parent( Gtk::gdk_rectangle( x, y, w, h ) ); 1528 GdkRectangle child( Gtk::gdk_rectangle( x, y, std::max( w, 14), std::max( h, 14 ) ) ); 1529 centerRect( &parent, &child ); 1530 x = child.x; 1531 y = child.y; 1532 w = child.width; 1533 h = child.height; 1534 clipRect = 0L; 1535 } 1536 1537 1538 // define colors 1539 ColorUtils::Rgba base( color( group, Palette::Button, options ) ); 1540 if( options&Blend ) 1541 { 1542 1543 gint wh, wy; 1544 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 1545 base = ColorUtils::backgroundColor( base, wh, y+wy+h/2 ); 1546 1547 } 1548 1549 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 1550 1551 // create context 1552 Cairo::Context context( window, clipRect ); 1553 cairo_save( context ); 1554 1555 // fill with appropriate pattern 1556 Cairo::Pattern pattern; 1557 if( options&Sunken ) 1558 { 1559 1560 pattern.set( cairo_pattern_create_linear( 0, y-h, 0, y+h ) ); 1561 cairo_pattern_add_color_stop( pattern, 0, light ); 1562 cairo_pattern_add_color_stop( pattern, 1.0, base ); 1563 1564 } else { 1565 1566 pattern.set( cairo_pattern_create_linear( 0, double(y)-0.2*h, 0, double(y) + h + 0.4*h ) ); 1567 cairo_pattern_add_color_stop( pattern, 0, light ); 1568 cairo_pattern_add_color_stop( pattern, 0.6, base ); 1569 1570 } 1571 1572 cairo_set_source( context, pattern ); 1573 _helper.fillSlab( context, x, y, w, h+1, tiles ); 1574 cairo_restore( context ); 1575 1576 if( options&Sunken ) 1577 { 1578 1579 _helper.slabSunken( base ).render( context, x, y, w, h, tiles ); 1580 1581 } else { 1582 1583 _helper.slab( base, glow, 0 ).render( context, x, y, w, h, tiles ); 1584 1585 } 1586 1587 } 1588 1589 //__________________________________________________________________ 1590 void Style::renderSlab( 1591 GdkWindow* window, 1592 GdkRectangle* clipRect, 1593 gint x, gint y, gint w, gint h, const Gtk::Gap& gap, 1594 const StyleOptions& options, 1595 const AnimationData& animationData ) 1596 { 1597 1598 // define colors 1599 ColorUtils::Rgba base; 1600 if( options&Blend ) 1601 { 1602 1603 gint wh, wy; 1604 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 1605 base = ColorUtils::backgroundColor( _settings.palette().color( Palette::Window ), wh, y+wy+h/2 ); 1606 1607 } else { 1608 1609 base = _settings.palette().color( Palette::Window ); 1610 1611 } 1612 1613 // create context 1614 Cairo::Context context( window, clipRect ); 1615 generateGapMask( context, x, y, w, h, gap ); 1616 renderSlab( context, x, y, w, h, base, options, animationData, TileSet::Ring ); 1617 1618 } 1619 1620 //__________________________________________________________________ 1621 void Style::renderInfoBar( 1622 GdkWindow* window, 1623 GdkRectangle* clipRect, 1624 gint x, gint y, gint w, gint h, 1625 const ColorUtils::Rgba& glow ) 1626 { 1627 1628 // create context 1629 Cairo::Context context( window, clipRect ); 1630 1631 // content 1632 cairo_rounded_rectangle( context, x+1, y+1, w-2, h-2, 5 ); 1633 cairo_set_source( context, glow ); 1634 cairo_fill( context ); 1635 1636 // border 1637 cairo_set_line_width( context, 1.0 ); 1638 cairo_rounded_rectangle( context, 1.5+x, 1.5+y, w-3, h-3, 4.5 ); 1639 cairo_set_source( context, ColorUtils::darken( glow ) ); 1640 cairo_stroke( context ); 1641 1642 } 1643 1644 //__________________________________________________________________ 1645 void Style::renderCheckBox( 1646 GdkWindow* window, 1647 GdkRectangle* clipRect, 1648 gint x, gint y, gint w, gint h, GtkShadowType shadow, 1649 const StyleOptions& options, 1650 const AnimationData& animationData ) 1651 { 1652 1653 // define checkbox rect 1654 gint cbw = CheckBox_Size; 1655 if( options & Flat ) cbw -= 5; 1656 GdkRectangle parent = {x, y, w, h }; 1657 GdkRectangle child = {0, 0, cbw, cbw }; 1658 centerRect( &parent, &child ); 1659 1660 // define colors 1661 ColorUtils::Rgba base; 1662 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 1663 const Palette::Role role( options&Flat ? Palette::Window : Palette::Button ); 1664 if( options&Blend ) 1665 { 1666 1667 gint wh, wy; 1668 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 1669 base = ColorUtils::backgroundColor( _settings.palette().color( group, role ), wh, y+wy+h/2 ); 1670 1671 } else { 1672 1673 base = _settings.palette().color( group, role ); 1674 1675 } 1676 1677 // draw slab 1678 Cairo::Context context( window, clipRect ); 1679 1680 if( options & Flat ) 1681 { 1682 1683 _helper.holeFlat( base, 0, false ).render( context, child.x+1, child.y-1, child.width, child.height, TileSet::Full ); 1684 cairo_translate( context, 0, -2 ); 1685 1686 } else { 1687 1688 StyleOptions localOptions( options ); 1689 localOptions &= ~Sunken; 1690 renderSlab( context, child.x, child.y, child.width, child.height, base, localOptions, animationData ); 1691 1692 } 1693 1694 // draw mark 1695 x = int( double(child.x + child.width/2) - 3.5 ); 1696 y = int( double(child.y + child.height/2) - 2.5 ); 1697 1698 if( shadow == GTK_SHADOW_IN || shadow == GTK_SHADOW_ETCHED_IN || options&Active ) 1699 { 1700 1701 cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND ); 1702 cairo_set_line_join( context, CAIRO_LINE_JOIN_ROUND ); 1703 if( shadow == GTK_SHADOW_IN ) cairo_set_line_width( context, 2.0 ); 1704 1705 Palette::Group group( (options&Disabled) ? Palette::Disabled : Palette::Active ); 1706 const ColorUtils::Rgba& color( _settings.palette().color( group, ( options&Flat ) ? Palette::WindowText : Palette::ButtonText ) ); 1707 const ColorUtils::Rgba& background( _settings.palette().color( ( options&Flat ) ? Palette::Window : Palette::Button ) ); 1708 1709 ColorUtils::Rgba base( ColorUtils::decoColor( background, color ) ); 1710 ColorUtils::Rgba contrast( ColorUtils::lightColor( background ) ); 1711 1712 // We don't want to change color on active state for menu checkboxes (it's never passed by GTK) 1713 // Also, if we ignore active state, we get correct render for LibreOffice 1714 if( options&Active && !(options&Flat) ) 1715 { 1716 base = ColorUtils::alphaColor( base, 0.3 ); 1717 contrast = ColorUtils::alphaColor( contrast, 0.3 ); 1718 } 1719 1720 cairo_translate( context, 0.5, 0.5 ); 1721 1722 const double offset( 1.0 ); 1723 if( _settings.checkBoxStyle() == QtSettings::CS_CHECK ) 1724 { 1725 1726 // dask pattern for tristate buttons 1727 if( shadow == GTK_SHADOW_ETCHED_IN ) 1728 { 1729 cairo_set_line_width( context, 1.3 ); 1730 double dashes[2] = { 1.3, 2.6 }; 1731 cairo_set_dash( context, &dashes[0], 2, 0 ); 1732 } 1733 1734 cairo_save( context ); 1735 cairo_translate( context, 0, offset ); 1736 cairo_move_to( context, x+9, y ); 1737 cairo_line_to( context, x+3, y+7 ); 1738 cairo_line_to( context, x, y+4 ); 1739 cairo_restore( context ); 1740 cairo_set_source( context, contrast ); 1741 cairo_stroke( context ); 1742 1743 cairo_move_to( context, x+9, y ); 1744 cairo_line_to( context, x+3, y+7 ); 1745 cairo_line_to( context, x, y+4 ); 1746 cairo_set_source( context, base ); 1747 cairo_stroke( context ); 1748 1749 } else { 1750 1751 // dask pattern for tristate buttons 1752 if( shadow == GTK_SHADOW_ETCHED_IN ) 1753 { 1754 double dashes[2] = { 0.8, 4.0 }; 1755 cairo_set_dash( context, &dashes[0], 2, 0 ); 1756 } 1757 1758 if( options&Flat ) 1759 { 1760 1761 cairo_save( context ); 1762 cairo_translate( context, 0, offset ); 1763 cairo_move_to( context, x+8, y ); cairo_line_to( context, x+1, y+7 ); 1764 cairo_move_to( context, x+8, y+7 ); cairo_line_to( context, x+1, y ); 1765 cairo_restore( context ); 1766 cairo_set_source( context, contrast ); 1767 cairo_stroke( context ); 1768 1769 cairo_move_to( context, x+8, y ); cairo_line_to( context, x+1, y+7 ); 1770 cairo_move_to( context, x+8, y+7 ); cairo_line_to( context, x+1, y ); 1771 cairo_set_source( context, base ); 1772 cairo_stroke( context ); 1773 1774 } else { 1775 1776 cairo_save( context ); 1777 cairo_translate( context, 0, offset ); 1778 cairo_move_to( context, x+8, y-1 ); cairo_line_to( context, x, y+7 ); 1779 cairo_move_to( context, x+8, y+7 ); cairo_line_to( context, x, y-1 ); 1780 cairo_restore( context ); 1781 cairo_set_source( context, contrast ); 1782 cairo_stroke( context ); 1783 1784 cairo_move_to( context, x+8, y-1 ); cairo_line_to( context, x, y+7 ); 1785 cairo_move_to( context, x+8, y+7 ); cairo_line_to( context, x, y-1 ); 1786 cairo_set_source( context, base ); 1787 cairo_stroke( context ); 1788 1789 } 1790 1791 } 1792 1793 } 1794 1795 } 1796 1797 //___________________________________________________________________ 1798 void Style::renderRadioButton( 1799 GdkWindow* window, 1800 GdkRectangle* clipRect, 1801 gint x, gint y, gint w, gint h, GtkShadowType shadow, 1802 const StyleOptions& options, 1803 const AnimationData& animationData ) 1804 { 1805 1806 // define checkbox rect 1807 gint cbw( CheckBox_Size ); 1808 gint tileSize( CheckBox_Size/3 ); 1809 double scale( 1.0 ); 1810 1811 if( _settings.applicationName().isOpenOffice() ) 1812 { 1813 const gint dimension = std::min( w, h ); 1814 cbw = std::min( 3*( 1 + dimension/3 ), (int)CheckBox_Size ); 1815 scale = double(cbw)/CheckBox_Size; 1816 tileSize = cbw/3; 1817 } 1818 1819 GdkRectangle parent = {x, y, w, h }; 1820 GdkRectangle child = {0, 0, cbw, cbw }; 1821 centerRect( &parent, &child ); 1822 x = child.x; 1823 y = child.y; 1824 1825 // define colors 1826 ColorUtils::Rgba base; 1827 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 1828 if( options&Blend ) 1829 { 1830 1831 gint wh, wy; 1832 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 1833 1834 if( options & Menu ) base = ColorUtils::menuBackgroundColor( _settings.palette().color( group, Palette::Button ), wh, y+wy+h/2 ); 1835 else base = ColorUtils::backgroundColor( _settings.palette().color( group, Palette::Button ), wh, y+wy+h/2 ); 1836 1837 } else { 1838 1839 base = _settings.palette().color( group, Palette::Button ); 1840 1841 } 1842 1843 // glow 1844 const ColorUtils::Rgba glow( slabShadowColor( options, animationData ) ); 1845 1846 // get the pixmap 1847 const Cairo::Surface& surface( _helper.roundSlab( base, glow, 0, tileSize ) ); 1848 1849 // create context 1850 Cairo::Context context( window, clipRect ); 1851 cairo_save( context ); 1852 cairo_translate( context, x, y ); 1853 if(options&NoFill) 1854 { 1855 // Only render the glow, leave the bullet clipped out 1856 const int border(4); 1857 cairo_ellipse_negative(context,border,border,child.width-border*2,child.height-border*2); 1858 cairo_rectangle(context,0,0,child.width,child.height); 1859 cairo_clip(context); 1860 } 1861 cairo_rectangle( context, 0, 0, child.width, child.height ); 1862 cairo_set_source_surface( context, surface, 0, 0 ); 1863 cairo_fill( context ); 1864 cairo_restore( context ); 1865 1866 if( shadow == GTK_SHADOW_IN || shadow == GTK_SHADOW_ETCHED_IN || options&Active ) 1867 { 1868 double radius( shadow == GTK_SHADOW_ETCHED_IN ? 1.4:2.6 ); 1869 radius *= scale; 1870 1871 const double dx( 0.5*child.width - radius ); 1872 const double dy( 0.5*child.height - radius ); 1873 1874 const ColorUtils::Rgba& background( _settings.palette().color( Palette::Button ) ); 1875 const ColorUtils::Rgba& color( _settings.palette().color( group, Palette::ButtonText ) ); 1876 1877 ColorUtils::Rgba base( ColorUtils::decoColor( background, color ) ); 1878 ColorUtils::Rgba contrast( ColorUtils::lightColor( background ) ); 1879 1880 // We don't want to change color on active state for menu radiobuttons (it's never passed by GTK) 1881 // Also, if we ignore active state, we get correct render for LibreOffice 1882 if( options&Active && !(options&Menu ) ) 1883 { 1884 base = ColorUtils::alphaColor( base, 0.3 ); 1885 contrast = ColorUtils::alphaColor( contrast, 0.3 ); 1886 } 1887 1888 1889 cairo_save( context ); 1890 cairo_translate( context, 0, radius/2 ); 1891 cairo_ellipse( context, x+dx, y+dy, child.width - 2*dx, child.height -2*dy ); 1892 cairo_restore( context ); 1893 if( shadow == GTK_SHADOW_ETCHED_IN ) 1894 { 1895 1896 cairo_set_line_width( context, 1.3 ); 1897 cairo_set_source( context, contrast ); 1898 cairo_stroke( context ); 1899 1900 cairo_set_source( context, base ); 1901 cairo_ellipse( context, x+dx, y+dy, child.width - 2*dx, child.height -2*dy ); 1902 cairo_stroke( context ); 1903 1904 } else { 1905 1906 cairo_set_source( context, contrast ); 1907 cairo_fill( context ); 1908 1909 cairo_set_source( context, base ); 1910 cairo_ellipse( context, x+dx, y+dy, child.width - 2*dx, child.height -2*dy ); 1911 cairo_fill( context ); 1912 1913 } 1914 1915 } 1916 1917 return; 1918 } 1919 1920 //____________________________________________________________________________________ 1921 void Style::renderHole( 1922 GdkWindow* window, 1923 GdkRectangle* clipRect, 1924 gint x, gint y, gint w, gint h, const Gtk::Gap& gap, 1925 const StyleOptions& options, 1926 const AnimationData& animationData, 1927 TileSet::Tiles tiles ) 1928 { 1929 1930 // do nothing if not enough room 1931 if( w < 14 || h < 14 ) return; 1932 1933 // enable state 1934 const bool enabled( !(options&Disabled ) ); 1935 1936 // load color 1937 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 1938 ColorUtils::Rgba fill; 1939 if( !( options&NoFill ) ) 1940 { 1941 const Palette::Group group( enabled ? Palette::Active : Palette::Disabled ); 1942 fill = _settings.palette().color( group, Palette::Base ); 1943 } 1944 1945 // create context, add mask, and render hole 1946 Cairo::Context context( window, clipRect ); 1947 generateGapMask( context, x, y, w, h, gap ); 1948 1949 if( fill.isValid() ) tiles |= TileSet::Center; 1950 1951 const ColorUtils::Rgba glow( holeShadowColor( options, animationData ) ); 1952 if( glow.isValid() ) _helper.holeFocused( base, fill, glow ).render( context, x, y, w, h, tiles ); 1953 else _helper.hole( base, fill ).render( context, x, y, w, h, tiles ); 1954 1955 } 1956 1957 //____________________________________________________________________________________ 1958 void Style::renderDockFrame( 1959 GdkWindow* window, 1960 GdkRectangle* clipRect, 1961 gint x, gint y, gint w, gint h, const Gtk::Gap& gap, const StyleOptions& options ) 1962 { 1963 1964 // do nothing if not enough room 1965 if( w < 9 || h < 9 ) return; 1966 1967 // define colors 1968 ColorUtils::Rgba top; 1969 ColorUtils::Rgba bottom; 1970 if( options&Blend ) 1971 { 1972 1973 gint wh, wy; 1974 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 1975 top = ColorUtils::backgroundColor( _settings.palette().color( Palette::Window ), wh, y+wy ); 1976 bottom = ColorUtils::backgroundColor( _settings.palette().color( Palette::Window ), wh, y+h+wy ); 1977 1978 } else { 1979 1980 top = _settings.palette().color( Palette::Window ); 1981 bottom = _settings.palette().color( Palette::Window ); 1982 1983 } 1984 1985 // create context, add mask, and render 1986 Cairo::Context context( window, clipRect ); 1987 generateGapMask( context, x, y, w, h, gap ); 1988 _helper.dockFrame( top, bottom ).render( context, x, y, w, h ); 1989 } 1990 1991 //____________________________________________________________________________________ 1992 void Style::renderGroupBoxFrame( 1993 GdkWindow* window, 1994 GtkWidget* widget, 1995 GdkRectangle* clipRect, 1996 gint x, gint y, gint w, gint h, const StyleOptions& options ) 1997 { 1998 1999 // register 2000 if( widget ) 2001 { _animations.groupBoxEngine().registerWidget( widget ); } 2002 2003 // define colors 2004 ColorUtils::Rgba base; 2005 if( options&Blend ) 2006 { 2007 2008 gint wh, wy; 2009 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 2010 base = ColorUtils::backgroundColor( _settings.palette().color( Palette::Window ), wh, y+wy+h/2 ); 2011 2012 } else { 2013 2014 base = _settings.palette().color( Palette::Window ); 2015 2016 } 2017 2018 Cairo::Context context( window, clipRect ); 2019 renderGroupBox( context, base, x, y, w, h, options ); 2020 2021 } 2022 2023 //____________________________________________________________________________________ 2024 void Style::renderMenuItemRect( 2025 GdkWindow* window, 2026 GdkRectangle* clipRect, 2027 GtkWidget* widget, 2028 gint x, gint y, gint w, gint h, 2029 const StyleOptions& options, 2030 const AnimationData& data ) 2031 { 2032 ColorUtils::Rgba base; 2033 2034 gint wh, wy; 2035 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 2036 const bool isInMenu( Gtk::gtk_parent_menu( widget ) ); 2037 const bool isInMenuBar( Gtk::gtk_parent_menubar( widget ) ); 2038 2039 if( wh > 0 ) 2040 { 2041 if( isInMenu ) base = ColorUtils::menuBackgroundColor( ColorUtils::midColor( _settings.palette().color( Palette::Window ) ), wh, y+wy+h/2 ); 2042 else if( options&Blend ) base = ColorUtils::backgroundColor( ColorUtils::midColor( _settings.palette().color( Palette::Window ) ), wh, y+wy+h/2 ); 2043 else base = ColorUtils::midColor( _settings.palette().color( Palette::Window ) ); 2044 2045 } else { 2046 2047 base = ColorUtils::midColor( _settings.palette().color( Palette::Window ) ); 2048 2049 } 2050 2051 // more color customization, based on menuHighlight mode 2052 ColorUtils::Rgba color( base ); 2053 if( _settings.menuHighlightMode() == QtSettings::MM_STRONG ) 2054 { 2055 2056 if( (options & Sunken) || isInMenu ) color = _settings.palette().color( Palette::Selected ); 2057 else color = ColorUtils::tint( color, _settings.palette().color( Palette::Hover ) ); 2058 2059 } else if( _settings.menuHighlightMode() == QtSettings::MM_SUBTLE ) { 2060 2061 if( (options & Sunken) || isInMenu ) color = ColorUtils::mix( color, ColorUtils::tint( color, _settings.palette().color( Palette::Selected ), 0.6 ) ); 2062 else color = ColorUtils::mix( color, ColorUtils::tint( color, _settings.palette().color( Palette::Hover ), 0.6 ) ); 2063 2064 } 2065 2066 // apply animation data 2067 if( data._mode == AnimationHover ) 2068 { 2069 if( data._opacity > 0 ) color = ColorUtils::alphaColor( color, data._opacity ); 2070 else return; 2071 } 2072 2073 2074 if( isInMenuBar ) 2075 { 2076 2077 // we force ytickness in gtkrc to emulate Qt menubar/menu space separation 2078 // so adjust vertical extent of the rect in menubar 2079 if( _settings.applicationName().isXul() ) 2080 { 2081 2082 y+=3; 2083 h-=6; 2084 2085 } else { 2086 2087 x+=1; 2088 w-=2; 2089 2090 y+=1; 2091 h-=2; 2092 2093 } 2094 } else if ( isInMenu ) { 2095 2096 // we force ytickness to 5 in gtkrc to emulate Qt menuitems space separation 2097 // so adjust vertical extent of the rect in menus to 21 (size with standard ytickness) 2098 if( h > 27 ) 2099 { 2100 2101 y+=4; 2102 h-=7; 2103 2104 } else { 2105 2106 y+=(h-21)/2; 2107 h=21; 2108 2109 } 2110 2111 } 2112 2113 bool hasSubMenu( isInMenu && GTK_IS_MENU_ITEM( widget ) && gtk_menu_item_get_submenu( GTK_MENU_ITEM( widget ) ) ); 2114 if( hasSubMenu ) 2115 { 2116 Cairo::Context context( window, clipRect ); 2117 cairo_translate( context, x, y ); 2118 2119 // draw item rect in a group 2120 cairo_push_group( context ); 2121 _helper.holeFlat( color, 0 ).render( context, 0, 0, w, h, TileSet::Full ); 2122 cairo_pop_group_to_source( context ); 2123 2124 // generate linear gradient for masking 2125 if( Gtk::gtk_widget_layout_is_reversed( widget ) ) 2126 { 2127 2128 Cairo::Pattern mask( cairo_pattern_create_linear( 4, 0, 40, 0 ) ); 2129 cairo_pattern_add_color_stop( mask, 0, ColorUtils::Rgba::transparent() ); 2130 cairo_pattern_add_color_stop( mask, 1, ColorUtils::Rgba::black() ); 2131 cairo_mask( context, mask ); 2132 2133 } else { 2134 2135 Cairo::Pattern mask( cairo_pattern_create_linear( w-40, 0, w-4, 0 ) ); 2136 cairo_pattern_add_color_stop( mask, 0, ColorUtils::Rgba::black() ); 2137 cairo_pattern_add_color_stop( mask, 1, ColorUtils::Rgba::transparent() ); 2138 cairo_mask( context, mask ); 2139 2140 } 2141 2142 } else { 2143 2144 Cairo::Context context( window, clipRect ); 2145 _helper.holeFlat( color, 0 ).render( context, x, y, w, h, TileSet::Full ); 2146 2147 } 2148 } 2149 2150 //____________________________________________________________________________________ 2151 void Style::renderSelection( 2152 GdkWindow* window, 2153 GdkRectangle* clipRect, 2154 gint x, gint y, gint w, gint h, 2155 TileSet::Tiles tiles, 2156 const StyleOptions& options 2157 ) 2158 { 2159 2160 // do nothing if not selected nor hovered 2161 if( !(options & (Hover|Selected )) ) return; 2162 2163 Palette::Group group( (options & Focus) ? Palette::Active : Palette::Inactive ); 2164 ColorUtils::Rgba base( _settings.palette().color( group, Palette::Selected ) ); 2165 if( options & Hover ) 2166 { 2167 if( !( options & Selected ) ) base.setAlpha( 0.2 ); 2168 else base = base.light( 110 ); 2169 } 2170 2171 // create context 2172 Cairo::Context context( window, clipRect ); 2173 if( !(tiles&TileSet::Left) ) { x -= 8; w+=8; } 2174 if( !(tiles&TileSet::Right) ) { w += 8; } 2175 _helper.selection( base, h, false ).render( context, x, y, w, h, tiles ); 2176 2177 } 2178 2179 //____________________________________________________________________________________ 2180 void Style::renderArrow( 2181 GdkWindow* window, 2182 GdkRectangle* clipRect, 2183 GtkArrowType orientation, 2184 gint x, gint y, gint w, gint h, 2185 QtSettings::ArrowSize arrowSize, 2186 const StyleOptions& options, 2187 const AnimationData& data, 2188 Palette::Role role ) const 2189 { 2190 2191 // get polygon 2192 const Polygon arrow( genericArrow( orientation, arrowSize ) ); 2193 2194 // retrieve colors 2195 ColorUtils::Rgba base; 2196 if( options&Disabled ) base = _settings.palette().color( Palette::Disabled, role ); 2197 else if( data._mode == AnimationHover ) base = ColorUtils::mix( 2198 _settings.palette().color( Palette::Active, role ), 2199 _settings.palette().color( Palette::Hover ), 2200 data._opacity ); 2201 else if( options&Hover ) base = _settings.palette().color( Palette::Hover ); 2202 else base = _settings.palette().color( Palette::Active, role ); 2203 2204 // merge base color with relevant background, if needed 2205 const Palette::Group group( (options&Disabled) ? Palette::Disabled : Palette::Active ); 2206 switch( role ) 2207 { 2208 2209 case Palette::WindowText: 2210 base = ColorUtils::decoColor( _settings.palette().color( group, Palette::Window ), base ); 2211 break; 2212 2213 case Palette::ButtonText: 2214 base = ColorUtils::decoColor( _settings.palette().color( group, Palette::Button ), base ); 2215 break; 2216 2217 default: break; 2218 2219 } 2220 2221 // need odd width and height 2222 if( !(w%2) ) w--; 2223 if( !(h%2) ) h--; 2224 const int xcenter = x + w/2; 2225 const int ycenter = y + h/2; 2226 2227 // create context and translate to center 2228 Cairo::Context context( window, clipRect ); 2229 cairo_translate( context, xcenter, ycenter ); 2230 2231 switch( orientation ) 2232 { 2233 case GTK_ARROW_UP: 2234 break; 2235 2236 case GTK_ARROW_DOWN: 2237 if( arrowSize == QtSettings::ArrowSmall ) cairo_translate( context, 0, 0.5 ); 2238 else cairo_translate( context, 0, 1 ); 2239 break; 2240 2241 case GTK_ARROW_LEFT: 2242 case GTK_ARROW_RIGHT: 2243 if( arrowSize == QtSettings::ArrowSmall ) 2244 { cairo_translate( context, 0.5, 0 ); } 2245 break; 2246 2247 default: 2248 break; 2249 } 2250 2251 switch( arrowSize ) 2252 { 2253 case QtSettings::ArrowTiny: 2254 case QtSettings::ArrowSmall: 2255 cairo_set_line_width( context, 1.2 ); 2256 break; 2257 2258 default: 2259 case QtSettings::ArrowNormal: 2260 cairo_set_line_width( context, 1.6 ); 2261 break; 2262 } 2263 2264 cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND ); 2265 cairo_set_line_join( context, CAIRO_LINE_JOIN_ROUND ); 2266 2267 // contrast 2268 if( options&Contrast ) 2269 { 2270 2271 // contrast color 2272 const ColorUtils::Rgba contrast( ColorUtils::lightColor( _settings.palette().color( Palette::Window ) ) ); 2273 2274 cairo_save( context ); 2275 cairo_translate( context, 0, 1 ); 2276 cairo_polygon( context, arrow ); 2277 cairo_restore( context ); 2278 2279 cairo_set_source( context, contrast ); 2280 cairo_stroke( context ); 2281 } 2282 2283 // base 2284 cairo_polygon( context, arrow ); 2285 cairo_set_source( context, base ); 2286 cairo_stroke( context ); 2287 2288 } 2289 2290 //____________________________________________________________________________________ 2291 void Style::renderSliderGroove( 2292 GdkWindow* window, 2293 GdkRectangle* clipRect, 2294 gint x, gint y, gint w, gint h, const StyleOptions& options ) 2295 { 2296 2297 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 2298 2299 const bool vertical( options & Vertical ); 2300 GdkRectangle parent = { x, y, w, h }; 2301 2302 GdkRectangle child; 2303 if( vertical ) child = Gtk::gdk_rectangle( 0, 0, Slider_GrooveWidth, h ); 2304 else child = Gtk::gdk_rectangle( 0, 0, w, Slider_GrooveWidth ); 2305 centerRect( &parent, &child ); 2306 2307 if( !vertical ) 2308 { 2309 // more adjustment needed due to contrast pixel 2310 child.y += 1; 2311 child.height -= 1; 2312 } 2313 2314 Cairo::Context context( window, clipRect ); 2315 _helper.scrollHole( base, vertical, true ).render( context, child.x, child.y, child.width, child.height, TileSet::Full ); 2316 2317 } 2318 2319 //____________________________________________________________________________________ 2320 void Style::renderSliderHandle( 2321 GdkWindow* window, 2322 GdkRectangle* clipRect, 2323 gint x, gint y, gint w, gint h, 2324 const StyleOptions& options, 2325 const AnimationData& animationData ) 2326 { 2327 2328 // define colors 2329 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 2330 ColorUtils::Rgba base; 2331 if( options&Blend ) 2332 { 2333 2334 gint wh, wy; 2335 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 2336 base = ColorUtils::backgroundColor( _settings.palette().color( group, Palette::Button ), wh, y+wy+h/2 ); 2337 2338 } else { 2339 2340 base = _settings.palette().color( group, Palette::Button ); 2341 2342 } 2343 2344 // render slab 2345 Cairo::Context context( window, clipRect ); 2346 2347 GdkRectangle parent = { x, y, w, h }; 2348 GdkRectangle child = {0, 0, 21, 21 }; 2349 centerRect( &parent, &child ); 2350 2351 x = child.x; 2352 y = child.y; 2353 2354 const ColorUtils::Rgba glow( slabShadowColor( options, animationData ) ); 2355 const Cairo::Surface& surface( _helper.sliderSlab( base, glow, (options&Sunken), 0 ) ); 2356 cairo_translate( context, x, y ); 2357 cairo_rectangle( context, 0, 0, child.width, child.height ); 2358 cairo_set_source_surface( context, surface, 0, 0 ); 2359 cairo_fill( context ); 2360 2361 } 2362 2363 //____________________________________________________________________________________ 2364 void Style::renderSizeGrip( 2365 GdkWindow* window, 2366 GdkRectangle* clipRect, 2367 GdkWindowEdge edge, 2368 gint x, gint y, gint w, gint h ) const 2369 { 2370 2371 gint dimension = std::min( w, h ); 2372 2373 // edges 2374 Polygon a; 2375 switch( edge ) 2376 { 2377 2378 case GDK_WINDOW_EDGE_NORTH_WEST: 2379 w = dimension; 2380 h = dimension; 2381 a << Point( double(x)+0.5, double(y)+0.5 ) << Point( double(x+w)-0.5, double(y)+0.5 ) << Point( double(x)+0.5, double(y+h)-0.5); 2382 break; 2383 2384 case GDK_WINDOW_EDGE_NORTH_EAST: 2385 x+= w-dimension; 2386 w = dimension; 2387 h = dimension; 2388 a << Point( double(x)+0.5, double(y)+0.5 ) << Point( double(x+w)-0.5, double(y)+0.5 ) << Point( double(x+w)-0.5, double(y+h)-0.5 ); 2389 break; 2390 2391 case GDK_WINDOW_EDGE_SOUTH_WEST: 2392 y+= h-dimension; 2393 w = dimension; 2394 h = dimension; 2395 a << Point( double(x)+0.5, double(y)+0.5 ) << Point( double(x+w)-0.5, double(y+h)-0.5 ) << Point( double(x)+0.5, double(y+h)-0.5 ); 2396 break; 2397 2398 case GDK_WINDOW_EDGE_SOUTH_EAST: 2399 x+= w-dimension; 2400 y+= h-dimension; 2401 w = dimension; 2402 h = dimension; 2403 a << Point( double(x)+0.5, double(y+h)-0.5 ) << Point( double(x+w)-0.5, double(y)+0.5 ) << Point( double(x+w)-0.5, double(y+h)-0.5 ); 2404 break; 2405 2406 default: return; 2407 2408 } 2409 2410 2411 // colors 2412 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 2413 const ColorUtils::Rgba dark( ColorUtils::darkColor( base ) ); 2414 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 2415 2416 // context 2417 Cairo::Context context( window, clipRect ); 2418 cairo_set_line_width( context, 1.0 ); 2419 2420 // fill 2421 cairo_polygon( context, a ); 2422 cairo_set_source( context, base ); 2423 cairo_fill( context ); 2424 2425 // draw edges 2426 cairo_move_to( context, a[0].x(), a[0].y() ); 2427 cairo_line_to( context, a[1].x(), a[1].y() ); 2428 cairo_set_source( context, dark ); 2429 cairo_stroke( context ); 2430 2431 cairo_move_to( context, a[1].x(), a[1].y() ); 2432 cairo_line_to( context, a[2].x(), a[2].y() ); 2433 cairo_line_to( context, a[0].x(), a[0].y() ); 2434 cairo_set_source( context, light ); 2435 cairo_stroke( context ); 2436 2437 } 2438 2439 //____________________________________________________________________________________ 2440 void Style::renderTab( 2441 GdkWindow* window, 2442 GdkRectangle* clipRect, 2443 gint x, gint y, gint w, gint h, 2444 GtkPositionType side, 2445 const StyleOptions& options, 2446 const TabOptions& tabOptions, 2447 const AnimationData& data 2448 ) 2449 { 2450 2451 if( tabOptions & CurrentTab ) 2452 { 2453 2454 return renderActiveTab( window, clipRect, x, y, w, h, side, options, tabOptions ); 2455 2456 } else { 2457 2458 switch( _settings.tabStyle() ) 2459 { 2460 case QtSettings::TS_SINGLE: return renderInactiveTab_Single( window, clipRect, x, y, w, h, side, options, tabOptions, data ); 2461 case QtSettings::TS_PLAIN: return renderInactiveTab_Plain( window, clipRect, x, y, w, h, side, options, tabOptions, data ); 2462 default: return; 2463 } 2464 2465 } 2466 2467 } 2468 2469 //____________________________________________________________________________________ 2470 void Style::renderTabBarBase( 2471 GdkWindow* window, 2472 GdkRectangle* clipRect, 2473 gint x, gint y, gint w, gint h, 2474 GtkPositionType side, 2475 Gtk::Gap gap, 2476 const StyleOptions& options, 2477 const TabOptions& tabOptions 2478 ) 2479 { 2480 2481 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 2482 2483 // adjust gap 2484 if( tabOptions & FirstTabAligned ) { gap.setX( gap.x()-3 ); gap.setWidth( gap.width()+3 ); } 2485 if( tabOptions & LastTabAligned ) { gap.setWidth( gap.width()+3 ); } 2486 2487 // create context 2488 Cairo::Context context( window, 0L ); 2489 2490 // generate mask and main slab 2491 SlabRect tabSlab; 2492 const TileSet::Tiles tabTiles( Style::tabTiles( side ) ); 2493 switch( side ) 2494 { 2495 case GTK_POS_BOTTOM: 2496 tabSlab = SlabRect( x, y+h-4, w, 15, tabTiles ); 2497 generateGapMask( context, x-1, y-4, w+2, h+8, gap ); 2498 break; 2499 2500 case GTK_POS_TOP: 2501 tabSlab = SlabRect( x, y-11, w, 15, tabTiles ); 2502 generateGapMask( context, x-1, y-4, w+2, h+8, gap ); 2503 break; 2504 2505 case GTK_POS_RIGHT: 2506 tabSlab = SlabRect( x+w-4, y, 15, h, tabTiles ); 2507 generateGapMask( context, x-4, y-1, w+8, h+2, gap ); 2508 break; 2509 2510 2511 case GTK_POS_LEFT: 2512 tabSlab = SlabRect( x-11, y, 15, h, tabTiles ); 2513 generateGapMask( context, x-4, y-1, w+8, h+2, gap ); 2514 break; 2515 2516 default: break; 2517 2518 } 2519 2520 // render 2521 _helper.slab( base, 0 ).render( context, tabSlab._x, tabSlab._y, tabSlab._w, tabSlab._h, tabSlab._tiles ); 2522 return; 2523 2524 } 2525 2526 //__________________________________________________________________ 2527 void Style::renderTabBarFrame( 2528 GdkWindow* window, 2529 GdkRectangle* clipRect, 2530 gint x, gint y, gint w, gint h, 2531 const Gtk::Gap& gap, 2532 const StyleOptions& options ) 2533 { 2534 2535 // define colors 2536 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 2537 2538 // create context 2539 Cairo::Context context( window, clipRect ); 2540 generateGapMask( context, x, y, w, h, gap ); 2541 renderSlab( context, x, y, w, h, base, options ); 2542 2543 } 2544 2545 //____________________________________________________________________________________ 2546 void Style::renderTreeExpander( 2547 GdkWindow* window, 2548 GdkRectangle* clipRect, 2549 gint x, gint y, gint w, gint h, 2550 GtkExpanderStyle style, 2551 const StyleOptions& options, 2552 const AnimationData& data, 2553 Palette::Role role 2554 ) const 2555 { 2556 2557 // retrieve colors 2558 ColorUtils::Rgba base; 2559 if( options&Disabled ) base = _settings.palette().color( Palette::Disabled, role ); 2560 else if( data._mode == AnimationHover ) base = ColorUtils::mix( 2561 _settings.palette().color( Palette::Active, role ), 2562 _settings.palette().color( Palette::Hover ), 2563 data._opacity ); 2564 else if( options&Hover ) base = _settings.palette().color( Palette::Hover ); 2565 else base = _settings.palette().color( Palette::Active, role ); 2566 2567 const int xcenter( x + w/2 ); 2568 const int ycenter( y + h/2 ); 2569 2570 // expander 'radius' (copied from oxygen-qt) 2571 const int radius( ( 9 - 4 ) / 2 ); 2572 2573 // create context and translate to center 2574 Cairo::Context context( window, clipRect ); 2575 cairo_set_line_width( context, 1.0 ); 2576 cairo_set_source( context, base ); 2577 2578 cairo_translate( context, -0.5+xcenter, -0.5+ycenter ); 2579 2580 // horizontal line 2581 cairo_move_to( context, -radius, 0 ); 2582 cairo_line_to( context, radius, 0 ); 2583 2584 // vertical line 2585 if( style == GTK_EXPANDER_COLLAPSED || style == GTK_EXPANDER_SEMI_COLLAPSED ) 2586 { 2587 cairo_move_to( context, 0, -radius ); 2588 cairo_line_to( context, 0, radius ); 2589 } 2590 2591 cairo_stroke( context ); 2592 2593 } 2594 2595 //__________________________________________________________________ 2596 void Style::renderWindowDecoration( cairo_t* context, WinDeco::Options wopt, gint x, gint y, gint w, gint h, const gchar** windowStrings, gint titleIndentLeft, gint titleIndentRight, bool gradient ) 2597 { 2598 bool hasAlpha( wopt & WinDeco::Alpha ); 2599 bool drawResizeHandle( !(wopt & WinDeco::Shaded) && (wopt & WinDeco::Resizable) ); 2600 bool isMaximized( wopt & WinDeco::Maximized ); 2601 bool drawAlphaChannel( wopt & WinDeco::DrawAlphaChannel ); 2602 StyleOptions options( hasAlpha ? Alpha : Blend ); 2603 2604 if( hasAlpha && !isMaximized ) 2605 { 2606 // cut round corners using alpha 2607 cairo_rounded_rectangle(context,x,y,w,h,3.5); 2608 cairo_clip(context); 2609 } 2610 2611 if(drawAlphaChannel) 2612 options|=DrawAlphaChannel; 2613 2614 if( gradient ) renderWindowBackground( context, x, y, w, h, options, isMaximized ); 2615 else 2616 { 2617 cairo_set_source( context, _settings.palette().color( Palette::Active, Palette::Window ) ); 2618 cairo_paint( context ); 2619 } 2620 2621 options|=Round; 2622 2623 // focus 2624 if(wopt & WinDeco::Active) options|=Focus; 2625 2626 if( !isMaximized ) 2627 { drawFloatFrame( context, 0L, 0L, x, y, w, h, options ); } 2628 2629 if( drawResizeHandle ) 2630 { 2631 ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 2632 renderWindowDots( context, x, y, w, h, base, wopt); 2633 } 2634 2635 if(windowStrings) 2636 { 2637 // caption is drawn in drawWindowDecoration 2638 if( windowStrings[1] ) 2639 { 2640 // TODO: use WMCLASS and caption to enable per-window style exceptions 2641 } 2642 } 2643 } 2644 2645 //__________________________________________________________________ 2646 void Style::drawWindowDecoration( cairo_t* context, WinDeco::Options wopt, gint x, gint y, gint w, gint h, const gchar** windowStrings, gint titleIndentLeft, gint titleIndentRight ) 2647 { 2648 2649 #ifdef GDK_WINDOWING_X11 2650 /* 2651 (any element of windowStrings[] may be NULL - will be understood as "") 2652 windowStrings may also be NULL 2653 2654 elements: 2655 windowStrings[0]: caption 2656 windowStrings[1]: WMCLASS 2657 windowStrings[2]: (gpointer)XID 2658 */ 2659 /* 2660 caches layout: 2661 left&right border height: h 2662 top&bottom border width: w-BorderLeft-BorderRight 2663 */ 2664 2665 // enable gradient if XID is not passed 2666 bool gradient=true; 2667 2668 const int buttonSpacing(WinDeco::getMetric(WinDeco::ButtonSpacing)); 2669 titleIndentLeft+=2*buttonSpacing; 2670 titleIndentRight+=2*buttonSpacing; 2671 2672 QtSettings::WindecoBlendType blendType(_settings.windecoBlendType()); 2673 if( blendType==QtSettings::SolidColor ) 2674 { 2675 2676 gradient=false; 2677 2678 } else if( blendType==QtSettings::FollowStyleHint && windowStrings && windowStrings[2] ) { 2679 2680 Window window((Window)windowStrings[2]); 2681 Display* display( GDK_DISPLAY_XDISPLAY(gdk_display_get_default()) ); 2682 if( _animations.backgroundHintEngine().backgroundGradientAtom() != None ) 2683 { 2684 Atom typeRet; 2685 int formatRet; 2686 unsigned long itemsRet; 2687 unsigned long afterRet; 2688 unsigned char *data = 0; 2689 2690 if( !( XGetWindowProperty(display, window, _animations.backgroundHintEngine().backgroundGradientAtom(), 0, G_MAXLONG, False, 2691 XA_CARDINAL, &typeRet, &formatRet, &itemsRet, &afterRet, &data) == Success 2692 && itemsRet == 1 2693 && formatRet == 32) ) 2694 { 2695 // if the window doesn't have this property set, it's likely 2696 // non-oxygenized, thus shouldn't have windeco bg gradient 2697 gradient=false; 2698 } 2699 } 2700 } 2701 2702 WindecoBorderKey key(wopt,w,h,gradient); 2703 2704 { 2705 // draw left border with cache 2706 Cairo::Surface left( _helper.windecoLeftBorderCache().value(key) ); 2707 int sw=WinDeco::getMetric(WinDeco::BorderLeft); 2708 if(sw) 2709 { 2710 2711 if( !left ) 2712 { 2713 2714 #if OXYGEN_DEBUG 2715 std::cerr<<"drawWindowDecoration: drawing left border; width: " << w << "; height: " << h << "; wopt: " << wopt << std::endl; 2716 #endif 2717 left=_helper.createSurface(sw,h); 2718 2719 Cairo::Context context(left); 2720 renderWindowDecoration( context, wopt, 0, 0, w, h, windowStrings, titleIndentLeft, titleIndentRight, gradient); 2721 2722 _helper.windecoLeftBorderCache().insert(key,left); 2723 2724 } else { 2725 2726 #if OXYGEN_DEBUG 2727 std::cerr << "drawWindowDecoration: using saved left border" << std::endl; 2728 #endif 2729 2730 } 2731 2732 cairo_set_source_surface(context, left, x, y); 2733 cairo_rectangle(context,x,y,sw,h); 2734 cairo_fill(context); 2735 } 2736 } 2737 2738 { 2739 // draw right border with cache 2740 Cairo::Surface right( _helper.windecoRightBorderCache().value(key) ); 2741 int sw=WinDeco::getMetric(WinDeco::BorderRight); 2742 if(sw) 2743 { 2744 2745 if( !right ) 2746 { 2747 2748 #if OXYGEN_DEBUG 2749 std::cerr<<"drawWindowDecoration: drawing right border; width: " << w << "; height: " << h << "; wopt: " << wopt << std::endl; 2750 #endif 2751 2752 right=_helper.createSurface(sw,h); 2753 2754 Cairo::Context context(right); 2755 renderWindowDecoration( context, wopt, -(w-sw), 0, w, h, windowStrings, titleIndentLeft, titleIndentRight, gradient ); 2756 2757 _helper.windecoRightBorderCache().insert(key,right); 2758 2759 } else { 2760 2761 #if OXYGEN_DEBUG 2762 std::cerr << "drawWindowDecoration: using saved right border" << std::endl; 2763 #endif 2764 2765 } 2766 2767 cairo_set_source_surface(context, right, x+w-sw, y); 2768 cairo_rectangle(context,x+w-sw,y,sw,h); 2769 cairo_fill(context); 2770 } 2771 } 2772 2773 { 2774 // draw top border with cache 2775 Cairo::Surface top( _helper.windecoTopBorderCache().value(key) ); 2776 int left=WinDeco::getMetric(WinDeco::BorderLeft); 2777 int right=WinDeco::getMetric(WinDeco::BorderRight); 2778 int sh=WinDeco::getMetric(WinDeco::BorderTop); 2779 int sw=w-left-right; 2780 if(sh && sw) 2781 { 2782 if( !top ) 2783 { 2784 2785 #if OXYGEN_DEBUG 2786 std::cerr<<"drawWindowDecoration: drawing top border; width: " << w << "; height: " << h << "; wopt: " << wopt << std::endl; 2787 #endif 2788 top=_helper.createSurface(sw,sh); 2789 2790 Cairo::Context context(top); 2791 renderWindowDecoration( context, wopt, -left, 0, w, h, windowStrings, titleIndentLeft, titleIndentRight, gradient ); 2792 2793 _helper.windecoTopBorderCache().insert(key,top); 2794 2795 } else { 2796 2797 #if OXYGEN_DEBUG 2798 std::cerr << "drawWindowDecoration: using saved top border" << std::endl; 2799 #endif 2800 2801 } 2802 2803 cairo_set_source_surface(context, top, x+left, y); 2804 cairo_rectangle(context,x+left,y,sw,sh); 2805 cairo_fill(context); 2806 2807 // caption shouldn't be saved in the cache 2808 if( windowStrings && windowStrings[0] ) 2809 { 2810 // draw caption 2811 const gchar* &caption(windowStrings[0]); 2812 const FontInfo& font( _settings.WMFont() ); 2813 gint layoutWidth=w-(titleIndentLeft+titleIndentRight); 2814 if( font.isValid() && layoutWidth>0 ) 2815 { 2816 PangoFontDescription* fdesc( pango_font_description_new() ); 2817 const Palette::Group group( wopt & WinDeco::Active ? Palette::Active : Palette::Disabled ); 2818 const int H=WinDeco::getMetric(WinDeco::BorderTop); 2819 int textHeight; 2820 2821 pango_font_description_set_family( fdesc, font.family().c_str() ); 2822 pango_font_description_set_weight( fdesc, PangoWeight( (font.weight()+2)*10 ) ); 2823 pango_font_description_set_style( fdesc, font.italic() ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL ); 2824 pango_font_description_set_absolute_size( fdesc, int(font.size()*PANGO_SCALE) ); 2825 2826 PangoLayout* layout( pango_cairo_create_layout(context) ); 2827 pango_layout_set_text( layout,caption, -1 ); 2828 pango_layout_set_font_description( layout, fdesc ); 2829 pango_layout_set_width( layout, layoutWidth*PANGO_SCALE ); 2830 pango_layout_set_ellipsize( layout, PANGO_ELLIPSIZE_END ); 2831 pango_layout_set_alignment( layout, _settings.TitleAlignment() ); 2832 pango_layout_get_pixel_size( layout, NULL, &textHeight ); 2833 2834 cairo_save( context ); 2835 2836 ColorUtils::Rgba titleContrastColor(ColorUtils::lightColor(_settings.palette().color( Palette::Disabled, Palette::Window ))); 2837 cairo_set_source( context, titleContrastColor ); 2838 cairo_translate( context, x+titleIndentLeft, y+(H-textHeight)/2.+1 ); 2839 pango_cairo_update_layout( context, layout ); 2840 pango_cairo_show_layout( context, layout ); 2841 2842 ColorUtils::Rgba titleTextColor(_settings.palette().color( group, Palette::WindowText )); 2843 cairo_set_source( context, titleTextColor ); 2844 cairo_translate( context, 0, -1 ); 2845 pango_cairo_update_layout( context, layout ); 2846 pango_cairo_show_layout( context, layout ); 2847 2848 cairo_restore( context ); 2849 2850 g_object_unref(layout); 2851 pango_font_description_free(fdesc); 2852 } 2853 } 2854 } 2855 } 2856 2857 { 2858 // draw bottom border with cache 2859 Cairo::Surface bottom( _helper.windecoBottomBorderCache().value(key) ); 2860 int left=WinDeco::getMetric(WinDeco::BorderLeft); 2861 int right=WinDeco::getMetric(WinDeco::BorderRight); 2862 int sh=WinDeco::getMetric(WinDeco::BorderBottom); 2863 int sw=w-left-right; 2864 int Y=y+h-sh; 2865 if(sh && sw) 2866 { 2867 if( !bottom) 2868 { 2869 2870 #if OXYGEN_DEBUG 2871 std::cerr<<"drawWindowDecoration: drawing bottom border; width: " << w << "; height: " << h << "; wopt: " << wopt << std::endl; 2872 #endif 2873 bottom=_helper.createSurface(sw,sh); 2874 2875 Cairo::Context context(bottom); 2876 renderWindowDecoration( context, wopt, -left, y-Y, w, h, windowStrings, titleIndentLeft, titleIndentRight, gradient ); 2877 2878 _helper.windecoBottomBorderCache().insert(key,bottom); 2879 2880 } else { 2881 2882 #if OXYGEN_DEBUG 2883 std::cerr << "drawWindowDecoration: using saved bottom border" << std::endl; 2884 #endif 2885 2886 } 2887 2888 cairo_set_source_surface(context, bottom, x+left, Y); 2889 cairo_rectangle(context,x+left,Y,sw,sh); 2890 cairo_fill(context); 2891 } 2892 } 2893 2894 #endif 2895 2896 } 2897 2898 //__________________________________________________________________ 2899 void Style::drawWindowShadow( cairo_t* context, WinDeco::Options wopt, gint x, gint y, gint w, gint h ) 2900 { 2901 cairo_set_source_rgba( context, 0, 0, 0, 0 ); 2902 cairo_set_operator( context, CAIRO_OPERATOR_SOURCE ); 2903 cairo_paint( context ); 2904 cairo_set_operator( context, CAIRO_OPERATOR_OVER ); 2905 2906 WindowShadow shadow(_settings, _helper); 2907 shadow.setWindowState(wopt); 2908 shadow.render(context, x,y,w,h); 2909 } 2910 2911 //__________________________________________________________________ 2912 void Style::drawWindecoButton( cairo_t* context, WinDeco::ButtonType type, WinDeco::ButtonStatus buttonState, WinDeco::Options windowState, gint x, gint y, gint w,gint h) 2913 { 2914 // validate arguments 2915 if(type>=WinDeco::ButtonTypeCount || buttonState>=WinDeco::ButtonStatusCount) 2916 { return; } 2917 2918 if( !(windowState & WinDeco::Active) && buttonState == WinDeco::Normal ) 2919 { 2920 // draw Oxygen-way disabled button on inactive window 2921 buttonState=WinDeco::Disabled; 2922 } 2923 if( !(windowState & WinDeco::Alpha) && !(windowState & WinDeco::Maximized) ) 2924 { y++; } 2925 2926 WinDeco::Button button( _settings, _helper, type ); 2927 button.setState(buttonState); 2928 int buttonSize=_settings.buttonSize(); 2929 button.render( context, x+(w-buttonSize)/2+1,y+(h-buttonSize)/2+1, buttonSize, buttonSize ); 2930 } 2931 2932 //__________________________________________________________________ 2933 void Style::drawWindecoShapeMask( cairo_t* context, WinDeco::Options wopt, gint x, gint y, gint w, gint h ) 2934 { 2935 cairo_save(context); 2936 cairo_set_source_rgba(context,0,0,0,0); 2937 cairo_set_operator(context,CAIRO_OPERATOR_SOURCE); 2938 cairo_paint(context); 2939 2940 cairo_set_source_rgba(context,1,1,1,1); 2941 cairo_set_operator(context,CAIRO_OPERATOR_OVER); 2942 cairo_set_antialias(context,CAIRO_ANTIALIAS_NONE); 2943 cairo_rounded_rectangle(context,x,y,w,h,6); 2944 cairo_fill(context); 2945 cairo_restore(context); 2946 2947 } 2948 2949 //__________________________________________________________________ 2950 void Style::sanitizeSize( GdkWindow* window, gint& w, gint& h ) const 2951 { 2952 if( w < 0 && h < 0 ) gdk_drawable_get_size( window, &w, &h ); 2953 else if( w < 0 ) gdk_drawable_get_size( window, &w, 0L ); 2954 else if( h < 0 ) gdk_drawable_get_size( window, 0L, &h ); 2955 } 2956 2957 //__________________________________________________________________ 2958 void Style::adjustScrollBarHole( int& x, int& y, int& w, int& h, const StyleOptions& options ) const 2959 { 2960 2961 const int buttonSize( 12 ); 2962 const int subLineOffset( buttonSize*_settings.scrollBarSubLineButtons() ); 2963 const int addLineOffset( buttonSize*_settings.scrollBarAddLineButtons() ); 2964 if( options&Vertical ) 2965 { 2966 2967 y += subLineOffset; 2968 h -= (subLineOffset+addLineOffset); 2969 2970 } else { 2971 2972 x += subLineOffset; 2973 w -= (subLineOffset+addLineOffset); 2974 2975 } 2976 2977 return; 2978 2979 } 2980 2981 //____________________________________________________________________________________ 2982 void Style::setBackgroundSurface( const std::string& filename ) 2983 { 2984 if( _backgroundSurface.isValid() ) _backgroundSurface.free(); 2985 _backgroundSurface.set( cairo_image_surface_create_from_png( filename.c_str() ) ); 2986 } 2987 2988 //____________________________________________________________________________________ 2989 void Style::renderActiveTab( 2990 GdkWindow* window, 2991 GdkRectangle* clipRect, 2992 gint x, gint y, gint w, gint h, 2993 GtkPositionType side, 2994 const StyleOptions& options, 2995 const TabOptions& tabOptions 2996 ) 2997 { 2998 2999 const bool isFirstTabAligned( tabOptions & FirstTabAligned ); 3000 const bool isLastTabAligned( tabOptions & LastTabAligned ); 3001 3002 // get color 3003 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 3004 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 3005 3006 // create context 3007 Cairo::Context context( window, clipRect ); 3008 3009 // borders and connections to tabs 3010 // this is quite painfull and slipery code. 3011 // the same is true with oxygen-qt 3012 int offset = 2; 3013 int adjust = ( tabOptions&Xul ) ? 0:2; 3014 const TileSet::Tiles tabTiles( Style::tabTiles( side ) ); 3015 3016 SlabRect tabSlab; 3017 SlabRect::List slabs; 3018 switch( side ) 3019 { 3020 case GTK_POS_BOTTOM: 3021 { 3022 // main slab 3023 y += adjust; h -= 2*adjust; 3024 tabSlab = SlabRect( x, y-offset, w, h+9+offset, tabTiles ); 3025 tabSlab._h+=1; 3026 3027 if( isFirstTabAligned ) { tabSlab._x-=1; tabSlab._w+=1; } 3028 if( isLastTabAligned ) { tabSlab._w+=1; } 3029 3030 // connections to frame 3031 if( isFirstTabAligned ) slabs.push_back( SlabRect( x-1, y+h+offset-6, 8, 18, TileSet::Left ) ); 3032 if( isLastTabAligned ) slabs.push_back( SlabRect( x+w-7, y+h+offset-6, 8, 18, TileSet::Right ) ); 3033 3034 break; 3035 } 3036 3037 case GTK_POS_TOP: 3038 { 3039 3040 // main slab 3041 y += adjust; h -= 2*adjust; 3042 tabSlab = SlabRect( x, y-9, w, h+11+offset, tabTiles ); 3043 tabSlab._y-=1; tabSlab._h+=1; 3044 3045 if( isFirstTabAligned ) { tabSlab._x-=1; tabSlab._w+=1; } 3046 if( isLastTabAligned ) { tabSlab._w-=1; } 3047 3048 // connections to frame 3049 if( isFirstTabAligned ) slabs.push_back( SlabRect( x-1, y-14, 8, 18, TileSet::Left ) ); 3050 if( isLastTabAligned ) slabs.push_back( SlabRect( x+w-7, y-14, 8, 18, TileSet::Right ) ); 3051 3052 break; 3053 } 3054 3055 case GTK_POS_RIGHT: 3056 { 3057 3058 // main slab 3059 x += adjust; w -= 2*adjust; 3060 tabSlab = SlabRect( x-offset, y, w+9+offset, h, tabTiles ); 3061 tabSlab._w+=1; 3062 if( isFirstTabAligned ) { tabSlab._y-=1; tabSlab._h+=1; } 3063 if( isLastTabAligned ) { tabSlab._h+=1; } 3064 3065 // connections to frame 3066 if( isFirstTabAligned ) slabs.push_back( SlabRect( x+w+offset-6, y-1, 18, 8, TileSet::Top ) ); 3067 if( isLastTabAligned ) slabs.push_back( SlabRect( x+w+offset-6, y+h-7, 18, 8, TileSet::Top ) ); 3068 3069 break; 3070 } 3071 3072 3073 case GTK_POS_LEFT: 3074 { 3075 3076 // main slab 3077 x += adjust; w -= 2*adjust; 3078 tabSlab = SlabRect( x-9, y, w+11+offset, h, tabTiles ); 3079 tabSlab._x-=1; tabSlab._w+=1; 3080 if( isFirstTabAligned ) { tabSlab._y-=1; tabSlab._h+=1; } 3081 if( isLastTabAligned ) { tabSlab._h+=1; } 3082 3083 // connections to frame 3084 if( isFirstTabAligned ) slabs.push_back( SlabRect( x-14, y-1, 18, 8, TileSet::Top ) ); 3085 if( isLastTabAligned ) slabs.push_back( SlabRect( x-14, y+h-7, 18, 8, TileSet::Top ) ); 3086 3087 break; 3088 3089 } 3090 3091 default: return; 3092 } 3093 3094 // render tab 3095 _helper.slab( base, 0 ).render( context, tabSlab._x, tabSlab._y, tabSlab._w, tabSlab._h, tabSlab._tiles ); 3096 3097 // adjust rect for filling 3098 SlabRect fillSlab( tabSlab ); 3099 fillSlab._x += 4; 3100 fillSlab._y += 4; 3101 fillSlab._w -= 8; 3102 fillSlab._h -= 8; 3103 3104 // fill 3105 Cairo::Pattern pattern; 3106 switch( side ) 3107 { 3108 case GTK_POS_BOTTOM: 3109 fillSlab._h -= 2; 3110 pattern.set( cairo_pattern_create_linear( 0, fillSlab._y, 0, fillSlab._y + fillSlab._h ) ); 3111 break; 3112 3113 case GTK_POS_TOP: 3114 fillSlab._y += 2; 3115 fillSlab._h -= 2; 3116 pattern.set( cairo_pattern_create_linear( 0, fillSlab._y + fillSlab._h, 0, fillSlab._y ) ); 3117 break; 3118 3119 case GTK_POS_RIGHT: 3120 fillSlab._w -= 2; 3121 pattern.set( cairo_pattern_create_linear( fillSlab._x, 0, fillSlab._x + fillSlab._w, 0 ) ); 3122 break; 3123 3124 case GTK_POS_LEFT: 3125 fillSlab._x += 2; 3126 fillSlab._w -= 2; 3127 pattern.set( cairo_pattern_create_linear( fillSlab._x + fillSlab._w, 0, fillSlab._x, 0 ) ); 3128 break; 3129 3130 default: return; 3131 3132 } 3133 3134 cairo_pattern_add_color_stop( pattern, 0.1, ColorUtils::alphaColor( light, 0.5 ) ); 3135 cairo_pattern_add_color_stop( pattern, 0.25, ColorUtils::alphaColor( light, 0.3 ) ); 3136 cairo_pattern_add_color_stop( pattern, 0.5, ColorUtils::alphaColor( light, 0.2 ) ); 3137 cairo_pattern_add_color_stop( pattern, 0.75, ColorUtils::alphaColor( light, 0.1 ) ); 3138 cairo_pattern_add_color_stop( pattern, 0.9, ColorUtils::Rgba::transparent( light ) ); 3139 3140 // in firefox a solid background must be filled 3141 if( tabOptions&Xul ) 3142 { 3143 cairo_set_source( context, base ); 3144 cairo_rectangle( context, fillSlab._x, fillSlab._y, fillSlab._w, fillSlab._h ); 3145 cairo_fill( context ); 3146 } 3147 3148 // draw pattern 3149 cairo_set_source( context, pattern ); 3150 cairo_rectangle( context, fillSlab._x, fillSlab._y, fillSlab._w, fillSlab._h ); 3151 cairo_fill( context ); 3152 3153 // render connections to frame 3154 for( SlabRect::List::const_iterator iter = slabs.begin(); iter != slabs.end(); ++iter ) 3155 { _helper.slab(base, 0).render( context, iter->_x, iter->_y, iter->_w, iter->_h, iter->_tiles ); } 3156 3157 } 3158 3159 //____________________________________________________________________________________ 3160 void Style::renderInactiveTab_Single( 3161 GdkWindow* window, 3162 GdkRectangle* clipRect, 3163 gint x, gint y, gint w, gint h, 3164 GtkPositionType side, 3165 const StyleOptions& options, 3166 const TabOptions& tabOptions, 3167 const AnimationData& data 3168 ) 3169 { 3170 3171 // convenience flags 3172 const bool isFirstTabAligned( tabOptions & FirstTabAligned ); 3173 const bool isLastTabAligned( tabOptions & LastTabAligned ); 3174 3175 // get color 3176 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 3177 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 3178 const ColorUtils::Rgba dark( ColorUtils::darkColor( base ) ); 3179 3180 // create context 3181 Cairo::Context context( window, clipRect ); 3182 3183 // borders and connections to tabs 3184 // this is quite painfull and slipery code. 3185 // the same is true with oxygen-qt 3186 int offset = 2; 3187 int adjust = (tabOptions&Xul) ? 0:2; 3188 const TileSet::Tiles tabTiles( Style::tabTiles( side ) ); 3189 3190 SlabRect tabSlab; 3191 SlabRect::List slabs; 3192 switch( side ) 3193 { 3194 case GTK_POS_BOTTOM: 3195 { 3196 // main slab 3197 y += adjust; h -= 2*adjust; 3198 tabSlab = SlabRect( x, y-offset, w, h+9+offset, tabTiles ); 3199 if( isFirstTabAligned ) { tabSlab._x-=1; tabSlab._w+=1; } 3200 if( isLastTabAligned ) { tabSlab._w+=1; } 3201 3202 // connections to frame 3203 if( isFirstTabAligned ) slabs.push_back( SlabRect( x-1, y+h+offset-7, 8, 17, TileSet::Left, Hover ) ); 3204 if( isLastTabAligned ) slabs.push_back( SlabRect( x+w-7, y+h+offset-7, 8, 17, TileSet::Right, Hover ) ); 3205 break; 3206 } 3207 3208 case GTK_POS_TOP: 3209 { 3210 3211 // main slab 3212 y += adjust; h -= 2*adjust; 3213 tabSlab = SlabRect( x, y-9, w, h+11+offset, tabTiles ); 3214 if( isFirstTabAligned ) { tabSlab._x-=1; tabSlab._w+=1; } 3215 if( isLastTabAligned ) { tabSlab._w-=1; } 3216 3217 // connections to frame 3218 if( isFirstTabAligned ) slabs.push_back( SlabRect( x-1, y-13+offset, 8, 16, TileSet::Left, Hover ) ); 3219 if( isLastTabAligned ) slabs.push_back( SlabRect( x+w-7, y-13+offset, 8, 16, TileSet::Right, Hover ) ); 3220 break; 3221 } 3222 3223 case GTK_POS_RIGHT: 3224 { 3225 3226 // main slab 3227 x += adjust; w -= 2*adjust; 3228 tabSlab = SlabRect( x-offset, y, w+9+offset, h, tabTiles ); 3229 if( isFirstTabAligned ) { tabSlab._y-=1; tabSlab._h+=1; } 3230 if( isLastTabAligned ) { tabSlab._h+=1; } 3231 3232 // connections to frame 3233 if( isFirstTabAligned ) slabs.push_back( SlabRect( x+w+offset-7, y-1, 17, 8, TileSet::Top, Hover ) ); 3234 if( isLastTabAligned ) slabs.push_back( SlabRect( x+w+offset-7, y+h-7, 17, 8, TileSet::Top, Hover ) ); 3235 break; 3236 } 3237 3238 3239 case GTK_POS_LEFT: 3240 { 3241 3242 // main slab 3243 x += adjust; w -= 2*adjust; 3244 tabSlab = SlabRect( x-9, y, w+11+offset, h, tabTiles ); 3245 if( isFirstTabAligned ) { tabSlab._y-=1; tabSlab._h+=1; } 3246 if( isLastTabAligned ) { tabSlab._h+=1; } 3247 3248 // connections to frame 3249 SlabRect baseSlab( x-10+1, y-6, 10, h+12, TileSet::Right ); 3250 if( isFirstTabAligned ) slabs.push_back( SlabRect( x-13 + offset, y-1, 16, 8, TileSet::Top, Hover ) ); 3251 if( isLastTabAligned )slabs.push_back( SlabRect( x-13 + offset, y+h-7, 16, 8, TileSet::Top, Hover ) ); 3252 break; 3253 } 3254 3255 default: return; 3256 } 3257 3258 // render tab 3259 ColorUtils::Rgba glow; 3260 if( data._mode == AnimationHover ) glow = ColorUtils::alphaColor( _settings.palette().color( Palette::Hover ), data._opacity ); 3261 else if( options&Hover ) glow = _settings.palette().color( Palette::Hover ); 3262 3263 _helper.slab( base, glow ).render( context, tabSlab._x, tabSlab._y, tabSlab._w, tabSlab._h, tabSlab._tiles ); 3264 3265 // adjust rect for filling 3266 SlabRect fillSlab( tabSlab ); 3267 fillSlab._x += 4; 3268 fillSlab._y += 4; 3269 fillSlab._w -= 8; 3270 fillSlab._h -= 8; 3271 3272 // fill 3273 Cairo::Pattern pattern; 3274 switch( side ) 3275 { 3276 case GTK_POS_BOTTOM: 3277 fillSlab._h -= 3; 3278 pattern.set( cairo_pattern_create_linear( 0, fillSlab._y, 0, fillSlab._y + fillSlab._h ) ); 3279 break; 3280 3281 case GTK_POS_TOP: 3282 fillSlab._y += 3; 3283 fillSlab._h -= 3; 3284 pattern.set( cairo_pattern_create_linear( 0, fillSlab._y + fillSlab._h, 0, fillSlab._y ) ); 3285 break; 3286 3287 case GTK_POS_RIGHT: 3288 fillSlab._w -= 3; 3289 pattern.set( cairo_pattern_create_linear( fillSlab._x, 0, fillSlab._x + fillSlab._w, 0 ) ); 3290 break; 3291 3292 case GTK_POS_LEFT: 3293 fillSlab._x += 3; 3294 fillSlab._w -= 3; 3295 pattern.set( cairo_pattern_create_linear( fillSlab._x + fillSlab._w, 0, fillSlab._x, 0 ) ); 3296 break; 3297 3298 default: return; 3299 3300 } 3301 3302 cairo_pattern_add_color_stop( pattern, 0.0, ColorUtils::alphaColor( light, 0.1 ) ); 3303 cairo_pattern_add_color_stop( pattern, 0.4, ColorUtils::alphaColor( dark, 0.5 ) ); 3304 cairo_pattern_add_color_stop( pattern, 0.8, ColorUtils::alphaColor( dark, 0.4 ) ); 3305 3306 // draw pattern 3307 cairo_set_source( context, pattern ); 3308 cairo_rectangle( context, fillSlab._x, fillSlab._y, fillSlab._w, fillSlab._h ); 3309 cairo_fill( context ); 3310 3311 // render connections to frame 3312 for( SlabRect::List::const_iterator iter = slabs.begin(); iter != slabs.end(); ++iter ) 3313 { 3314 3315 if( (iter->_options&Hover) && glow.isValid() ) 3316 { 3317 3318 _helper.slab(base, glow).render( context, iter->_x, iter->_y, iter->_w, iter->_h, iter->_tiles ); 3319 3320 } else { 3321 3322 _helper.slab(base).render( context, iter->_x, iter->_y, iter->_w, iter->_h, iter->_tiles ); 3323 3324 } 3325 } 3326 } 3327 3328 //____________________________________________________________________________________ 3329 void Style::renderInactiveTab_Plain( 3330 GdkWindow* window, 3331 GdkRectangle* clipRect, 3332 gint x, gint y, gint w, gint h, 3333 GtkPositionType side, 3334 const StyleOptions& options, 3335 const TabOptions& tabOptions, 3336 const AnimationData& data 3337 ) 3338 { 3339 // convenience flags 3340 const bool isFirstTabAligned( tabOptions & FirstTabAligned ); 3341 const bool isLastTabAligned( tabOptions & LastTabAligned ); 3342 3343 const bool isLeftOfSelected( tabOptions & LeftOfSelected ); 3344 const bool isRightOfSelected( tabOptions & RightOfSelected ); 3345 3346 // get color 3347 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 3348 3349 // create context 3350 Cairo::Context context( window, clipRect ); 3351 3352 // borders and connections to tabs 3353 // this is quite painfull and slipery code. 3354 // the same is true with oxygen-qt 3355 int offset = 2; 3356 int adjust = (tabOptions&Xul) ? 0:2; 3357 const TileSet::Tiles tabTiles( Style::tabTiles( side ) ); 3358 3359 SlabRect tabSlab; 3360 SlabRect::List slabs; 3361 switch( side ) 3362 { 3363 case GTK_POS_BOTTOM: 3364 { 3365 // main slab 3366 y += adjust; h -= 2*adjust; 3367 tabSlab = SlabRect( x, y-offset, w, h+10 + offset, tabTiles ); 3368 if( isFirstTabAligned ) { tabSlab._x-=1; tabSlab._w+=1; } 3369 if( isLastTabAligned ) { tabSlab._w+=1; } 3370 3371 // connections to frame 3372 SlabRect baseSlab( x-4-1, y+h-1, w+8+2, 10, TileSet::Top ); 3373 if( isFirstTabAligned ) 3374 { 3375 baseSlab._x += 4; baseSlab._w -= 4; baseSlab._tiles |= TileSet::Left; 3376 slabs.push_back( SlabRect( x-1, y+h+offset-6, 8, 16, TileSet::Left ) ); 3377 } 3378 3379 if( isLastTabAligned ) 3380 { 3381 baseSlab._w -= 4; baseSlab._tiles |= TileSet::Right; 3382 slabs.push_back( SlabRect( x+w-7, y+h+offset-6, 8, 16, TileSet::Right ) ); 3383 } 3384 3385 if( isLeftOfSelected ) { baseSlab._w += 3; } 3386 else if( isRightOfSelected ) { baseSlab._x -= 3; baseSlab._w += 4; } 3387 else { baseSlab._w += 2; } 3388 3389 slabs.push_back( baseSlab ); 3390 break; 3391 } 3392 3393 case GTK_POS_TOP: 3394 { 3395 3396 // main slab 3397 y += adjust; h -= 2*adjust; 3398 tabSlab = SlabRect( x, y-10, w, h+10+offset, tabTiles ); 3399 if( isFirstTabAligned ) { tabSlab._x-=1; tabSlab._w+=1; } 3400 if( isLastTabAligned ) { tabSlab._w-=1; } 3401 3402 // connections to frame 3403 SlabRect baseSlab( x-4-1, y-10+1, w+8+2, 10, TileSet::Bottom ); 3404 if( isFirstTabAligned ) { baseSlab._x += 4; baseSlab._w -= 4; baseSlab._tiles |= TileSet::Left; } 3405 if( isLastTabAligned ) { baseSlab._w -=4; baseSlab._tiles |= TileSet::Right; } 3406 if( isLeftOfSelected ) { baseSlab._w += 3; } 3407 else if( isRightOfSelected ) { baseSlab._x -= 3; baseSlab._w += 4; } 3408 else { baseSlab._w += 2; } 3409 3410 slabs.push_back( baseSlab ); 3411 break; 3412 } 3413 3414 case GTK_POS_RIGHT: 3415 { 3416 3417 // main slab 3418 x += adjust; w -= 2*adjust; 3419 tabSlab = SlabRect( x-offset, y, w+10+offset, h, tabTiles ); 3420 if( isFirstTabAligned ) { tabSlab._y-=1; tabSlab._h+=1; } 3421 if( isLastTabAligned ) { tabSlab._h+=1; } 3422 3423 // connections to frame 3424 SlabRect baseSlab( x+w-1, y-4-1, 10, h+8+3, TileSet::Left ); 3425 if( isFirstTabAligned ) 3426 { 3427 baseSlab._y += 4; baseSlab._h -= 4; baseSlab._tiles |= TileSet::Top; 3428 slabs.push_back( SlabRect( x+w+offset-6, y-1, 16, 8, TileSet::Top ) ); 3429 } 3430 3431 if( isLastTabAligned ) 3432 { 3433 baseSlab._h -= 4; baseSlab._tiles |= TileSet::Bottom; 3434 slabs.push_back( SlabRect( x+w+offset-6, y+h-7, 16, 8, TileSet::Top ) ); 3435 } 3436 3437 if( isLeftOfSelected ) { baseSlab._h += 3; } 3438 else if( isRightOfSelected ) { baseSlab._y -= 3; baseSlab._h += 3; } 3439 else { baseSlab._h += 1; } 3440 3441 slabs.push_back( baseSlab ); 3442 break; 3443 } 3444 3445 3446 case GTK_POS_LEFT: 3447 { 3448 3449 // main slab 3450 x += adjust; w -= 2*adjust; 3451 tabSlab = SlabRect( x-10, y, w+10+offset, h, tabTiles ); 3452 if( isFirstTabAligned ) { tabSlab._y-=1; tabSlab._h+=1; } 3453 if( isLastTabAligned ) { tabSlab._h+=1; } 3454 3455 // connections to frame 3456 SlabRect baseSlab( x-10+1, y-4-1, 10, h+8+3, TileSet::Right ); 3457 if( isFirstTabAligned ) 3458 { 3459 baseSlab._y += 4; baseSlab._h -= 4; baseSlab._tiles |= TileSet::Top; 3460 slabs.push_back( SlabRect( x-10+1 + offset-5, y-1, 16, 8, TileSet::Top ) ); 3461 } 3462 3463 if( isLastTabAligned ) 3464 { 3465 baseSlab._h -= 4; baseSlab._tiles |= TileSet::Bottom; 3466 slabs.push_back( SlabRect( x-10+1 + offset-5, y+h-7, 16, 8, TileSet::Top ) ); 3467 } 3468 3469 if( isLeftOfSelected ) { baseSlab._h += 3; } 3470 else if( isRightOfSelected ) { baseSlab._y -= 3; baseSlab._h += 3; } 3471 else { baseSlab._h += 1; } 3472 3473 slabs.push_back( baseSlab ); 3474 break; 3475 } 3476 3477 default: return; 3478 } 3479 3480 const bool isFirstTab( tabOptions & FirstTab ); 3481 const bool isLastTab( tabOptions & LastTab ); 3482 3483 const double radius( 5 ); 3484 double xF( 0.5 + x ); 3485 double yF( 0.5 + y ); 3486 double wF( w-1 ); 3487 double hF( h-1 ); 3488 3489 switch( side ) 3490 { 3491 3492 case GTK_POS_BOTTOM: 3493 { 3494 xF += 1.0; 3495 wF -= 1.0; 3496 hF += 2; 3497 if( isLeftOfSelected ) wF += 1; 3498 else if( isRightOfSelected ) { xF -= 2; wF += 2; } 3499 3500 if( isFirstTab ) 3501 { 3502 3503 if( isFirstTabAligned ) cairo_move_to( context, xF, yF + hF + 2 ); 3504 else cairo_move_to( context, xF, yF + hF ); 3505 3506 cairo_line_to( context, xF, yF + radius ); 3507 cairo_arc( context, xF + radius, yF + radius, radius, M_PI, 3.0*M_PI/2 ); 3508 cairo_line_to( context, xF + wF, yF ); 3509 cairo_line_to( context, xF + wF, yF + hF ); 3510 3511 } else if( isLastTab ) { 3512 3513 cairo_move_to( context, xF, yF + hF ); 3514 cairo_line_to( context, xF, yF ); 3515 cairo_line_to( context, xF + wF - radius, yF ); 3516 cairo_arc( context, xF + wF - radius, yF + radius, radius, 3.0*M_PI/2, 2.0*M_PI ); 3517 if( isLastTabAligned ) cairo_line_to( context, xF + wF, yF + hF + 2 ); 3518 else cairo_line_to( context, xF + wF, yF + hF ); 3519 3520 } else { 3521 3522 cairo_move_to( context, xF, yF + hF ); 3523 cairo_line_to( context, xF, yF ); 3524 cairo_line_to( context, xF + wF, yF ); 3525 cairo_line_to( context, xF + wF, yF + hF ); 3526 3527 } 3528 3529 } 3530 3531 break; 3532 3533 case GTK_POS_TOP: 3534 { 3535 xF += 1.0; 3536 wF -= 1.0; 3537 yF -= 1; 3538 hF += 1; 3539 if( isLeftOfSelected ) wF += 1; 3540 else if( isRightOfSelected ) { xF -= 2; wF += 2; } 3541 3542 3543 if( isFirstTab ) 3544 { 3545 3546 cairo_move_to( context, xF+wF, yF ); 3547 cairo_line_to( context, xF+wF, yF + hF ); 3548 cairo_line_to( context, xF+radius, yF + hF ); 3549 cairo_arc( context, xF+radius, yF + hF -radius, radius, M_PI/2, M_PI ); 3550 if( isFirstTabAligned ) cairo_line_to( context, xF, yF - 2 ); 3551 else cairo_line_to( context, xF, yF ); 3552 3553 } else if( isLastTab ) { 3554 3555 if( isLastTabAligned ) cairo_move_to( context, xF+wF, yF-2 ); 3556 else cairo_move_to( context, xF+wF, yF-2 ); 3557 cairo_line_to( context, xF+wF, yF+hF-radius ); 3558 cairo_arc( context, xF+wF-radius, yF+hF-radius, radius, 0, M_PI/2 ); 3559 cairo_line_to( context, xF, yF+hF ); 3560 cairo_line_to( context, xF, yF ); 3561 3562 } else { 3563 3564 cairo_move_to( context, xF+wF, yF ); 3565 cairo_line_to( context, xF+wF, yF + hF ); 3566 cairo_line_to( context, xF, yF+hF ); 3567 cairo_line_to( context, xF, yF ); 3568 3569 } 3570 3571 } 3572 3573 break; 3574 3575 case GTK_POS_RIGHT: 3576 { 3577 3578 yF += 1.0; 3579 hF -= 1.0; 3580 wF += 2; 3581 3582 if( isLeftOfSelected ) hF += 1; 3583 else if( isRightOfSelected ) { yF -= 2; hF += 2; } 3584 3585 if( isFirstTab ) 3586 { 3587 3588 cairo_move_to( context, xF+wF, yF+hF ); 3589 cairo_line_to( context, xF, yF+hF ); 3590 cairo_line_to( context, xF, yF+radius ); 3591 cairo_arc( context, xF+radius, yF+radius, radius, M_PI, 3.0*M_PI/2 ); 3592 if( isFirstTabAligned ) cairo_line_to( context, xF+wF+2, yF ); 3593 else cairo_line_to( context, xF+wF, yF ); 3594 3595 } else if( isLastTab ) { 3596 3597 if( isLastTabAligned ) cairo_line_to( context, xF + wF + 2, yF + hF ); 3598 else cairo_line_to( context, xF + wF, yF + hF ); 3599 cairo_line_to( context, xF+radius, yF+hF ); 3600 cairo_arc( context, xF+radius, yF+hF - radius, radius, M_PI/2, M_PI ); 3601 cairo_line_to( context, xF, yF ); 3602 cairo_line_to( context, xF + wF, yF ); 3603 3604 } else { 3605 3606 cairo_move_to( context, xF+wF, yF+hF ); 3607 cairo_line_to( context, xF, yF+hF ); 3608 cairo_line_to( context, xF, yF ); 3609 cairo_line_to( context, xF+wF, yF ); 3610 3611 } 3612 } 3613 break; 3614 3615 case GTK_POS_LEFT: 3616 { 3617 yF += 1.0; 3618 hF -= 1.0; 3619 xF -= 2; 3620 wF += 2; 3621 3622 if( isLeftOfSelected ) hF += 1; 3623 else if( isRightOfSelected ) { yF -= 2; hF += 2; } 3624 3625 if( isFirstTab ) 3626 { 3627 3628 if( isFirstTabAligned ) cairo_move_to( context, xF-2, yF ); 3629 else cairo_move_to( context, xF, yF ); 3630 cairo_line_to( context, xF + wF - radius, yF ); 3631 cairo_arc( context, xF + wF - radius, yF + radius, radius, 3.0*M_PI/2, 2*M_PI ); 3632 cairo_line_to( context, xF+wF, yF+hF ); 3633 cairo_line_to( context, xF, yF+hF ); 3634 3635 } else if( isLastTab ) { 3636 3637 cairo_move_to( context, xF, yF ); 3638 cairo_line_to( context, xF+wF, yF ); 3639 cairo_line_to( context, xF+wF, yF + hF - radius ); 3640 cairo_arc( context, xF+wF-radius, yF + hF - radius, radius, 0, M_PI/2 ); 3641 if( isLastTabAligned ) cairo_line_to( context, xF-2, yF+hF ); 3642 else cairo_line_to( context, xF, yF+hF ); 3643 3644 } else { 3645 3646 cairo_move_to( context, xF, yF ); 3647 cairo_line_to( context, xF+wF, yF ); 3648 cairo_line_to( context, xF+wF, yF+hF ); 3649 cairo_line_to( context, xF, yF+hF ); 3650 3651 } 3652 } 3653 break; 3654 3655 default: return; 3656 3657 } 3658 3659 ColorUtils::Rgba backgroundColor( base ); 3660 { 3661 3662 gint wh, wy; 3663 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 3664 if( wh > 0 ) 3665 { backgroundColor = ColorUtils::backgroundColor( _settings.palette().color( Palette::Window ), wh, y+wy+h/2 ); } 3666 3667 } 3668 3669 const ColorUtils::Rgba midColor( ColorUtils::alphaColor( ColorUtils::darkColor( backgroundColor ), 0.4 ) ); 3670 const ColorUtils::Rgba darkColor( ColorUtils::alphaColor( ColorUtils::darkColor( backgroundColor ), 0.8 ) ); 3671 3672 cairo_set_line_width( context, 1.0 ); 3673 cairo_set_source( context, midColor ); 3674 cairo_fill_preserve( context ); 3675 3676 cairo_set_source( context, darkColor ); 3677 cairo_stroke( context ); 3678 3679 ColorUtils::Rgba glow; 3680 if( data._mode == AnimationHover ) glow = ColorUtils::alphaColor( _settings.palette().color( Palette::Hover ), data._opacity ); 3681 else if( options&Hover ) glow = _settings.palette().color( Palette::Hover ); 3682 3683 for( SlabRect::List::const_iterator iter = slabs.begin(); iter != slabs.end(); ++iter ) 3684 { _helper.slab(base, glow, 0).render( context, iter->_x, iter->_y, iter->_w, iter->_h, iter->_tiles ); } 3685 3686 } 3687 3688 //____________________________________________________________________________________ 3689 ColorUtils::Rgba Style::slabShadowColor( const StyleOptions& options, const AnimationData& data ) const 3690 { 3691 3692 // no glow when widget is disabled 3693 if( options&Disabled ) return ColorUtils::Rgba(); 3694 3695 if( (options&Flat) && !(options&Sunken) ) 3696 { 3697 3698 /* 3699 flat buttons have special handling of colors: hover and focus are both assigned 3700 the hover color. This is consistent with oxygen-qt, though quite inconsistent with 3701 other widgets. 3702 */ 3703 if( 3704 ( data._mode == AnimationHover && (options&Focus) ) || 3705 ( data._mode == AnimationFocus && (options&Hover) ) ) 3706 { 3707 return _settings.palette().color( Palette::Focus ); 3708 3709 } else if( data._mode & (AnimationHover|AnimationFocus) ) { 3710 3711 return ColorUtils::alphaColor( _settings.palette().color( Palette::Focus ), data._opacity ); 3712 3713 } else if( options&(Focus|Hover) ) { 3714 3715 return _settings.palette().color( Palette::Focus ); 3716 3717 } else return ColorUtils::Rgba(); 3718 3719 } else if( data._mode == AnimationHover ) { 3720 3721 if( options & Focus ) 3722 { 3723 return ColorUtils::mix( 3724 _settings.palette().color( Palette::Focus ), 3725 _settings.palette().color( Palette::Hover ), data._opacity ); 3726 3727 } else { 3728 3729 return ColorUtils::alphaColor( _settings.palette().color( Palette::Hover ), data._opacity ); 3730 3731 } 3732 3733 } else if( options&Hover ) { 3734 3735 return _settings.palette().color( Palette::Hover ); 3736 3737 } else if( data._mode == AnimationFocus ) { 3738 3739 return ColorUtils::alphaColor( _settings.palette().color( Palette::Focus ), data._opacity ); 3740 3741 } else if( options&Focus ) { 3742 3743 return _settings.palette().color( Palette::Focus ); 3744 3745 } else return ColorUtils::Rgba(); 3746 3747 } 3748 3749 //____________________________________________________________________________________ 3750 ColorUtils::Rgba Style::holeShadowColor( const StyleOptions& options, const AnimationData& data ) const 3751 { 3752 3753 // no glow when widget is disabled 3754 if( options&Disabled ) return ColorUtils::Rgba(); 3755 3756 if( data._mode == AnimationFocus && data._opacity >= 0 ) 3757 { 3758 3759 if( options & Hover ) 3760 { 3761 3762 return ColorUtils::mix( 3763 _settings.palette().color( Palette::Hover ), 3764 _settings.palette().color( Palette::Focus ), data._opacity ); 3765 3766 } else return ColorUtils::alphaColor( _settings.palette().color( Palette::Focus ), data._opacity ); 3767 3768 } else if( options & Focus ) { 3769 3770 return _settings.palette().color( Palette::Focus ); 3771 3772 } else if( data._mode == AnimationHover && data._opacity >= 0 ) { 3773 3774 return ColorUtils::alphaColor( _settings.palette().color( Palette::Hover ), data._opacity ); 3775 3776 } else if( options & Hover ) { 3777 3778 return _settings.palette().color( Palette::Hover ); 3779 3780 } else return ColorUtils::Rgba(); 3781 3782 } 3783 3784 //__________________________________________________________________ 3785 void Style::renderGroupBox( 3786 cairo_t* context, 3787 const ColorUtils::Rgba& base, 3788 gint x, gint y, gint w, gint h, 3789 const StyleOptions& options ) 3790 { 3791 3792 cairo_push_group( context ); 3793 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, y - h + 12, 0, y + 2*h - 19 ) ); 3794 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 3795 cairo_pattern_add_color_stop( pattern, 0, ColorUtils::alphaColor( light, 0.4 ) ); 3796 cairo_pattern_add_color_stop( pattern, 1, ColorUtils::Rgba::transparent( light ) ); 3797 cairo_set_source( context, pattern ); 3798 3799 if( !_settings.applicationName().useFlatBackground( 0L ) ) 3800 _helper.fillSlab( context, x, y, w, h ); 3801 3802 if( !(options&NoFill) ) 3803 { _helper.slope( base, 0.0 ).render( context, x, y, w, h ); } 3804 3805 cairo_pop_group_to_source( context ); 3806 3807 Cairo::Pattern mask( cairo_pattern_create_linear( 0, y + h - 19, 0, y + h ) ); 3808 cairo_pattern_add_color_stop( mask, 0, ColorUtils::Rgba::black() ); 3809 cairo_pattern_add_color_stop( mask, 1.0, ColorUtils::Rgba::transparent() ); 3810 cairo_mask( context, mask ); 3811 3812 return; 3813 3814 } 3815 3816 //__________________________________________________________________ 3817 void Style::renderSlab( 3818 Cairo::Context& context, 3819 gint x, gint y, gint w, gint h, 3820 const ColorUtils::Rgba& base, 3821 const StyleOptions& options, 3822 const AnimationData& animationData, 3823 TileSet::Tiles tiles ) 3824 { 3825 3826 // do nothing if not enough room 3827 if( w<14 || h<14 ) return; 3828 3829 // additional adjustment for sunken frames 3830 // TODO: double check 3831 if( options & Sunken) 3832 { 3833 3834 x -= 1; 3835 w += 2; 3836 h += 2; 3837 3838 } 3839 3840 // fill 3841 if( !(options & NoFill)) 3842 { 3843 3844 Cairo::Pattern pattern; 3845 const ColorUtils::Rgba shadow( ColorUtils::shadowColor( base ) ); 3846 if( shadow.value() > base.value() && (options & Sunken) ) 3847 { 3848 3849 pattern.set( cairo_pattern_create_linear( 0, y, 0, y+2*h ) ); 3850 cairo_pattern_add_color_stop( pattern, 0, base ); 3851 cairo_pattern_add_color_stop( pattern, 1.0, ColorUtils::lightColor( base ) ); 3852 3853 } else { 3854 3855 pattern.set( cairo_pattern_create_linear( 0, y-h, 0, y+h ) ); 3856 cairo_pattern_add_color_stop( pattern, 0, ColorUtils::lightColor( base ) ); 3857 cairo_pattern_add_color_stop( pattern, 1.0, base ); 3858 3859 } 3860 3861 cairo_set_source( context, pattern ); 3862 _helper.fillSlab( context, x, y, w, h, tiles ); 3863 3864 } 3865 3866 if( !(options&Sunken) ) { 3867 3868 // calculate glow color 3869 const TileSet* tile; 3870 const ColorUtils::Rgba glow( slabShadowColor( options, animationData ) ); 3871 if( glow.isValid() || base.isValid() ) tile = &_helper.slab( base, glow , 0); 3872 else return; 3873 3874 if( tile ) tile->render( context, x, y, w, h ); 3875 3876 } else if( base.isValid() ) { 3877 3878 _helper.slabSunken( base ).render( context, x, y, w, h ); 3879 3880 } 3881 3882 } 3883 3884 //__________________________________________________________________ 3885 void Style::renderScrollBarHole( Cairo::Context& context, gint x, gint y, gint w, gint h, const ColorUtils::Rgba& base, bool vertical, TileSet::Tiles tiles ) 3886 { 3887 3888 // use tileset from helper 3889 _helper.scrollHole( base, vertical ).render( context, x, y, w, h, tiles ); 3890 3891 } 3892 3893 //__________________________________________________________________ 3894 Polygon Style::genericArrow( GtkArrowType orientation, QtSettings::ArrowSize size ) const 3895 { 3896 3897 Polygon a; 3898 switch( orientation ) 3899 { 3900 3901 case GTK_ARROW_UP: 3902 { 3903 if( size == QtSettings::ArrowTiny ) a << Point( -1.75, 1.125 ) << Point( 0.5, -1.125 ) << Point( 2.75, 1.125 ); 3904 else if( size == QtSettings::ArrowSmall ) a << Point( -2,1.5 ) << Point( 0.5, -1.5 ) << Point( 3,1.5 ); 3905 else a << Point( -3,2.5 ) << Point( 0.5, -1.5 ) << Point( 4,2.5 ); 3906 break; 3907 } 3908 3909 case GTK_ARROW_DOWN: 3910 { 3911 if( size == QtSettings::ArrowTiny ) a << Point( -1.75, -1.125 ) << Point( 0.5, 1.125 ) << Point( 2.75, -1.125 ); 3912 else if( size == QtSettings::ArrowSmall ) a << Point( -2,-1.5 ) << Point( 0.5, 1.5 ) << Point( 3,-1.5 ); 3913 else a << Point( -3,-1.5 ) << Point( 0.5, 2.5 ) << Point( 4,-1.5 ); 3914 break; 3915 } 3916 3917 case GTK_ARROW_LEFT: 3918 { 3919 if( size == QtSettings::ArrowTiny ) a << Point( 1.125, -1.75 ) << Point( -1.125, 0.5 ) << Point( 1.125, 2.75 ); 3920 else if( size == QtSettings::ArrowSmall ) a << Point( 1.5,-2 ) << Point( -1.5, 0.5 ) << Point( 1.5,3 ); 3921 else a << Point( 2.5,-3 ) << Point( -1.5, 0.5 ) << Point( 2.5,4 ); 3922 break; 3923 } 3924 3925 case GTK_ARROW_RIGHT: 3926 { 3927 if( size == QtSettings::ArrowTiny ) a << Point( -1.125, -1.75 ) << Point( 1.125, 0.5 ) << Point( -1.125, 2.75 ); 3928 else if( size == QtSettings::ArrowSmall ) a << Point( -1.5,-2 ) << Point( 1.5, 0.5 ) << Point( -1.5,3 ); 3929 else a << Point( -1.5,-3 ) << Point( 2.5, 0.5 ) << Point( -1.5,4 ); 3930 break; 3931 } 3932 3933 default: break; 3934 3935 } 3936 3937 return a; 3938 3939 3940 3941 } 3942 3943 //__________________________________________________________________ 3944 void Style::renderWindowDots(cairo_t* context, gint x, gint y, gint w, gint h, const ColorUtils::Rgba& color, WinDeco::Options wopt) 3945 { 3946 bool isMaximized( wopt & WinDeco::Maximized ); 3947 bool hasAlpha( wopt & WinDeco::Alpha ); 3948 int offset( hasAlpha ? 0 : -1 ); 3949 if( _settings.frameBorder() >= QtSettings::BorderTiny ) 3950 { 3951 if( !isMaximized ) 3952 { 3953 // Draw right side 3-dots resize handles 3954 int cenY = int(h/2+y); 3955 int posX = int(w+x-3) + 1; 3956 _helper.renderDot(context,color,posX+offset, cenY-3); 3957 _helper.renderDot(context,color,posX+offset, cenY); 3958 _helper.renderDot(context,color,posX+offset, cenY+3); 3959 } 3960 3961 // Draw bottom-right corner 3-dots resize handles 3962 // if( !config.drawSizeGrip ) 3963 { 3964 cairo_save(context); 3965 cairo_translate(context,x+w-8,y+h-8); 3966 _helper.renderDot(context,color,2+offset,6+offset); 3967 _helper.renderDot(context,color,5+offset,5+offset); 3968 _helper.renderDot(context,color,6+offset,2+offset); 3969 cairo_restore(context); 3970 } 3971 } 3972 } 3973 3974 //__________________________________________________________________ 3975 void Style::centerRect( GdkRectangle* parent, GdkRectangle* child ) const 3976 { 3977 if( !( parent && child ) ) return; 3978 child->x = parent->x + (parent->width - child->width)/2; 3979 child->y = parent->y + (parent->height - child->height)/2; 3980 return; 3981 } 3982 3983 //__________________________________________________________________ 3984 void Style::generateGapMask( Cairo::Context& context, gint x, gint y, gint w, gint h, const Gtk::Gap& gap ) const 3985 { 3986 3987 if( gap.width() <= 0 ) return; 3988 3989 // store current rect in 3990 GdkRectangle mask( Gtk::gdk_rectangle() ); 3991 3992 switch( gap.position() ) 3993 { 3994 case GTK_POS_TOP: 3995 { 3996 mask = Gtk::gdk_rectangle( x+gap.x(), y, gap.width(), gap.height() ); 3997 break; 3998 } 3999 4000 case GTK_POS_BOTTOM: 4001 { 4002 mask = Gtk::gdk_rectangle( x+gap.x(), y+h-gap.height(), gap.width(), gap.height() ); 4003 break; 4004 } 4005 4006 case GTK_POS_LEFT: 4007 { 4008 mask = Gtk::gdk_rectangle( x, y+gap.x(), gap.height(), gap.width() ); 4009 break; 4010 } 4011 4012 case GTK_POS_RIGHT: 4013 { 4014 mask = Gtk::gdk_rectangle( x + w - gap.height(), y+gap.x(), gap.height(), gap.width() ); 4015 break; 4016 } 4017 4018 default: return; 4019 } 4020 4021 if( false ) 4022 { 4023 cairo_set_source( context, ColorUtils::Rgba( 1, 0, 0, 0.3 ) ); 4024 gdk_cairo_rectangle( context, &mask ); 4025 cairo_fill( context ); 4026 } 4027 4028 cairo_rectangle( context, x, y, w, h ); 4029 cairo_rectangle_negative( context, mask.x, mask.y, mask.width, mask.height ); 4030 cairo_clip( context ); 4031 4032 return; 4033 4034 } 4035 4036 //_________________________________________________________ 4037 void Style::fileChanged( GFileMonitor*, GFile* file, GFile*, GFileMonitorEvent event, gpointer data ) 4038 { 4039 4040 #if OXYGEN_DEBUG 4041 std::cerr << "Oxygen::Style::fileChanged -" 4042 << " file: " << g_file_get_path( file ) 4043 << " event: " << Gtk::TypeNames::fileMonitorEvent( event ) 4044 << std::endl; 4045 #endif 4046 4047 Style& style( *static_cast<Style*>( data ) ); 4048 if( style.initialize( QtSettings::All|QtSettings::Forced ) ) 4049 { gtk_rc_reset_styles( gtk_settings_get_default() ); } 4050 4051 } 4052 4053 //_______________________________________________________________________ 4054 void Style::renderTabCloseIcon(cairo_t* context, GdkRectangle* r) const 4055 { 4056 cairo_save(context); 4057 cairo_translate(context,r->x,r->y); 4058 4059 cairo_move_to( context, 5.5, 5.5 ); cairo_line_to( context, 10.5, 10.5 ); 4060 cairo_move_to( context, 10.5, 5.5 ); cairo_line_to( context, 5.5, 10.5 ); 4061 cairo_stroke( context ); 4062 4063 cairo_restore(context); 4064 } 4065 4066 //_______________________________________________________________________________ 4067 void Style::renderTabCloseButton(cairo_t* context, GdkRectangle* r, const ColorUtils::Rgba& base, const ColorUtils::Rgba& color) 4068 { 4069 cairo_save(context); 4070 4071 cairo_set_source_surface(context,_helper.dockWidgetButton(base,true,r->width),0,0); 4072 cairo_rectangle(context,r->x,r->y,r->width,r->height); 4073 cairo_fill(context); 4074 4075 const double width(1.1); 4076 4077 // contrast 4078 cairo_translate(context,0,0.5); 4079 cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND ); 4080 cairo_set_line_join( context, CAIRO_LINE_JOIN_ROUND ); 4081 cairo_set_line_width(context,width); 4082 cairo_set_source(context,ColorUtils::lightColor( base )); 4083 4084 renderTabCloseIcon(context,r); 4085 4086 // main icon painting 4087 cairo_translate(context,0,-1); 4088 cairo_set_source(context,color); 4089 4090 renderTabCloseIcon(context,r); 4091 4092 cairo_restore(context); 4093 } 4094 4095 //_________________________________________________________ 4096 void Style::adjustMask( GtkWidget* widget, int width, int height, bool alpha ) 4097 { 4098 4099 // get window and decide offset 4100 GdkWindow* window(0); 4101 int verticalMaskOffset(0); 4102 if( GTK_IS_MENU( widget ) ) 4103 { 4104 4105 window = gtk_widget_get_parent_window( widget ); 4106 verticalMaskOffset=Oxygen::Menu_VerticalOffset; 4107 4108 } else if( 4109 Gtk::gtk_is_tooltip( widget ) || 4110 Gtk::gtk_combobox_is_popup( widget ) || 4111 Gtk::gtk_combo_is_popup( widget ) ) { 4112 4113 window=gtk_widget_get_window( widget ); 4114 4115 } else { 4116 4117 std::cerr << "FIXME: Oxygen::WidgetSizeData: unknown window type: \""<< Gtk::gtk_widget_path( widget )<<"\"\n"; 4118 return; 4119 4120 } 4121 4122 // adjust mask 4123 if(!alpha) 4124 { 4125 4126 // make menus/tooltips/combo lists appear rounded using XShape extension if screen isn't composited 4127 GdkPixmap* mask( _helper.roundMask( width, height - 2*verticalMaskOffset) ); 4128 gdk_window_shape_combine_mask( window, mask, 0, verticalMaskOffset ); 4129 gdk_pixmap_unref(mask); 4130 4131 } else { 4132 4133 // reset mask if compositing has appeared after we had set a mask 4134 gdk_window_shape_combine_mask( window, NULL, 0, 0); 4135 4136 } 4137 4138 } 4139 4140 //_________________________________________________________ 4141 void Style::setWindowBlur( GtkWidget* widget, bool enable ) 4142 { 4143 4144 #ifdef GDK_WINDOWING_X11 4145 GdkWindow* window( 0L ); 4146 if( GTK_IS_MENU( widget ) ) 4147 { 4148 4149 window = gtk_widget_get_parent_window( widget ); 4150 4151 } else if( 4152 Gtk::gtk_is_tooltip( widget ) || 4153 Gtk::gtk_combobox_is_popup( widget ) || 4154 Gtk::gtk_combo_is_popup( widget ) ) { 4155 4156 window=gtk_widget_get_window( widget ); 4157 4158 } else return; 4159 4160 // Make whole window blurred 4161 // FIXME: should roundedness be taken into account? 4162 #if GTK_CHECK_VERSION(2,24,0) 4163 const int w( gdk_window_get_width( window ) ); 4164 const int h( gdk_window_get_height( window ) ); 4165 GdkDisplay* gdkDisplay = gdk_window_get_display( window ); 4166 #else 4167 int w(0), h(0); 4168 gdk_drawable_get_size( window, &w, &h ); 4169 GdkDisplay* gdkDisplay = gdk_drawable_get_display( window ); 4170 #endif 4171 4172 const unsigned long rects[4] = { 0, 0, (unsigned long)w, (unsigned long)h }; 4173 const XID id( GDK_WINDOW_XID( window ) ); 4174 Display* display( GDK_DISPLAY_XDISPLAY( gdkDisplay ) ); 4175 4176 if(enable) 4177 { 4178 4179 XChangeProperty( display, id, _blurAtom, XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<const unsigned char*>(rects), 4 ); 4180 4181 } else XDeleteProperty( display, id, _blurAtom ); 4182 4183 #endif 4184 4185 } 4186 4187 }