1 /* 2 * this file is part of the oxygen gtk engine 3 * Copyright (c) 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr> 4 * Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@gmail.com> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or( at your option ) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free 18 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 19 * MA 02110-1301, USA. 20 */ 21 22 #include "oxygenstyle.h" 23 #include "oxygencairocontext.h" 24 #include "oxygencairoutils.h" 25 #include "oxygencolorutils.h" 26 #include "oxygenfontinfo.h" 27 #include "oxygengtkutils.h" 28 #include "oxygenmetrics.h" 29 #include "oxygenwindecobutton.h" 30 #include "oxygenwindowshadow.h" 31 32 #include "oxygengtktypenames.h" 33 34 #include <algorithm> 35 #include <cmath> 36 37 #ifdef GDK_WINDOWING_X11 38 #include <X11/Xatom.h> 39 #endif 40 41 namespace Oxygen 42 { 43 44 //__________________________________________________________________ 45 Style* Style::_instance = 0; instance(void)46 Style& Style::instance( void ) 47 { 48 if( !_instance ) 49 { 50 #if OXYGEN_DEBUG 51 std::cerr << "Oxygen::Style::instance - creating new style." << std::endl; 52 #endif 53 54 _instance = new Style(); 55 } 56 57 return *_instance; 58 } 59 60 //__________________________________________________________________ Style(void)61 Style::Style( void ) 62 { 63 #ifdef GDK_WINDOWING_X11 64 _blurAtom = None; 65 #endif 66 } 67 68 //__________________________________________________________________ initialize(unsigned int flags)69 bool Style::initialize( unsigned int flags ) 70 { 71 72 // initialize ref surface 73 _helper.initializeRefSurface(); 74 75 // reinitialize settings 76 if( !_settings.initialize( flags ) ) return false; 77 78 // reset caches if colors have changed 79 if( flags&QtSettings::Colors ) 80 { 81 _helper.clearCaches(); 82 ColorUtils::clearCaches(); 83 } 84 85 // connect files 86 QtSettings::FileMap& monitoredFiles( _settings.monitoredFiles() ); 87 for( QtSettings::FileMap::iterator iter = monitoredFiles.begin(); iter != monitoredFiles.end(); ++iter ) 88 { 89 if( !iter->second.signal.isConnected() ) 90 { iter->second.signal.connect( G_OBJECT( iter->second.monitor ), "changed", G_CALLBACK(fileChanged), this ); } 91 } 92 93 // reinitialize animations 94 _animations.initialize( _settings ); 95 96 if( flags&QtSettings::Oxygen ) 97 { 98 // pass window drag mode to window manager 99 if( !_settings.windowDragEnabled() ) _windowManager.setDragMode( WindowManager::Disabled ); 100 else if( _settings.windowDragMode() == QtSettings::WD_MINIMAL ) _windowManager.setDragMode( WindowManager::Minimal ); 101 else _windowManager.setDragMode( WindowManager::Full ); 102 103 // use window manager to handle window drag 104 _windowManager.setUseWMMoveResize( _settings.useWMMoveResize() ); 105 106 } 107 108 if( flags&QtSettings::KdeGlobals ) 109 { 110 // pass drag distance and delay to window manager 111 _windowManager.setDragDistance( _settings.startDragDist() ); 112 _windowManager.setDragDelay( _settings.startDragTime() ); 113 } 114 115 // background surface 116 if( !_settings.backgroundPixmap().empty() ) setBackgroundSurface( _settings.backgroundPixmap() ); 117 118 // create window shadow 119 WindowShadow shadow( _settings, _helper ); 120 _shadowHelper.setApplicationName( _settings.applicationName() ); 121 _shadowHelper.initialize( _settings.palette().color(Palette::Window), shadow ); 122 123 #ifdef GDK_WINDOWING_X11 124 if( _blurAtom == None ) 125 { 126 127 GdkDisplay *display( gdk_display_get_default() ); 128 if( display ) 129 { _blurAtom = XInternAtom(GDK_DISPLAY_XDISPLAY( display ),"_KDE_NET_WM_BLUR_BEHIND_REGION",False); } 130 131 } 132 133 #endif 134 135 return true; 136 137 } 138 139 //__________________________________________________________________ tabCloseButton(const StyleOptions & options)140 Cairo::Surface Style::tabCloseButton( const StyleOptions& options ) 141 { 142 143 // active tab 144 if( options&Focus ) 145 { 146 // create button 147 if( !_tabCloseButtons.active ) 148 { 149 const std::string filename( std::string(GTK_THEME_DIR)+ "/special-icons/standardbutton-closetab-down-16.png" ); 150 _tabCloseButtons.active = Cairo::Surface( cairo_image_surface_create_from_png( filename.c_str() ) ); 151 } 152 153 return _tabCloseButtons.active; 154 } 155 156 // prelight 157 if( options&Hover ) 158 { 159 // create button 160 if( !_tabCloseButtons.prelight ) 161 { 162 const std::string filename( std::string(GTK_THEME_DIR) + "/special-icons/standardbutton-closetab-hover-16.png" ); 163 _tabCloseButtons.prelight = Cairo::Surface( cairo_image_surface_create_from_png( filename.c_str() ) ); 164 } 165 166 return _tabCloseButtons.prelight; 167 168 } 169 170 // normal or inactive 171 if( !_tabCloseButtons.normal ) 172 { 173 const std::string filename( std::string(GTK_THEME_DIR) + "/special-icons/standardbutton-closetab-16.png" ); 174 _tabCloseButtons.normal = Cairo::Surface( cairo_image_surface_create_from_png( filename.c_str() ) ); 175 } 176 177 // inactive 178 if( (options&Disabled) && _tabCloseButtons.normal ) 179 { 180 181 if( !_tabCloseButtons.inactive ) 182 { 183 184 // make deep copy of the normal image 185 _tabCloseButtons.inactive = Cairo::Surface( cairo_surface_copy( _tabCloseButtons.normal ) ); 186 cairo_surface_add_alpha( _tabCloseButtons.inactive, 0.5 ); 187 cairo_image_surface_saturate( _tabCloseButtons.inactive, 0.1 ); 188 189 } 190 191 return _tabCloseButtons.inactive; 192 193 } 194 195 // fallback to normal 196 return _tabCloseButtons.normal; 197 198 } 199 200 //____________________________________________________________________________________ hasBackgroundSurface(void) const201 bool Style::hasBackgroundSurface( void ) const 202 { 203 if( !_backgroundSurface.isValid() ) return false; 204 const cairo_status_t status( cairo_surface_status( _backgroundSurface ) ); 205 return 206 status != CAIRO_STATUS_NO_MEMORY && 207 status != CAIRO_STATUS_FILE_NOT_FOUND && 208 status != CAIRO_STATUS_READ_ERROR; 209 } 210 211 //__________________________________________________________________ fill(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const ColorUtils::Rgba & color) const212 void Style::fill( GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h, const ColorUtils::Rgba& color ) const 213 { 214 215 // define colors 216 Cairo::Context context( window, clipRect ); 217 cairo_rectangle( context, x, y, w, h ); 218 cairo_set_source( context, color ); 219 cairo_fill( context ); 220 221 } 222 223 //__________________________________________________________________ outline(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const ColorUtils::Rgba & color) const224 void Style::outline( GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h, const ColorUtils::Rgba& color ) const 225 { 226 227 // define colors 228 Cairo::Context context( window, clipRect ); 229 cairo_rectangle( context, 0.5+x, 0.5+y, w-1, h-1 ); 230 cairo_set_line_width( context, 1 ); 231 cairo_set_source( context, color ); 232 cairo_stroke( context ); 233 234 } 235 236 //__________________________________________________________________ drawSeparator(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options)237 void Style::drawSeparator( GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h, const StyleOptions& options ) 238 { 239 240 // define colors 241 ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 242 if( options & Blend ) 243 { 244 245 gint wh, wy; 246 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 247 if( wh > 0 ) 248 { 249 if( options & Menu ) base = ColorUtils::menuBackgroundColor( _settings.palette().color( Palette::Window ), wh, y+wy+h/2 ); 250 else base = ColorUtils::backgroundColor( _settings.palette().color( Palette::Window ), wh, y+wy+h/2 ); 251 } 252 253 } 254 255 Cairo::Context context( window, clipRect ); 256 _helper.drawSeparator( context, base, x, y, w, h, (options&Vertical) ); 257 258 } 259 260 //__________________________________________________________________ renderWindowBackground(cairo_t * context,GdkWindow * window,GtkWidget * widget,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options,bool isMaximized)261 bool Style::renderWindowBackground( 262 cairo_t* context, GdkWindow* window, GtkWidget* widget, 263 GdkRectangle* clipRect, gint x, gint y, gint w, gint h, 264 const StyleOptions& options, 265 bool isMaximized ) 266 { 267 if( _settings.useBackgroundGradient() ) 268 { 269 270 if( !renderBackgroundGradient( context, window, widget, clipRect, x, y, w, h, options, isMaximized ) ) 271 { return false; } 272 273 } else { 274 275 ColorUtils::Rgba base( color( Palette::Window, options ) ); 276 const bool needToDestroyContext( !context ); 277 if( !context ) 278 { 279 280 // create context 281 context = gdk_cairo_create(window); 282 283 // set clip rect 284 if( clipRect ) 285 { 286 cairo_rectangle(context,clipRect->x,clipRect->y,clipRect->width,clipRect->height); 287 cairo_clip(context); 288 } 289 290 } else cairo_save( context ); 291 292 cairo_set_source(context,base); 293 cairo_rectangle(context,x,y,w,h); 294 cairo_fill(context); 295 296 if( needToDestroyContext ) 297 { 298 cairo_destroy(context); 299 context = 0; 300 } 301 else cairo_restore(context); 302 303 } 304 305 // background pixmap 306 if( hasBackgroundSurface() ) 307 { renderBackgroundPixmap( context, window, widget, clipRect, x, y, w, h, isMaximized ); } 308 309 return true; 310 311 } 312 313 //__________________________________________________________________ renderBackgroundGradient(cairo_t * context,GdkWindow * window,GtkWidget * widget,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options,bool isMaximized)314 bool Style::renderBackgroundGradient( 315 cairo_t* context, GdkWindow* window, GtkWidget* widget, 316 GdkRectangle* clipRect, gint x, gint y, gint w, gint h, 317 const StyleOptions& options, 318 bool isMaximized ) 319 { 320 321 // define colors 322 ColorUtils::Rgba base( color( Palette::Window, options ) ); 323 bool renderingWindeco(context && !window); 324 325 // the hard-coded metrics are copied for 326 // kdebase/workspace/libs/oxygen/oxygenhelper.cpp 327 // vertical shift to account for window decoration 328 const int yShift = 23; 329 330 // toplevel window information and relative positioning 331 gint ww(0), wh(0); 332 gint wx(0), wy(0); 333 334 // if we aren't going to draw window decorations... 335 bool needToDestroyContext( false ); 336 if( renderingWindeco ) 337 { 338 // drawing window decorations, so logic is simplified 339 ww=w; 340 wh=h; 341 cairo_save(context); 342 cairo_translate(context,x,y); 343 x=0; 344 y=0; 345 346 } else { 347 348 349 if( !context ) 350 { 351 // create context and translate to toplevel coordinates 352 // make it the old good way since context is cairo_t* instead Cairo::Context 353 context = gdk_cairo_create(window); 354 needToDestroyContext=true; 355 356 if( clipRect ) 357 { 358 cairo_rectangle(context,clipRect->x,clipRect->y,clipRect->width,clipRect->height); 359 cairo_clip(context); 360 } 361 362 } else cairo_save( context ); 363 364 // get window dimension and position 365 // paint flat background when mapping failed 366 if( !Gtk::gdk_map_to_toplevel( window, widget, &wx, &wy, &ww, &wh, true ) ) 367 { 368 369 #if OXYGEN_DEBUG 370 std::cerr << "Oxygen::Style::renderBackgroundGradient - map_to_toplevel failed" << std::endl; 371 std::cerr << "original xywh: ("<<x<<","<<y<<","<<w<<","<<h<<")\n"; 372 #endif 373 374 if( _settings.applicationName().isOpenOffice() && GTK_IS_WINDOW(widget)) 375 { 376 gtk_window_get_size(GTK_WINDOW(widget),&ww,&wh); 377 wx=0; 378 wy=0; 379 cairo_translate(context,x,y); 380 if(clipRect) 381 { 382 #if OXYGEN_DEBUG 383 std::cerr << "original clipRect: " << *clipRect << std::endl; 384 #endif 385 clipRect->x-=x; 386 clipRect->y-=y; 387 clipRect->width-=x; 388 clipRect->height-=y; 389 } 390 x=y=0; 391 #if OXYGEN_DEBUG 392 std::cerr <<"Oxygen::Style::renderBackgroundGradient - setting openoffice-specific coords:"<<wx<<","<<wy<<","<<ww<<","<<wh<<"\n\n"; 393 #endif 394 } 395 else 396 { 397 // flat painting for all other apps 398 cairo_set_source(context,base); 399 cairo_rectangle(context,x,y,w,h); 400 cairo_fill(context); 401 if( needToDestroyContext ) cairo_destroy(context); 402 else cairo_restore(context); 403 return false; 404 } 405 406 } 407 408 // translate to toplevel coordinates 409 wy += yShift; 410 x+=wx; 411 y+=wy; 412 413 // no sense in context saving since it will be destroyed 414 cairo_translate( context, -wx, -wy ); 415 416 } 417 418 if(options&DrawAlphaChannel) 419 { 420 base.setAlpha(_settings.backgroundOpacity()/255.); 421 cairo_set_operator(context,CAIRO_OPERATOR_SOURCE); 422 } 423 424 // split 425 const int splitY( std::min(300, 3*wh/4 ) ); 426 427 // store rectangle 428 GdkRectangle rect = { x, y, w, h }; 429 430 /* 431 if there is a valid clipRect, 432 intersects it with painting Rect, for performances 433 */ 434 if( clipRect ) 435 { 436 437 GdkRectangle localClip( *clipRect ); 438 localClip.x += wx; 439 localClip.y += wy; 440 gdk_rectangle_intersect( &rect, &localClip, &rect ); 441 442 } 443 444 // upper rect 445 GdkRectangle upperRect = { 0, 0, ww, splitY }; 446 if( gdk_rectangle_intersect( &rect, &upperRect, &upperRect ) ) 447 { 448 449 const Cairo::Surface& surface( _helper.verticalGradient( base, splitY ) ); 450 cairo_set_source_surface( context, surface, 0, 0 ); 451 cairo_pattern_set_extend( cairo_get_source( context ), CAIRO_EXTEND_REPEAT ); 452 gdk_cairo_rectangle( context, &upperRect ); 453 cairo_fill( context ); 454 455 } 456 457 // fill lower rect 458 GdkRectangle lowerRect = { 0, splitY, ww, wh - splitY + yShift }; 459 if( gdk_rectangle_intersect( &rect, &lowerRect, &lowerRect ) ) 460 { 461 462 ColorUtils::Rgba bottom( ColorUtils::backgroundBottomColor( base ) ); 463 gdk_cairo_rectangle( context, &lowerRect ); 464 cairo_set_source( context, bottom ); 465 cairo_fill( context ); 466 467 } 468 469 // gradient should be rendered with full opacity 470 base.setAlpha(1); 471 cairo_set_operator(context,CAIRO_OPERATOR_OVER); 472 473 // radial pattern 474 const int patternHeight = 64; 475 const int radialW( std::min(600, ww ) ); 476 477 GdkRectangle radialRect = { (ww - radialW)/2, 0, radialW, patternHeight }; 478 if( gdk_rectangle_intersect( &rect, &radialRect, &radialRect ) ) 479 { 480 481 const Cairo::Surface& surface( _helper.radialGradient( base, 64 ) ); 482 cairo_set_source_surface( context, surface, 0, 0 ); 483 484 // add matrix transformation 485 cairo_matrix_t transformation; 486 cairo_matrix_init_identity( &transformation ); 487 cairo_matrix_scale( &transformation, 128.0/radialW, 1.0 ); 488 cairo_matrix_translate( &transformation, -(ww - radialW)/2, 0 ); 489 cairo_pattern_set_matrix( cairo_get_source( context ), &transformation ); 490 491 gdk_cairo_rectangle( context, &radialRect ); 492 cairo_fill( context ); 493 494 } 495 496 if(needToDestroyContext) cairo_destroy(context); 497 else cairo_restore(context); 498 499 return true; 500 501 } 502 503 //__________________________________________________________________ renderBackgroundPixmap(cairo_t * context,GdkWindow * window,GtkWidget * widget,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,bool isMaximized)504 bool Style::renderBackgroundPixmap( 505 cairo_t* context, GdkWindow* window, GtkWidget* widget, 506 GdkRectangle* clipRect, gint x, gint y, gint w, gint h, 507 bool isMaximized ) 508 { 509 510 // define colors 511 bool renderingWindeco(context && !window); 512 513 // the hard-coded metrics are copied for 514 // kdebase/workspace/libs/oxygen/oxygenhelper.cpp 515 // vertical shift to account for window decoration 516 const int yShift = 23; 517 518 // toplevel window information and relative positioning 519 gint ww(0), wh(0); 520 gint wx(0), wy(0); 521 522 // if we aren't going to draw window decorations... 523 bool needToDestroyContext( false ); 524 if( renderingWindeco ) 525 { 526 // drawing window decorations, so logic is simplified 527 ww=w; 528 wh=h; 529 cairo_save(context); 530 cairo_translate(context,x,y); 531 x=0; 532 y=0; 533 534 } else { 535 536 if( !context ) 537 { 538 // create context and translate to toplevel coordinates 539 // make it the old good way since context is cairo_t* instead Cairo::Context 540 context = gdk_cairo_create(window); 541 needToDestroyContext=true; 542 543 if( clipRect ) 544 { 545 cairo_rectangle(context,clipRect->x,clipRect->y,clipRect->width,clipRect->height); 546 cairo_clip(context); 547 } 548 549 } else cairo_save( context ); 550 551 // get window dimension and position 552 // paint flat background when mapping failed 553 if( !Gtk::gdk_map_to_toplevel( window, widget, &wx, &wy, &ww, &wh, true ) ) 554 { 555 if( needToDestroyContext ) cairo_destroy(context); 556 else cairo_restore(context); 557 return false; 558 } 559 560 // translate to toplevel coordinates 561 wy += yShift; 562 x+=wx; 563 y+=wy; 564 565 // no sense in context saving since it will be destroyed 566 cairo_translate( context, -wx, -wy ); 567 568 } 569 570 // store rectangle 571 GdkRectangle rect = { x, y, w, h }; 572 573 /* 574 if there is a valid clipRect, 575 intersects it with painting Rect, for performances 576 */ 577 if( clipRect ) 578 { 579 580 GdkRectangle localClip( *clipRect ); 581 localClip.x += wx; 582 localClip.y += wy; 583 gdk_rectangle_intersect( &rect, &localClip, &rect ); 584 585 } 586 587 // Additional clip constraint so that no extra space is filled (important for LibreOffice) 588 cairo_rectangle(context,x,y,w,h); 589 cairo_clip(context); 590 591 if(renderingWindeco) 592 { 593 // Take border sizes into account 594 int bgShiftX=isMaximized?0:WinDeco::getMetric(WinDeco::BorderLeft); 595 int bgShiftY=WinDeco::getMetric(WinDeco::BorderTop)-yShift; 596 cairo_translate(context,bgShiftX,bgShiftY); 597 } 598 599 // no sense in context saving since it will be either destroyed or restored to earlier state 600 cairo_translate( context, -40, -(48-20) ); 601 cairo_set_source_surface( context, _backgroundSurface, 0, 0 ); 602 cairo_rectangle( context, 0, 0, ww + wx + 40, wh + wy + 48 - 20 ); 603 cairo_fill( context ); 604 605 if(needToDestroyContext) cairo_destroy(context); 606 else cairo_restore(context); 607 608 return true; 609 610 } 611 612 //__________________________________________________________________ renderGroupBoxBackground(cairo_t * context,GdkWindow * window,GtkWidget * widget,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options,TileSet::Tiles tiles)613 bool Style::renderGroupBoxBackground( 614 cairo_t* context, 615 GdkWindow* window, GtkWidget* widget, 616 GdkRectangle* clipRect, gint x, gint y, gint w, gint h, 617 const StyleOptions& options, 618 TileSet::Tiles tiles ) 619 { 620 621 // find groupbox parent 622 GtkWidget* parent( Gtk::gtk_parent_groupbox( widget ) ); 623 if( !( parent && _animations.groupBoxEngine().contains( parent ) ) ) return false; 624 625 // toplevel window information and relative positioning 626 gint ww(0), wh(0); 627 gint wx(0), wy(0); 628 629 // map to parent 630 if( !Gtk::gtk_widget_map_to_parent( widget, parent, &wx, &wy, &ww, &wh ) ) 631 { return false; } 632 633 // create context and translate 634 bool needToDestroyContext( false ); 635 if( !context ) 636 { 637 // create context and translate to toplevel coordinates 638 // make it the old good way since context is cairo_t* instead Cairo::Context 639 context = gdk_cairo_create(window); 640 needToDestroyContext=true; 641 642 if( clipRect ) 643 { 644 cairo_rectangle(context,clipRect->x,clipRect->y,clipRect->width,clipRect->height); 645 cairo_clip(context); 646 } 647 648 } else cairo_save( context ); 649 650 const int margin( 1 ); 651 wh += 2*margin; 652 ww += 2*margin; 653 x+=wx; 654 y+=wy; 655 cairo_translate( context, -wx, -wy ); 656 657 // define colors 658 ColorUtils::Rgba base; 659 if( options&Blend ) 660 { 661 662 gint wwh, wwy; 663 Gtk::gtk_widget_map_to_toplevel( parent, 0L, &wwy, 0L, &wwh ); 664 base = ColorUtils::backgroundColor( _settings.palette().color( Palette::Window ), wwh, wwy-1+wh/2 ); 665 666 } else { 667 668 base = _settings.palette().color( Palette::Window ); 669 670 } 671 672 const int xGroupBox = x - wx - margin; 673 const int yGroupBox = y - wy - margin; 674 renderGroupBox( context, base, xGroupBox, yGroupBox, ww, wh, options ); 675 676 if(needToDestroyContext) cairo_destroy(context); 677 else cairo_restore(context); 678 679 return true; 680 681 } 682 683 //__________________________________________________________________ renderMenuBackground(GdkWindow * window,Cairo::Context & context,gint x,gint y,gint w,gint h,const StyleOptions & options) const684 bool Style::renderMenuBackground( GdkWindow* window, Cairo::Context& context, gint x, gint y, gint w, gint h, const StyleOptions& options ) const 685 { 686 // define colors 687 ColorUtils::Rgba base( color( Palette::Window, options ) ); 688 ColorUtils::Rgba top( ColorUtils::backgroundTopColor( base ) ); 689 ColorUtils::Rgba bottom( ColorUtils::backgroundBottomColor( base ) ); 690 691 // get window dimension and position 692 gint ww, wh; 693 gint wx, wy; 694 if( !Gtk::gdk_map_to_toplevel( window, 0L, &wx, &wy, &ww, &wh, true ) ) 695 { return false; } 696 697 // translate to toplevel coordinates 698 x+=wx; 699 y+=wy; 700 701 cairo_translate( context, -wx, -wy ); 702 const bool hasAlpha( options&Alpha ); 703 const bool isMenu( options&Menu ); 704 const bool round( options&Round ); 705 706 GdkRectangle rect = { x, y, w, h }; 707 708 // paint translucent first 709 if( hasAlpha ) 710 { 711 cairo_rectangle( context, 0, 0, ww, wh ); 712 cairo_set_operator( context, CAIRO_OPERATOR_SOURCE ); 713 cairo_set_source( context, ColorUtils::alphaColor( base, 0 ) ); 714 cairo_fill( context ); 715 716 if(_settings.backgroundOpacity()<255) 717 { 718 double opacity(_settings.backgroundOpacity()/255.); 719 top.setAlpha(opacity); 720 bottom.setAlpha(opacity); 721 } 722 } 723 724 const int splitY( std::min(200, 3*wh/4 ) ); 725 const int verticalOffset( (isMenu && round) ? Menu_VerticalOffset:0 ); 726 727 GdkRectangle upperRect = { 0, verticalOffset, ww, splitY - verticalOffset }; 728 if( gdk_rectangle_intersect( &rect, &upperRect, &upperRect ) ) 729 { 730 // upper rect 731 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 0, 0, splitY ) ); 732 cairo_pattern_add_color_stop( pattern, 0, top ); 733 cairo_pattern_add_color_stop( pattern, 1, bottom ); 734 735 gdk_cairo_rounded_rectangle( context, &upperRect, 3.5, round ? CornersTop:CornersNone ); 736 cairo_set_source( context, pattern ); 737 cairo_fill( context ); 738 739 } 740 741 GdkRectangle lowerRect = { 0, splitY, ww, wh-splitY - verticalOffset }; 742 if( gdk_rectangle_intersect( &rect, &lowerRect, &lowerRect ) ) 743 { 744 745 // lower part 746 gdk_cairo_rounded_rectangle( context, &lowerRect, 3.5, round ? CornersBottom:CornersNone ); 747 cairo_set_source( context, bottom ); 748 cairo_fill( context ); 749 750 } 751 752 return true; 753 754 } 755 756 //__________________________________________________________________ renderTooltipBackground(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options) const757 void Style::renderTooltipBackground( GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h, const StyleOptions& options ) const 758 { 759 760 // define colors 761 ColorUtils::Rgba base(_settings.palette().color( Palette::Tooltip ) ); 762 ColorUtils::Rgba top( ColorUtils::backgroundTopColor( base ) ); 763 ColorUtils::Rgba bottom( ColorUtils::backgroundBottomColor( base ) ); 764 765 // create context and translate 766 Cairo::Context context( window, clipRect ); 767 cairo_translate( context, x, y ); 768 769 // paint translucent first 770 const bool hasAlpha( (options&Alpha) ); 771 bool round( GDK_IS_WINDOW( window ) && (options&Round) ); 772 773 if( hasAlpha ) 774 { 775 if( _settings.tooltipTransparent() ) 776 { 777 top.setAlpha( 0.86 ); 778 bottom.setAlpha( 0.86 ); 779 } 780 781 cairo_rectangle( context, 0, 0, w, h ); 782 cairo_set_operator( context, CAIRO_OPERATOR_SOURCE ); 783 cairo_set_source( context, ColorUtils::alphaColor( base, 0 ) ); 784 cairo_fill( context ); 785 } 786 787 // fill 788 { 789 GdkRectangle rect = { 0, 0, w, h }; 790 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 0, 0, h ) ); 791 cairo_pattern_add_color_stop( pattern, 0, top ); 792 cairo_pattern_add_color_stop( pattern, 1, bottom ); 793 794 gdk_cairo_rounded_rectangle( context, &rect, 3.5, round ? CornersAll:CornersNone ); 795 cairo_set_source( context, pattern ); 796 cairo_fill( context ); 797 798 } 799 800 // contrast pixel 801 { 802 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, 0, 0, h ) ); 803 cairo_pattern_add_color_stop( pattern, 0.5, ColorUtils::lightColor( bottom ) ); 804 cairo_pattern_add_color_stop( pattern, 0.9, bottom ); 805 806 cairo_rounded_rectangle( context, 0.5, 0.5, w-1, h-1, 3.5, round ? CornersAll:CornersNone ); 807 cairo_set_line_width( context, 1.0 ); 808 cairo_set_source( context, pattern ); 809 cairo_stroke( context ); 810 } 811 812 return; 813 814 } 815 816 //__________________________________________________________________ renderHeaderBackground(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h)817 void Style::renderHeaderBackground( GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h ) 818 { 819 820 // load color 821 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 822 823 // render normal window background 824 renderWindowBackground( window, clipRect, x, y, w, h ); 825 826 // render lines 827 renderHeaderLines( window, clipRect, x, y, w, h ); 828 829 // render side dots 830 Cairo::Context context( window, clipRect ); 831 int yCenter( y + h/2 ); 832 int xDots( x + w - 1 ); 833 _helper.renderDot( context, base, xDots, yCenter - 3 ); 834 _helper.renderDot( context, base, xDots, yCenter ); 835 _helper.renderDot( context, base, xDots, yCenter + 3 ); 836 837 } 838 839 840 //__________________________________________________________________ renderHeaderLines(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h) const841 void Style::renderHeaderLines( GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h ) const 842 { 843 844 // add horizontal lines 845 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 846 const ColorUtils::Rgba dark( ColorUtils::darkColor( base ) ); 847 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 848 849 Cairo::Context context( window, clipRect ); 850 cairo_set_line_width( context, 1.0 ); 851 852 // dark line 853 cairo_set_source( context, dark ); 854 cairo_move_to( context, x, y+h-0.5 ); 855 cairo_line_to( context, x+w, y+h-0.5 ); 856 cairo_stroke( context ); 857 858 // light line 859 cairo_set_source( context, light ); 860 cairo_move_to( context, x, y+h-1.5 ); 861 cairo_line_to( context, x+w, y+h-1.5 ); 862 cairo_stroke( context ); 863 864 } 865 866 //____________________________________________________________________________________ renderTreeLines(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const Gtk::CellInfoFlags & cellFlags,const StyleOptions & options) const867 void Style::renderTreeLines( GdkWindow* window, GdkRectangle* clipRect, gint x, gint y, gint w, gint h, const Gtk::CellInfoFlags& cellFlags, const StyleOptions& options ) const 868 { 869 870 // define pen color 871 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 872 const ColorUtils::Rgba base( ColorUtils::mix( 873 _settings.palette().color( group, Palette::Text ), 874 _settings.palette().color( group, Palette::Window ), 875 0.8 ) ); 876 877 Cairo::Context context( window, clipRect ); 878 cairo_set_source( context, base ); 879 cairo_set_line_width( context, 1.0 ); 880 881 const bool reversed( cellFlags._flags & Gtk::CellInfoFlags::Reversed ); 882 883 int cellIndent( cellFlags._levelIndent + cellFlags._expanderSize + 4 ); 884 int xStart( x + cellIndent/2 ); 885 886 if( reversed ) { 887 888 xStart += w - cellIndent; 889 cellIndent *= -1; 890 891 } 892 893 for( unsigned int i=0; i< cellFlags._depth; ++i ) 894 { 895 896 const bool isLastCell( cellFlags._isLast[i] ); 897 const bool last( i == cellFlags._depth -1 ); 898 double xCenter = xStart; 899 900 if( last ) 901 { 902 903 double yCenter = int(y+h/2); 904 const bool hasChildren( cellFlags._flags & Gtk::CellInfoFlags::HasChildren ); 905 906 if( hasChildren ) 907 { 908 // first vertical line 909 cairo_move_to( context, xCenter + 0.5 , y ); 910 cairo_line_to( context, xCenter + 0.5, yCenter - int(cellFlags._expanderSize/3 )-1 ); 911 912 // second vertical line 913 if( !isLastCell ) 914 { 915 916 cairo_move_to( context, xCenter + 0.5, y+h ); 917 cairo_line_to( context, xCenter + 0.5, yCenter + int( cellFlags._expanderSize/3 )+2 ); 918 } 919 920 // horizontal line 921 if( reversed ) 922 { 923 924 cairo_move_to( context, xCenter - 1 - int( cellFlags._expanderSize/3 ), yCenter + 0.5 ); 925 cairo_line_to( context, xCenter + 1 - cellFlags._expanderSize*2/3, yCenter + 0.5 ); 926 927 } else { 928 929 cairo_move_to( context, xCenter + 2 + int( cellFlags._expanderSize/3 ), yCenter + 0.5 ); 930 cairo_line_to( context, xCenter + cellFlags._expanderSize*2/3, yCenter + 0.5 ); 931 932 } 933 934 } else { 935 936 // vertical line 937 cairo_move_to( context, xCenter + 0.5, y ); 938 if( isLastCell ) cairo_line_to( context, xCenter + 0.5, yCenter ); 939 else cairo_line_to( context, xCenter + 0.5, y+h ); 940 941 // horizontal line 942 if( reversed ) 943 { 944 945 cairo_move_to( context, xCenter + 1 , yCenter + 0.5 ); 946 cairo_line_to( context, xCenter + 1 - cellFlags._expanderSize*2/3, yCenter + 0.5 ); 947 948 } else { 949 950 cairo_move_to( context, xCenter, yCenter + 0.5 ); 951 cairo_line_to( context, xCenter + cellFlags._expanderSize*2/3, yCenter + 0.5 ); 952 953 } 954 955 } 956 957 } else if( !isLastCell ) { 958 959 960 // vertical line 961 cairo_move_to( context, xCenter + 0.5, y ); 962 cairo_line_to( context, xCenter + 0.5, y + h ); 963 964 } 965 966 // render 967 cairo_stroke( context ); 968 969 // increment 970 xStart += cellIndent; 971 972 } 973 974 return; 975 } 976 977 //____________________________________________________________________________________ renderHoleBackground(GdkWindow * window,GtkWidget * widget,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options,TileSet::Tiles tiles,gint sideMargin)978 void Style::renderHoleBackground( 979 GdkWindow* window, 980 GtkWidget* widget, 981 GdkRectangle* clipRect, 982 gint x, gint y, gint w, gint h, const StyleOptions& options, TileSet::Tiles tiles, 983 gint sideMargin ) 984 { 985 986 // do nothing if not enough room 987 if( w < 14 || h < 14 ) return; 988 989 // add hole mask 990 Cairo::Context context( window, clipRect ); 991 renderHoleMask( context, x, y, w, h, tiles, sideMargin ); 992 993 if( (options&Flat) || _settings.applicationName().useFlatBackground( widget ) ) 994 { 995 996 // create a rounded-rect antimask for renderHoleBackground 997 cairo_set_source( context, _settings.palette().color( Palette::Window ) ); 998 cairo_rectangle( context, x, y, w, h ); 999 cairo_fill( context ); 1000 1001 } else if( GtkWidget* parent = _animations.flatWidgetEngine().flatParent( widget ) ) { 1002 1003 // get background color and fill 1004 if( Gtk::gtk_widget_style_is_modified( parent, GTK_STATE_NORMAL, GTK_RC_BG ) ) 1005 { 1006 1007 cairo_set_source( context, Gtk::gdk_get_color( gtk_widget_get_modifier_style( parent )->bg[GTK_STATE_NORMAL] ) ); 1008 1009 } else { 1010 1011 cairo_set_source( context, _settings.palette().color( Palette::Window ) ); 1012 1013 } 1014 1015 cairo_rectangle( context, x, y, w, h ); 1016 cairo_fill( context ); 1017 1018 } else { 1019 1020 // normal window background 1021 renderWindowBackground( context, window, 0L, clipRect, x, y, w, h, options, tiles); 1022 1023 // possible groupbox background 1024 // Pass NoFill option in order not to render the surrounding frame 1025 if( widget ) 1026 { renderGroupBoxBackground( context, window, widget, clipRect, x, y, w, h, options | Blend | NoFill, tiles ); } 1027 1028 } 1029 1030 } 1031 1032 //__________________________________________________________________ renderSplitter(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options,const AnimationData & data) const1033 void Style::renderSplitter( 1034 GdkWindow* window, GdkRectangle* clipRect, 1035 gint x, gint y, gint w, gint h, 1036 const StyleOptions& options, 1037 const AnimationData& data ) const 1038 { 1039 1040 // orientation 1041 const bool vertical( options&Vertical ); 1042 1043 // colors 1044 const ColorUtils::Rgba& base( _settings.palette().color( Palette::Window ) ); 1045 1046 // context 1047 Cairo::Context context( window, clipRect ); 1048 1049 // hover color 1050 ColorUtils::Rgba highlight; 1051 if( data._mode == AnimationHover ) 1052 { 1053 1054 highlight = ColorUtils::alphaColor( ColorUtils::lightColor( base ), 0.5*data._opacity ); 1055 1056 } else if( options&Hover ) { 1057 1058 highlight = ColorUtils::alphaColor( ColorUtils::lightColor( base ), 0.5 ); 1059 1060 } 1061 1062 // render hover rect 1063 if( highlight.isValid() ) 1064 { 1065 1066 Cairo::Context context( window, clipRect ); 1067 Cairo::Pattern pattern; 1068 double a(0.1); 1069 if( vertical ) 1070 { 1071 1072 if( w > 30 ) a = 10.0/w; 1073 pattern.set( cairo_pattern_create_linear( x, 0, x+w, 0 ) ); 1074 1075 } else { 1076 1077 if( h>30 ) a = 10.0/h; 1078 pattern.set( cairo_pattern_create_linear( 0, y, 0, y+h ) ); 1079 1080 } 1081 1082 cairo_pattern_add_color_stop( pattern, 0, ColorUtils::alphaColor( highlight, 0 ) ); 1083 cairo_pattern_add_color_stop( pattern, a, highlight ); 1084 cairo_pattern_add_color_stop( pattern, 1.0-a, highlight ); 1085 cairo_pattern_add_color_stop( pattern, 1.0, ColorUtils::alphaColor( highlight, 0 ) ); 1086 1087 cairo_set_source( context, pattern ); 1088 cairo_rectangle( context, x, y, w, h ); 1089 cairo_fill( context ); 1090 } 1091 1092 // dots 1093 if( vertical ) 1094 { 1095 1096 y += h/2; 1097 const int ngroups( std::max( 1, w/250 ) ); 1098 int center = ( w-( ngroups-1 )*250 )/2 + x; 1099 for( int k = 0; k < ngroups; k++, center += 250 ) 1100 { 1101 _helper.renderDot( context, base, center-3, y ); 1102 _helper.renderDot( context, base, center, y ); 1103 _helper.renderDot( context, base, center+3, y ); 1104 } 1105 1106 } else { 1107 1108 x += w/2; 1109 const int ngroups( std::max( 1, h/250 ) ); 1110 int center = ( h-( ngroups-1 )*250 )/2 + y; 1111 for( int k = 0; k < ngroups; k++, center += 250 ) 1112 { 1113 _helper.renderDot( context, base, x, center-3 ); 1114 _helper.renderDot( context, base, x, center ); 1115 _helper.renderDot( context, base, x, center+3 ); 1116 } 1117 1118 } 1119 1120 } 1121 1122 //____________________________________________________________________________________ renderProgressBarHole(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options)1123 void Style::renderProgressBarHole( 1124 GdkWindow* window, 1125 GdkRectangle* clipRect, 1126 gint x, gint y, gint w, gint h, const StyleOptions& options ) 1127 { 1128 1129 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 1130 const ColorUtils::Rgba base(_settings.palette().color( group, Palette::Window ) ); 1131 1132 Cairo::Context context( window, clipRect ); 1133 renderScrollBarHole( context, x, y, w, h, base, (options&Vertical) ); 1134 1135 } 1136 1137 //____________________________________________________________________________________ renderProgressBarHandle(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options)1138 void Style::renderProgressBarHandle( 1139 GdkWindow* window, 1140 GdkRectangle* clipRect, 1141 gint x, gint y, gint w, gint h, const StyleOptions& options ) 1142 { 1143 1144 // colors 1145 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 1146 const ColorUtils::Rgba base( _settings.palette().color( Palette::Active, Palette::Window ) ); 1147 const ColorUtils::Rgba glow( _settings.palette().color( group, Palette::Selected ) ); 1148 1149 // context 1150 Cairo::Context context( window, clipRect ); 1151 1152 // validate rect 1153 if(w<0 || h<0) return; 1154 1155 // make sure that width is large enough 1156 const int indicatorSize( (options&Vertical ? h:w ) ); 1157 1158 if( indicatorSize >= 3 && w > 0 && h > 1 ) 1159 { 1160 // get surface 1161 const Cairo::Surface& surface( _helper.progressBarIndicator( base, glow, w, h-1 ) ); 1162 cairo_translate( context, x, y ); 1163 cairo_rectangle( context, 0, 0, w, h-1 ); 1164 cairo_set_source_surface( context, surface, 0, 0 ); 1165 cairo_fill( context ); 1166 } 1167 1168 } 1169 1170 //____________________________________________________________________________________ renderScrollBarHole(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options)1171 void Style::renderScrollBarHole( 1172 GdkWindow* window, 1173 GdkRectangle* clipRect, 1174 gint x, gint y, gint w, gint h, const StyleOptions& options ) 1175 { 1176 1177 // colors 1178 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 1179 const ColorUtils::Rgba base(_settings.palette().color( group, Palette::Window ) ); 1180 1181 // context 1182 Cairo::Context context( window, clipRect ); 1183 renderScrollBarHole( context, x, y, w, h, base, options&Vertical ); 1184 1185 } 1186 1187 //____________________________________________________________________________________ renderHoleMask(cairo_t * context,gint x,gint y,gint w,gint h,TileSet::Tiles tiles,gint sideMargin)1188 void Style::renderHoleMask( cairo_t* context, gint x, gint y, gint w, gint h, TileSet::Tiles tiles, gint sideMargin ) 1189 { 1190 1191 GdkRectangle mask = {x+2, y+1, w-4, h-3 }; 1192 const double maskRadius = 3.5; 1193 Corners corners( CornersNone ); 1194 if( tiles & TileSet::Left ) 1195 { 1196 mask.x += sideMargin; 1197 mask.width -= sideMargin; 1198 if( tiles & TileSet::Top ) corners |= CornersTopLeft; 1199 if( tiles & TileSet::Bottom ) corners |= CornersBottomLeft; 1200 } 1201 1202 if( tiles & TileSet::Right ) 1203 { 1204 mask.width -= sideMargin; 1205 if( tiles & TileSet::Top ) corners |= CornersTopRight; 1206 if( tiles & TileSet::Bottom ) corners |= CornersBottomRight; 1207 } 1208 1209 // set clipping mask 1210 gdk_cairo_rounded_rectangle_negative(context,&mask,maskRadius,CornersAll); 1211 cairo_rectangle(context,x,y,w,h); 1212 cairo_clip(context); 1213 1214 return; 1215 1216 } 1217 1218 //____________________________________________________________________________________ renderScrollBarHandle(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options,const AnimationData & data)1219 void Style::renderScrollBarHandle( 1220 GdkWindow* window, 1221 GdkRectangle* clipRect, 1222 gint x, gint y, gint w, gint h, 1223 const StyleOptions& options, 1224 const AnimationData& data ) 1225 { 1226 1227 // vertical 1228 const bool vertical( options&Vertical ); 1229 1230 const double xf( vertical ? x+3 : x+4 ); 1231 const double yf( vertical ? y+3 : y+2 ); 1232 const double wf( vertical ? w-6 : w-8 ); 1233 const double hf( vertical ? h-6 : h-5 ); 1234 1235 // const double xf( vertical ? x+2 : x+3 ); 1236 // const double yf( vertical ? y+2 : y+1 ); 1237 // const double wf( vertical ? w-4 : w-6 ); 1238 // const double hf( vertical ? h-4 : h-3 ); 1239 1240 if( wf <= 0 || hf <= 0 ) return; 1241 1242 // context 1243 Cairo::Context context( window, clipRect ); 1244 1245 // store colors 1246 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 1247 const ColorUtils::Rgba color( _settings.palette().color( group, Palette::Button ) ); 1248 1249 const double radius( 3.5 ); 1250 1251 // glow color 1252 ColorUtils::Rgba glow; 1253 const ColorUtils::Rgba shadow( ColorUtils::alphaColor( ColorUtils::shadowColor( color ), 0.4 ) ); 1254 const ColorUtils::Rgba hovered( _settings.palette().color( Palette::Hover ) ); 1255 if( data._mode == AnimationHover ) glow = ColorUtils::mix( shadow, hovered, data._opacity ); 1256 else if( options&Hover ) glow = hovered; 1257 else glow = shadow; 1258 1259 _helper.scrollHandle( color, glow ).render( context, xf-3, yf-3, wf+6, hf+6, TileSet::Full ); 1260 1261 // contents 1262 const ColorUtils::Rgba mid( ColorUtils::midColor( color ) ); 1263 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, yf, 0, yf+hf ) ); 1264 cairo_pattern_add_color_stop( pattern, 0, color ); 1265 cairo_pattern_add_color_stop( pattern, 1, mid ); 1266 cairo_set_source( context, pattern ); 1267 cairo_rounded_rectangle( context, xf+1, yf+1, wf-2, hf-2, radius - 2 ); 1268 cairo_fill( context ); 1269 1270 // bevel pattern 1271 { 1272 const ColorUtils::Rgba light( ColorUtils::lightColor( color ) ); 1273 Cairo::Pattern pattern; 1274 if( vertical ) pattern.set( cairo_pattern_create_linear( 0, 0, 0, 30 ) ); 1275 else pattern.set( cairo_pattern_create_linear( 0, 0, 30, 0 ) ); 1276 cairo_pattern_set_extend( pattern, CAIRO_EXTEND_REFLECT ); 1277 1278 cairo_pattern_add_color_stop( pattern, 0, ColorUtils::Rgba::transparent() ); 1279 cairo_pattern_add_color_stop( pattern, 1.0, ColorUtils::alphaColor( light, 0.1 ) ); 1280 1281 cairo_set_source( context, pattern ); 1282 if( vertical ) cairo_rectangle( context, xf+3, yf, wf-6, hf ); 1283 else cairo_rectangle( context, xf, yf+3, wf, hf-6 ); 1284 cairo_fill( context ); 1285 } 1286 1287 } 1288 1289 //____________________________________________________________________________________ renderToolBarHandle(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options) const1290 void Style::renderToolBarHandle( 1291 GdkWindow* window, 1292 GdkRectangle* clipRect, 1293 gint x, gint y, gint w, gint h, const StyleOptions& options ) const 1294 { 1295 1296 const bool vertical( options & Vertical ); 1297 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 1298 1299 Cairo::Context context( window, clipRect ); 1300 int counter(0); 1301 if( vertical ) 1302 { 1303 1304 const int xcenter( x+w/2 ); 1305 for( int ycenter = y+2; ycenter <= y+h-3; ycenter+=3, ++counter ) 1306 { 1307 if( counter%2 == 0 ) _helper.renderDot( context, base, xcenter+1, ycenter ); 1308 else _helper.renderDot( context, base, xcenter-2, ycenter ); 1309 } 1310 1311 } else { 1312 1313 const int ycenter( y + h/2 ); 1314 for( int xcenter = x+2; xcenter < x+w-3; xcenter+=3, ++counter ) 1315 { 1316 if( counter%2 == 0 ) _helper.renderDot( context, base, xcenter, ycenter+1 ); 1317 else _helper.renderDot( context, base, xcenter, ycenter-2 ); 1318 } 1319 1320 } 1321 1322 return; 1323 1324 } 1325 1326 //__________________________________________________________________ drawFloatFrame(cairo_t * context,GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options,Palette::Role role) const1327 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 1328 { 1329 1330 // define colors 1331 ColorUtils::Rgba base(_settings.palette().color( role ) ); 1332 ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 1333 ColorUtils::Rgba dark( ColorUtils::darkColor( ColorUtils::backgroundBottomColor( base ) ) ); 1334 1335 const bool hasAlpha( options&Alpha ); 1336 const bool isMenu( options&Menu ); 1337 const bool drawUglyShadow( !hasAlpha ); 1338 const bool rounded( options&Round ); 1339 1340 // if we aren't drawing window decoration 1341 if( !context ) 1342 { 1343 // create context 1344 // make it the old good way since context is cairo_t* instead Cairo::Context 1345 context=gdk_cairo_create(window); 1346 if(clipRect) 1347 { 1348 cairo_rectangle(context,clipRect->x,clipRect->y,clipRect->width,clipRect->height); 1349 cairo_clip(context); 1350 } 1351 } 1352 1353 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, double(y)+0.5, 0, y+h-1 ) ); 1354 1355 // add vertical offset 1356 if( isMenu && rounded ) 1357 { 1358 y += Menu_VerticalOffset; 1359 h -= 2*Menu_VerticalOffset; 1360 } 1361 1362 if( drawUglyShadow ) 1363 { 1364 1365 // adjust rectangle 1366 x++; 1367 y++; 1368 w-=2; 1369 h-=2; 1370 1371 cairo_set_line_width(context,1); 1372 1373 if( options&Focus ) 1374 { 1375 1376 // window is active - it's a glow, not a shadow 1377 const ColorUtils::Rgba frameColor( _settings.palette().color( Palette::ActiveWindowBackground ) ); 1378 const ColorUtils::Rgba glow = ColorUtils::mix(ColorUtils::Rgba(0.5,0.5,0.5),frameColor,0.7); 1379 cairo_set_source(context,glow); 1380 1381 const double radius( 11*0.5 ); 1382 cairo_move_to( context, x+4, y-0.5 ); cairo_line_to( context, x+w-4, y-0.5 ); 1383 cairo_stroke( context ); 1384 1385 cairo_arc_negative( context, x-0.5+radius, y-0.5+radius, radius, -0.5*M_PI, -M_PI ); 1386 cairo_stroke( context ); 1387 cairo_arc_negative( context, x+w-11+0.5+radius, y-0.5+radius, radius, 0, -0.5*M_PI ); 1388 cairo_stroke( context ); 1389 1390 cairo_move_to( context, x-0.5, y+4 ); cairo_line_to( context, x-0.5, y+h-4 ); 1391 cairo_move_to( context, x+w+0.5, y+4 ); cairo_line_to( context, x+w+0.5, y+h-4 ); 1392 cairo_stroke( context ); 1393 1394 cairo_arc_negative( context, x-0.5+radius, y+h-11+0.5+radius, radius, -M_PI, -1.5*M_PI ); 1395 cairo_stroke( context ); 1396 cairo_arc_negative( context, x+w-11+0.5+radius, y+h-11+0.5+radius, radius, 0.5*M_PI, 0 ); 1397 cairo_stroke( context ); 1398 1399 cairo_move_to( context, x+4, y+h+0.5 ); cairo_line_to( context, x+w-4, y+h+0.5 ); 1400 cairo_stroke( context ); 1401 1402 1403 light=ColorUtils::mix(light, frameColor); 1404 dark=ColorUtils::mix(dark,frameColor); 1405 1406 } else { 1407 1408 // window inactive - draw something resembling shadow 1409 // fully desaturate 1410 ColorUtils::Rgba shadow( ColorUtils::darken( base, 0., 0. ) ); 1411 1412 if(rounded) 1413 { 1414 const double radius( 11*0.5 ); 1415 cairo_set_source( context, ColorUtils::darken( shadow, 0.2 )); 1416 cairo_move_to( context, x+4, y-0.5 ); cairo_line_to( context, x+w-4, y-0.5 ); 1417 cairo_stroke( context ); 1418 1419 cairo_arc_negative( context, x-0.5+radius, y-0.5+radius, radius, -0.5*M_PI, -M_PI ); 1420 cairo_stroke( context ); 1421 cairo_arc_negative( context, x+w-11+0.5+radius, y-0.5+radius, radius, 0, -0.5*M_PI ); 1422 cairo_stroke( context ); 1423 1424 cairo_set_source( context, ColorUtils::darken( shadow, 0.35 )); 1425 cairo_move_to( context, x-0.5, y+4 ); cairo_line_to( context, x-0.5, y+h-4 ); 1426 cairo_move_to( context, x+w+0.5, y+4 ); cairo_line_to( context, x+w+0.5, y+h-4 ); 1427 cairo_stroke( context ); 1428 1429 cairo_set_source( context, ColorUtils::darken( shadow, 0.45 )); 1430 cairo_arc_negative( context, x-0.5+radius, y+h-11+0.5+radius, radius, -M_PI, -1.5*M_PI ); 1431 cairo_stroke( context ); 1432 cairo_arc_negative( context, x+w-11+0.5+radius, y+h-11+0.5+radius, radius, 0.5*M_PI, 0 ); 1433 cairo_stroke( context ); 1434 1435 cairo_set_source( context, ColorUtils::darken( shadow, 0.6 )); 1436 cairo_move_to( context, x+4, y+h+0.5 ); cairo_line_to( context, x+w-4, y+h+0.5 ); 1437 cairo_stroke( context ); 1438 1439 } else { 1440 1441 cairo_set_source( context, ColorUtils::darken( shadow, 0.2 )); 1442 cairo_move_to( context, x-0.5, y-0.5 ); cairo_line_to( context, x+w+0.5, y-0.5 ); 1443 cairo_stroke( context ); 1444 1445 cairo_set_source( context, ColorUtils::darken( shadow, 0.35 )); 1446 cairo_move_to( context, x-0.5, y-0.5 ); cairo_line_to( context, x-0.5, y+h+0.5 ); 1447 cairo_move_to( context, x+w+0.5, y-0.5 ); cairo_line_to( context, x+w+0.5, y+h+0.5 ); 1448 cairo_stroke( context ); 1449 1450 cairo_set_source( context, ColorUtils::darken( shadow, 0.6 )); 1451 cairo_move_to( context, x-0.5, y+h+0.5 ); cairo_line_to( context, x+w+0.5, y+h+0.5 ); 1452 cairo_stroke( context ); 1453 1454 } 1455 } 1456 } 1457 1458 cairo_pattern_add_color_stop( pattern, 0, light ); 1459 1460 if( !rounded ) 1461 { 1462 1463 cairo_pattern_add_color_stop( pattern, 1, ColorUtils::alphaColor( dark, 0 ) ); 1464 1465 } else { 1466 1467 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 ) ); 1468 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 ) ); 1469 cairo_pattern_add_color_stop( pattern, 1, ColorUtils::Rgba::transparent( light ) ); 1470 1471 } 1472 1473 cairo_rounded_rectangle( context, x+0.5, y+0.5, w-1, h-1, 3.5, rounded ? CornersAll : CornersNone ); 1474 1475 cairo_set_source( context, pattern ); 1476 cairo_set_line_width( context, 0.8 ); 1477 cairo_stroke( context ); 1478 } 1479 1480 //__________________________________________________________________ renderButtonSlab(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options,const AnimationData & animationData,TileSet::Tiles tiles)1481 void Style::renderButtonSlab( 1482 GdkWindow* window, 1483 GdkRectangle* clipRect, 1484 gint x, gint y, gint w, gint h, 1485 const StyleOptions& options, 1486 const AnimationData& animationData, 1487 TileSet::Tiles tiles 1488 ) 1489 { 1490 1491 // flat buttons are only rendered with a simple Rect, and only when either focused or sunken 1492 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 1493 1494 // glow color (depending on hover/glow 1495 const ColorUtils::Rgba glow( slabShadowColor( options, animationData ) ); 1496 1497 if( options & Flat ) 1498 { 1499 if( options & Sunken ) 1500 { 1501 1502 Cairo::Context context( window, clipRect ); 1503 const ColorUtils::Rgba base( color( group, Palette::Window, options ) ); 1504 1505 const double bias( 0.75 ); 1506 double opacity( 1.0 ); 1507 if( glow.isValid() ) opacity -= bias*glow.alpha(); 1508 1509 // fill hole 1510 ColorUtils::Rgba color( ColorUtils::midColor( base ) ); 1511 color = ColorUtils::alphaColor( color, opacity ); 1512 cairo_save( context ); 1513 cairo_set_source( context, color ); 1514 cairo_rounded_rectangle( context, x+1, y+1, w-2, h-2, 3.5 ); 1515 cairo_fill( context ); 1516 cairo_restore( context ); 1517 1518 if( glow.isValid() ) _helper.holeFocused( base, glow, 7, true ).render( context, x, y, w, h ); 1519 else _helper.hole( base, 7, true ).render( context, x, y, w, h ); 1520 1521 } else if( glow.isValid() ) { 1522 1523 Cairo::Context context( window, clipRect ); 1524 _helper.slitFocused( glow ).render( context, x, y, w, h, tiles ); 1525 1526 } 1527 1528 return; 1529 1530 } 1531 1532 // forces minimum size to 14x14 1533 if( w < 14 || h < 14 ) 1534 { 1535 GdkRectangle parent( Gtk::gdk_rectangle( x, y, w, h ) ); 1536 GdkRectangle child( Gtk::gdk_rectangle( x, y, std::max( w, 14), std::max( h, 14 ) ) ); 1537 centerRect( &parent, &child ); 1538 x = child.x; 1539 y = child.y; 1540 w = child.width; 1541 h = child.height; 1542 clipRect = 0L; 1543 } 1544 1545 1546 // define colors 1547 ColorUtils::Rgba base( color( group, Palette::Button, options ) ); 1548 if( options&Blend ) 1549 { 1550 1551 gint wh, wy; 1552 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 1553 base = ColorUtils::backgroundColor( base, wh, y+wy+h/2 ); 1554 1555 } 1556 1557 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 1558 1559 // create context 1560 Cairo::Context context( window, clipRect ); 1561 cairo_save( context ); 1562 1563 // fill with appropriate pattern 1564 Cairo::Pattern pattern; 1565 if( options&Sunken ) 1566 { 1567 1568 pattern.set( cairo_pattern_create_linear( 0, y-h, 0, y+h ) ); 1569 cairo_pattern_add_color_stop( pattern, 0, light ); 1570 cairo_pattern_add_color_stop( pattern, 1.0, base ); 1571 1572 } else { 1573 1574 pattern.set( cairo_pattern_create_linear( 0, double(y)-0.2*h, 0, double(y) + h + 0.4*h ) ); 1575 cairo_pattern_add_color_stop( pattern, 0, light ); 1576 cairo_pattern_add_color_stop( pattern, 0.6, base ); 1577 1578 } 1579 1580 cairo_set_source( context, pattern ); 1581 _helper.fillSlab( context, x, y, w, h+1, tiles ); 1582 cairo_restore( context ); 1583 1584 if( options&Sunken ) 1585 { 1586 1587 _helper.slabSunken( base ).render( context, x, y, w, h, tiles ); 1588 1589 } else { 1590 1591 _helper.slab( base, glow, 0 ).render( context, x, y, w, h, tiles ); 1592 1593 } 1594 1595 } 1596 1597 //__________________________________________________________________ renderSlab(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const Gtk::Gap & gap,const StyleOptions & options,const AnimationData & animationData)1598 void Style::renderSlab( 1599 GdkWindow* window, 1600 GdkRectangle* clipRect, 1601 gint x, gint y, gint w, gint h, const Gtk::Gap& gap, 1602 const StyleOptions& options, 1603 const AnimationData& animationData ) 1604 { 1605 1606 // define colors 1607 ColorUtils::Rgba base; 1608 if( options&Blend ) 1609 { 1610 1611 gint wh, wy; 1612 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 1613 base = ColorUtils::backgroundColor( _settings.palette().color( Palette::Window ), wh, y+wy+h/2 ); 1614 1615 } else { 1616 1617 base = _settings.palette().color( Palette::Window ); 1618 1619 } 1620 1621 // create context 1622 Cairo::Context context( window, clipRect ); 1623 generateGapMask( context, x, y, w, h, gap ); 1624 renderSlab( context, x, y, w, h, base, options, animationData, TileSet::Ring ); 1625 1626 } 1627 1628 //__________________________________________________________________ renderInfoBar(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const ColorUtils::Rgba & glow)1629 void Style::renderInfoBar( 1630 GdkWindow* window, 1631 GdkRectangle* clipRect, 1632 gint x, gint y, gint w, gint h, 1633 const ColorUtils::Rgba& glow ) 1634 { 1635 1636 // create context 1637 Cairo::Context context( window, clipRect ); 1638 1639 // content 1640 cairo_rounded_rectangle( context, x+1, y+1, w-2, h-2, 5 ); 1641 cairo_set_source( context, glow ); 1642 cairo_fill( context ); 1643 1644 // border 1645 cairo_set_line_width( context, 1.0 ); 1646 cairo_rounded_rectangle( context, 1.5+x, 1.5+y, w-3, h-3, 4.5 ); 1647 cairo_set_source( context, ColorUtils::darken( glow ) ); 1648 cairo_stroke( context ); 1649 1650 } 1651 1652 //__________________________________________________________________ renderCheckBox(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,GtkShadowType shadow,const StyleOptions & options,const AnimationData & animationData)1653 void Style::renderCheckBox( 1654 GdkWindow* window, 1655 GdkRectangle* clipRect, 1656 gint x, gint y, gint w, gint h, GtkShadowType shadow, 1657 const StyleOptions& options, 1658 const AnimationData& animationData ) 1659 { 1660 1661 // define checkbox rect 1662 gint cbw = CheckBox_Size; 1663 if( options & Flat ) cbw -= 5; 1664 GdkRectangle parent = {x, y, w, h }; 1665 GdkRectangle child = {0, 0, cbw, cbw }; 1666 centerRect( &parent, &child ); 1667 1668 // define colors 1669 ColorUtils::Rgba base; 1670 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 1671 const Palette::Role role( options&Flat ? Palette::Window : Palette::Button ); 1672 if( options&Blend ) 1673 { 1674 1675 gint wh, wy; 1676 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 1677 base = ColorUtils::backgroundColor( _settings.palette().color( group, role ), wh, y+wy+h/2 ); 1678 1679 } else { 1680 1681 base = _settings.palette().color( group, role ); 1682 1683 } 1684 1685 // draw slab 1686 Cairo::Context context( window, clipRect ); 1687 1688 if( options & Flat ) 1689 { 1690 1691 _helper.holeFlat( base, 0, false ).render( context, child.x+1, child.y-1, child.width, child.height, TileSet::Full ); 1692 cairo_translate( context, 0, -2 ); 1693 1694 } else { 1695 1696 StyleOptions localOptions( options ); 1697 localOptions &= ~Sunken; 1698 renderSlab( context, child.x, child.y, child.width, child.height, base, localOptions, animationData ); 1699 1700 } 1701 1702 // draw mark 1703 x = int( double(child.x + child.width/2) - 3.5 ); 1704 y = int( double(child.y + child.height/2) - 2.5 ); 1705 1706 if( shadow == GTK_SHADOW_IN || shadow == GTK_SHADOW_ETCHED_IN || options&Active ) 1707 { 1708 1709 cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND ); 1710 cairo_set_line_join( context, CAIRO_LINE_JOIN_ROUND ); 1711 if( shadow == GTK_SHADOW_IN ) cairo_set_line_width( context, 2.0 ); 1712 1713 Palette::Group group( (options&Disabled) ? Palette::Disabled : Palette::Active ); 1714 const ColorUtils::Rgba& color( _settings.palette().color( group, ( options&Flat ) ? Palette::WindowText : Palette::ButtonText ) ); 1715 const ColorUtils::Rgba& background( _settings.palette().color( ( options&Flat ) ? Palette::Window : Palette::Button ) ); 1716 1717 ColorUtils::Rgba base( ColorUtils::decoColor( background, color ) ); 1718 ColorUtils::Rgba contrast( ColorUtils::lightColor( background ) ); 1719 1720 // We don't want to change color on active state for menu checkboxes (it's never passed by GTK) 1721 // Also, if we ignore active state, we get correct render for LibreOffice 1722 if( options&Active && !(options&Flat) ) 1723 { 1724 base = ColorUtils::alphaColor( base, 0.3 ); 1725 contrast = ColorUtils::alphaColor( contrast, 0.3 ); 1726 } 1727 1728 cairo_translate( context, 0.5, 0.5 ); 1729 1730 const double offset( 1.0 ); 1731 if( _settings.checkBoxStyle() == QtSettings::CS_CHECK ) 1732 { 1733 1734 // dask pattern for tristate buttons 1735 if( shadow == GTK_SHADOW_ETCHED_IN ) 1736 { 1737 cairo_set_line_width( context, 1.3 ); 1738 double dashes[2] = { 1.3, 2.6 }; 1739 cairo_set_dash( context, &dashes[0], 2, 0 ); 1740 } 1741 1742 cairo_save( context ); 1743 cairo_translate( context, 0, offset ); 1744 cairo_move_to( context, x+9, y ); 1745 cairo_line_to( context, x+3, y+7 ); 1746 cairo_line_to( context, x, y+4 ); 1747 cairo_restore( context ); 1748 cairo_set_source( context, contrast ); 1749 cairo_stroke( context ); 1750 1751 cairo_move_to( context, x+9, y ); 1752 cairo_line_to( context, x+3, y+7 ); 1753 cairo_line_to( context, x, y+4 ); 1754 cairo_set_source( context, base ); 1755 cairo_stroke( context ); 1756 1757 } else { 1758 1759 // dask pattern for tristate buttons 1760 if( shadow == GTK_SHADOW_ETCHED_IN ) 1761 { 1762 double dashes[2] = { 0.8, 4.0 }; 1763 cairo_set_dash( context, &dashes[0], 2, 0 ); 1764 } 1765 1766 if( options&Flat ) 1767 { 1768 1769 cairo_save( context ); 1770 cairo_translate( context, 0, offset ); 1771 cairo_move_to( context, x+8, y ); cairo_line_to( context, x+1, y+7 ); 1772 cairo_move_to( context, x+8, y+7 ); cairo_line_to( context, x+1, y ); 1773 cairo_restore( context ); 1774 cairo_set_source( context, contrast ); 1775 cairo_stroke( context ); 1776 1777 cairo_move_to( context, x+8, y ); cairo_line_to( context, x+1, y+7 ); 1778 cairo_move_to( context, x+8, y+7 ); cairo_line_to( context, x+1, y ); 1779 cairo_set_source( context, base ); 1780 cairo_stroke( context ); 1781 1782 } else { 1783 1784 cairo_save( context ); 1785 cairo_translate( context, 0, offset ); 1786 cairo_move_to( context, x+8, y-1 ); cairo_line_to( context, x, y+7 ); 1787 cairo_move_to( context, x+8, y+7 ); cairo_line_to( context, x, y-1 ); 1788 cairo_restore( context ); 1789 cairo_set_source( context, contrast ); 1790 cairo_stroke( context ); 1791 1792 cairo_move_to( context, x+8, y-1 ); cairo_line_to( context, x, y+7 ); 1793 cairo_move_to( context, x+8, y+7 ); cairo_line_to( context, x, y-1 ); 1794 cairo_set_source( context, base ); 1795 cairo_stroke( context ); 1796 1797 } 1798 1799 } 1800 1801 } 1802 1803 } 1804 1805 //___________________________________________________________________ renderRadioButton(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,GtkShadowType shadow,const StyleOptions & options,const AnimationData & animationData)1806 void Style::renderRadioButton( 1807 GdkWindow* window, 1808 GdkRectangle* clipRect, 1809 gint x, gint y, gint w, gint h, GtkShadowType shadow, 1810 const StyleOptions& options, 1811 const AnimationData& animationData ) 1812 { 1813 1814 // define checkbox rect 1815 gint cbw( CheckBox_Size ); 1816 gint tileSize( CheckBox_Size/3 ); 1817 double scale( 1.0 ); 1818 1819 if( _settings.applicationName().isOpenOffice() ) 1820 { 1821 const gint dimension = std::min( w, h ); 1822 cbw = std::min( 3*( 1 + dimension/3 ), (int)CheckBox_Size ); 1823 scale = double(cbw)/CheckBox_Size; 1824 tileSize = cbw/3; 1825 } 1826 1827 GdkRectangle parent = {x, y, w, h }; 1828 GdkRectangle child = {0, 0, cbw, cbw }; 1829 centerRect( &parent, &child ); 1830 x = child.x; 1831 y = child.y; 1832 1833 // define colors 1834 ColorUtils::Rgba base; 1835 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 1836 if( options&Blend ) 1837 { 1838 1839 gint wh, wy; 1840 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 1841 1842 if( options & Menu ) base = ColorUtils::menuBackgroundColor( _settings.palette().color( group, Palette::Button ), wh, y+wy+h/2 ); 1843 else base = ColorUtils::backgroundColor( _settings.palette().color( group, Palette::Button ), wh, y+wy+h/2 ); 1844 1845 } else { 1846 1847 base = _settings.palette().color( group, Palette::Button ); 1848 1849 } 1850 1851 // glow 1852 const ColorUtils::Rgba glow( slabShadowColor( options, animationData ) ); 1853 1854 // get the pixmap 1855 const Cairo::Surface& surface( _helper.roundSlab( base, glow, 0, tileSize ) ); 1856 1857 // create context 1858 Cairo::Context context( window, clipRect ); 1859 cairo_save( context ); 1860 cairo_translate( context, x, y ); 1861 if(options&NoFill) 1862 { 1863 // Only render the glow, leave the bullet clipped out 1864 const int border(4); 1865 cairo_ellipse_negative(context,border,border,child.width-border*2,child.height-border*2); 1866 cairo_rectangle(context,0,0,child.width,child.height); 1867 cairo_clip(context); 1868 } 1869 cairo_rectangle( context, 0, 0, child.width, child.height ); 1870 cairo_set_source_surface( context, surface, 0, 0 ); 1871 cairo_fill( context ); 1872 cairo_restore( context ); 1873 1874 if( shadow == GTK_SHADOW_IN || shadow == GTK_SHADOW_ETCHED_IN || options&Active ) 1875 { 1876 double radius( shadow == GTK_SHADOW_ETCHED_IN ? 1.4:2.6 ); 1877 radius *= scale; 1878 1879 const double dx( 0.5*child.width - radius ); 1880 const double dy( 0.5*child.height - radius ); 1881 1882 const ColorUtils::Rgba& background( _settings.palette().color( Palette::Button ) ); 1883 const ColorUtils::Rgba& color( _settings.palette().color( group, Palette::ButtonText ) ); 1884 1885 ColorUtils::Rgba base( ColorUtils::decoColor( background, color ) ); 1886 ColorUtils::Rgba contrast( ColorUtils::lightColor( background ) ); 1887 1888 // We don't want to change color on active state for menu radiobuttons (it's never passed by GTK) 1889 // Also, if we ignore active state, we get correct render for LibreOffice 1890 if( options&Active && !(options&Menu ) ) 1891 { 1892 base = ColorUtils::alphaColor( base, 0.3 ); 1893 contrast = ColorUtils::alphaColor( contrast, 0.3 ); 1894 } 1895 1896 1897 cairo_save( context ); 1898 cairo_translate( context, 0, radius/2 ); 1899 cairo_ellipse( context, x+dx, y+dy, child.width - 2*dx, child.height -2*dy ); 1900 cairo_restore( context ); 1901 if( shadow == GTK_SHADOW_ETCHED_IN ) 1902 { 1903 1904 cairo_set_line_width( context, 1.3 ); 1905 cairo_set_source( context, contrast ); 1906 cairo_stroke( context ); 1907 1908 cairo_set_source( context, base ); 1909 cairo_ellipse( context, x+dx, y+dy, child.width - 2*dx, child.height -2*dy ); 1910 cairo_stroke( context ); 1911 1912 } else { 1913 1914 cairo_set_source( context, contrast ); 1915 cairo_fill( context ); 1916 1917 cairo_set_source( context, base ); 1918 cairo_ellipse( context, x+dx, y+dy, child.width - 2*dx, child.height -2*dy ); 1919 cairo_fill( context ); 1920 1921 } 1922 1923 } 1924 1925 return; 1926 } 1927 1928 //____________________________________________________________________________________ renderHole(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const Gtk::Gap & gap,const StyleOptions & options,const AnimationData & animationData,TileSet::Tiles tiles)1929 void Style::renderHole( 1930 GdkWindow* window, 1931 GdkRectangle* clipRect, 1932 gint x, gint y, gint w, gint h, const Gtk::Gap& gap, 1933 const StyleOptions& options, 1934 const AnimationData& animationData, 1935 TileSet::Tiles tiles ) 1936 { 1937 1938 // do nothing if not enough room 1939 if( w < 14 || h < 14 ) return; 1940 1941 // enable state 1942 const bool enabled( !(options&Disabled ) ); 1943 1944 // load color 1945 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 1946 ColorUtils::Rgba fill; 1947 if( !( options&NoFill ) ) 1948 { 1949 const Palette::Group group( enabled ? Palette::Active : Palette::Disabled ); 1950 fill = _settings.palette().color( group, Palette::Base ); 1951 } 1952 1953 // create context, add mask, and render hole 1954 Cairo::Context context( window, clipRect ); 1955 generateGapMask( context, x, y, w, h, gap ); 1956 1957 if( fill.isValid() ) tiles |= TileSet::Center; 1958 1959 const ColorUtils::Rgba glow( holeShadowColor( options, animationData ) ); 1960 if( glow.isValid() ) _helper.holeFocused( base, fill, glow ).render( context, x, y, w, h, tiles ); 1961 else _helper.hole( base, fill ).render( context, x, y, w, h, tiles ); 1962 1963 } 1964 1965 //____________________________________________________________________________________ renderDockFrame(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const Gtk::Gap & gap,const StyleOptions & options)1966 void Style::renderDockFrame( 1967 GdkWindow* window, 1968 GdkRectangle* clipRect, 1969 gint x, gint y, gint w, gint h, const Gtk::Gap& gap, const StyleOptions& options ) 1970 { 1971 1972 // do nothing if not enough room 1973 if( w < 9 || h < 9 ) return; 1974 1975 // define colors 1976 ColorUtils::Rgba top; 1977 ColorUtils::Rgba bottom; 1978 if( options&Blend ) 1979 { 1980 1981 gint wh, wy; 1982 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 1983 top = ColorUtils::backgroundColor( _settings.palette().color( Palette::Window ), wh, y+wy ); 1984 bottom = ColorUtils::backgroundColor( _settings.palette().color( Palette::Window ), wh, y+h+wy ); 1985 1986 } else { 1987 1988 top = _settings.palette().color( Palette::Window ); 1989 bottom = _settings.palette().color( Palette::Window ); 1990 1991 } 1992 1993 // create context, add mask, and render 1994 Cairo::Context context( window, clipRect ); 1995 generateGapMask( context, x, y, w, h, gap ); 1996 _helper.dockFrame( top, bottom ).render( context, x, y, w, h ); 1997 } 1998 1999 //____________________________________________________________________________________ renderGroupBoxFrame(GdkWindow * window,GtkWidget * widget,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options)2000 void Style::renderGroupBoxFrame( 2001 GdkWindow* window, 2002 GtkWidget* widget, 2003 GdkRectangle* clipRect, 2004 gint x, gint y, gint w, gint h, const StyleOptions& options ) 2005 { 2006 2007 // register 2008 if( widget ) 2009 { _animations.groupBoxEngine().registerWidget( widget ); } 2010 2011 // define colors 2012 ColorUtils::Rgba base; 2013 if( options&Blend ) 2014 { 2015 2016 gint wh, wy; 2017 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 2018 base = ColorUtils::backgroundColor( _settings.palette().color( Palette::Window ), wh, y+wy+h/2 ); 2019 2020 } else { 2021 2022 base = _settings.palette().color( Palette::Window ); 2023 2024 } 2025 2026 Cairo::Context context( window, clipRect ); 2027 renderGroupBox( context, base, x, y, w, h, options ); 2028 2029 } 2030 2031 //____________________________________________________________________________________ renderMenuItemRect(GdkWindow * window,GdkRectangle * clipRect,GtkWidget * widget,gint x,gint y,gint w,gint h,const StyleOptions & options,const AnimationData & data)2032 void Style::renderMenuItemRect( 2033 GdkWindow* window, 2034 GdkRectangle* clipRect, 2035 GtkWidget* widget, 2036 gint x, gint y, gint w, gint h, 2037 const StyleOptions& options, 2038 const AnimationData& data ) 2039 { 2040 ColorUtils::Rgba base; 2041 2042 gint wh, wy; 2043 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 2044 const bool isInMenu( Gtk::gtk_parent_menu( widget ) ); 2045 const bool isInMenuBar( Gtk::gtk_parent_menubar( widget ) ); 2046 2047 if( wh > 0 ) 2048 { 2049 if( isInMenu ) base = ColorUtils::menuBackgroundColor( ColorUtils::midColor( _settings.palette().color( Palette::Window ) ), wh, y+wy+h/2 ); 2050 else if( options&Blend ) base = ColorUtils::backgroundColor( ColorUtils::midColor( _settings.palette().color( Palette::Window ) ), wh, y+wy+h/2 ); 2051 else base = ColorUtils::midColor( _settings.palette().color( Palette::Window ) ); 2052 2053 } else { 2054 2055 base = ColorUtils::midColor( _settings.palette().color( Palette::Window ) ); 2056 2057 } 2058 2059 // more color customization, based on menuHighlight mode 2060 ColorUtils::Rgba color( base ); 2061 if( _settings.menuHighlightMode() == QtSettings::MM_STRONG ) 2062 { 2063 2064 if( (options & Sunken) || isInMenu ) color = _settings.palette().color( Palette::Selected ); 2065 else color = ColorUtils::tint( color, _settings.palette().color( Palette::Hover ) ); 2066 2067 } else if( _settings.menuHighlightMode() == QtSettings::MM_SUBTLE ) { 2068 2069 if( (options & Sunken) || isInMenu ) color = ColorUtils::mix( color, ColorUtils::tint( color, _settings.palette().color( Palette::Selected ), 0.6 ) ); 2070 else color = ColorUtils::mix( color, ColorUtils::tint( color, _settings.palette().color( Palette::Hover ), 0.6 ) ); 2071 2072 } 2073 2074 // apply animation data 2075 if( data._mode == AnimationHover ) 2076 { 2077 if( data._opacity > 0 ) color = ColorUtils::alphaColor( color, data._opacity ); 2078 else return; 2079 } 2080 2081 2082 if( isInMenuBar ) 2083 { 2084 2085 // we force ytickness in gtkrc to emulate Qt menubar/menu space separation 2086 // so adjust vertical extent of the rect in menubar 2087 if( _settings.applicationName().isXul() ) 2088 { 2089 2090 y+=3; 2091 h-=6; 2092 2093 } else { 2094 2095 x+=1; 2096 w-=2; 2097 2098 y+=1; 2099 h-=2; 2100 2101 } 2102 } else if ( isInMenu ) { 2103 2104 // we force ytickness to 5 in gtkrc to emulate Qt menuitems space separation 2105 // so adjust vertical extent of the rect in menus to 21 (size with standard ytickness) 2106 if( h > 27 ) 2107 { 2108 2109 y+=4; 2110 h-=7; 2111 2112 } else { 2113 2114 y+=(h-21)/2; 2115 h=21; 2116 2117 } 2118 2119 } 2120 2121 bool hasSubMenu( isInMenu && GTK_IS_MENU_ITEM( widget ) && gtk_menu_item_get_submenu( GTK_MENU_ITEM( widget ) ) ); 2122 if( hasSubMenu ) 2123 { 2124 Cairo::Context context( window, clipRect ); 2125 cairo_translate( context, x, y ); 2126 2127 // draw item rect in a group 2128 cairo_push_group( context ); 2129 _helper.holeFlat( color, 0 ).render( context, 0, 0, w, h, TileSet::Full ); 2130 cairo_pop_group_to_source( context ); 2131 2132 // generate linear gradient for masking 2133 if( Gtk::gtk_widget_layout_is_reversed( widget ) ) 2134 { 2135 2136 Cairo::Pattern mask( cairo_pattern_create_linear( 4, 0, 40, 0 ) ); 2137 cairo_pattern_add_color_stop( mask, 0, ColorUtils::Rgba::transparent() ); 2138 cairo_pattern_add_color_stop( mask, 1, ColorUtils::Rgba::black() ); 2139 cairo_mask( context, mask ); 2140 2141 } else { 2142 2143 Cairo::Pattern mask( cairo_pattern_create_linear( w-40, 0, w-4, 0 ) ); 2144 cairo_pattern_add_color_stop( mask, 0, ColorUtils::Rgba::black() ); 2145 cairo_pattern_add_color_stop( mask, 1, ColorUtils::Rgba::transparent() ); 2146 cairo_mask( context, mask ); 2147 2148 } 2149 2150 } else { 2151 2152 Cairo::Context context( window, clipRect ); 2153 _helper.holeFlat( color, 0 ).render( context, x, y, w, h, TileSet::Full ); 2154 2155 } 2156 } 2157 2158 //____________________________________________________________________________________ renderSelection(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,TileSet::Tiles tiles,const StyleOptions & options)2159 void Style::renderSelection( 2160 GdkWindow* window, 2161 GdkRectangle* clipRect, 2162 gint x, gint y, gint w, gint h, 2163 TileSet::Tiles tiles, 2164 const StyleOptions& options 2165 ) 2166 { 2167 2168 // do nothing if not selected nor hovered 2169 if( !options & (Hover|Selected ) ) return; 2170 2171 Palette::Group group( (options & Focus) ? Palette::Active : Palette::Inactive ); 2172 ColorUtils::Rgba base( _settings.palette().color( group, Palette::Selected ) ); 2173 if( options & Hover ) 2174 { 2175 if( !( options & Selected ) ) base.setAlpha( 0.2 ); 2176 else base = base.light( 110 ); 2177 } 2178 2179 // create context 2180 Cairo::Context context( window, clipRect ); 2181 if( !(tiles&TileSet::Left) ) { x -= 8; w+=8; } 2182 if( !(tiles&TileSet::Right) ) { w += 8; } 2183 _helper.selection( base, h, false ).render( context, x, y, w, h, tiles ); 2184 2185 } 2186 2187 //____________________________________________________________________________________ renderArrow(GdkWindow * window,GdkRectangle * clipRect,GtkArrowType orientation,gint x,gint y,gint w,gint h,QtSettings::ArrowSize arrowSize,const StyleOptions & options,const AnimationData & data,Palette::Role role) const2188 void Style::renderArrow( 2189 GdkWindow* window, 2190 GdkRectangle* clipRect, 2191 GtkArrowType orientation, 2192 gint x, gint y, gint w, gint h, 2193 QtSettings::ArrowSize arrowSize, 2194 const StyleOptions& options, 2195 const AnimationData& data, 2196 Palette::Role role ) const 2197 { 2198 2199 // get polygon 2200 const Polygon arrow( genericArrow( orientation, arrowSize ) ); 2201 2202 // retrieve colors 2203 ColorUtils::Rgba base; 2204 if( options&Disabled ) base = _settings.palette().color( Palette::Disabled, role ); 2205 else if( data._mode == AnimationHover ) base = ColorUtils::mix( 2206 _settings.palette().color( Palette::Active, role ), 2207 _settings.palette().color( Palette::Hover ), 2208 data._opacity ); 2209 else if( options&Hover ) base = _settings.palette().color( Palette::Hover ); 2210 else base = _settings.palette().color( Palette::Active, role ); 2211 2212 // merge base color with relevant background, if needed 2213 const Palette::Group group( (options&Disabled) ? Palette::Disabled : Palette::Active ); 2214 switch( role ) 2215 { 2216 2217 case Palette::WindowText: 2218 base = ColorUtils::decoColor( _settings.palette().color( group, Palette::Window ), base ); 2219 break; 2220 2221 case Palette::ButtonText: 2222 base = ColorUtils::decoColor( _settings.palette().color( group, Palette::Button ), base ); 2223 break; 2224 2225 default: break; 2226 2227 } 2228 2229 // need odd width and height 2230 if( !(w%2) ) w--; 2231 if( !(h%2) ) h--; 2232 const int xcenter = x + w/2; 2233 const int ycenter = y + h/2; 2234 2235 // create context and translate to center 2236 Cairo::Context context( window, clipRect ); 2237 cairo_translate( context, xcenter, ycenter ); 2238 2239 switch( orientation ) 2240 { 2241 case GTK_ARROW_UP: 2242 break; 2243 2244 case GTK_ARROW_DOWN: 2245 if( arrowSize == QtSettings::ArrowSmall ) cairo_translate( context, 0, 0.5 ); 2246 else cairo_translate( context, 0, 1 ); 2247 break; 2248 2249 case GTK_ARROW_LEFT: 2250 case GTK_ARROW_RIGHT: 2251 if( arrowSize == QtSettings::ArrowSmall ) 2252 { cairo_translate( context, 0.5, 0 ); } 2253 break; 2254 2255 default: 2256 break; 2257 } 2258 2259 switch( arrowSize ) 2260 { 2261 case QtSettings::ArrowTiny: 2262 case QtSettings::ArrowSmall: 2263 cairo_set_line_width( context, 1.2 ); 2264 break; 2265 2266 default: 2267 case QtSettings::ArrowNormal: 2268 cairo_set_line_width( context, 1.6 ); 2269 break; 2270 } 2271 2272 cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND ); 2273 cairo_set_line_join( context, CAIRO_LINE_JOIN_ROUND ); 2274 2275 // contrast 2276 if( options&Contrast ) 2277 { 2278 2279 // contrast color 2280 const ColorUtils::Rgba contrast( ColorUtils::lightColor( _settings.palette().color( Palette::Window ) ) ); 2281 2282 cairo_save( context ); 2283 cairo_translate( context, 0, 1 ); 2284 cairo_polygon( context, arrow ); 2285 cairo_restore( context ); 2286 2287 cairo_set_source( context, contrast ); 2288 cairo_stroke( context ); 2289 } 2290 2291 // base 2292 cairo_polygon( context, arrow ); 2293 cairo_set_source( context, base ); 2294 cairo_stroke( context ); 2295 2296 } 2297 2298 //____________________________________________________________________________________ renderSliderGroove(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options)2299 void Style::renderSliderGroove( 2300 GdkWindow* window, 2301 GdkRectangle* clipRect, 2302 gint x, gint y, gint w, gint h, const StyleOptions& options ) 2303 { 2304 2305 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 2306 2307 const bool vertical( options & Vertical ); 2308 GdkRectangle parent = { x, y, w, h }; 2309 2310 GdkRectangle child; 2311 if( vertical ) child = Gtk::gdk_rectangle( 0, 0, Slider_GrooveWidth, h ); 2312 else child = Gtk::gdk_rectangle( 0, 0, w, Slider_GrooveWidth ); 2313 centerRect( &parent, &child ); 2314 2315 if( !vertical ) 2316 { 2317 // more adjustment needed due to contrast pixel 2318 child.y += 1; 2319 child.height -= 1; 2320 } 2321 2322 Cairo::Context context( window, clipRect ); 2323 _helper.scrollHole( base, vertical, true ).render( context, child.x, child.y, child.width, child.height, TileSet::Full ); 2324 2325 } 2326 2327 //____________________________________________________________________________________ renderSliderHandle(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const StyleOptions & options,const AnimationData & animationData)2328 void Style::renderSliderHandle( 2329 GdkWindow* window, 2330 GdkRectangle* clipRect, 2331 gint x, gint y, gint w, gint h, 2332 const StyleOptions& options, 2333 const AnimationData& animationData ) 2334 { 2335 2336 // define colors 2337 const Palette::Group group( options&Disabled ? Palette::Disabled : Palette::Active ); 2338 ColorUtils::Rgba base; 2339 if( options&Blend ) 2340 { 2341 2342 gint wh, wy; 2343 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 2344 base = ColorUtils::backgroundColor( _settings.palette().color( group, Palette::Button ), wh, y+wy+h/2 ); 2345 2346 } else { 2347 2348 base = _settings.palette().color( group, Palette::Button ); 2349 2350 } 2351 2352 // render slab 2353 Cairo::Context context( window, clipRect ); 2354 2355 GdkRectangle parent = { x, y, w, h }; 2356 GdkRectangle child = {0, 0, 21, 21 }; 2357 centerRect( &parent, &child ); 2358 2359 x = child.x; 2360 y = child.y; 2361 2362 const ColorUtils::Rgba glow( slabShadowColor( options, animationData ) ); 2363 const Cairo::Surface& surface( _helper.sliderSlab( base, glow, (options&Sunken), 0 ) ); 2364 cairo_translate( context, x, y ); 2365 cairo_rectangle( context, 0, 0, child.width, child.height ); 2366 cairo_set_source_surface( context, surface, 0, 0 ); 2367 cairo_fill( context ); 2368 2369 } 2370 2371 //____________________________________________________________________________________ renderSizeGrip(GdkWindow * window,GdkRectangle * clipRect,GdkWindowEdge edge,gint x,gint y,gint w,gint h) const2372 void Style::renderSizeGrip( 2373 GdkWindow* window, 2374 GdkRectangle* clipRect, 2375 GdkWindowEdge edge, 2376 gint x, gint y, gint w, gint h ) const 2377 { 2378 2379 gint dimension = std::min( w, h ); 2380 2381 // edges 2382 Polygon a; 2383 switch( edge ) 2384 { 2385 2386 case GDK_WINDOW_EDGE_NORTH_WEST: 2387 w = dimension; 2388 h = dimension; 2389 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); 2390 break; 2391 2392 case GDK_WINDOW_EDGE_NORTH_EAST: 2393 x+= w-dimension; 2394 w = dimension; 2395 h = dimension; 2396 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 ); 2397 break; 2398 2399 case GDK_WINDOW_EDGE_SOUTH_WEST: 2400 y+= h-dimension; 2401 w = dimension; 2402 h = dimension; 2403 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 ); 2404 break; 2405 2406 case GDK_WINDOW_EDGE_SOUTH_EAST: 2407 x+= w-dimension; 2408 y+= h-dimension; 2409 w = dimension; 2410 h = dimension; 2411 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 ); 2412 break; 2413 2414 default: return; 2415 2416 } 2417 2418 2419 // colors 2420 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 2421 const ColorUtils::Rgba dark( ColorUtils::darkColor( base ) ); 2422 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 2423 2424 // context 2425 Cairo::Context context( window, clipRect ); 2426 cairo_set_line_width( context, 1.0 ); 2427 2428 // fill 2429 cairo_polygon( context, a ); 2430 cairo_set_source( context, base ); 2431 cairo_fill( context ); 2432 2433 // draw edges 2434 cairo_move_to( context, a[0].x(), a[0].y() ); 2435 cairo_line_to( context, a[1].x(), a[1].y() ); 2436 cairo_set_source( context, dark ); 2437 cairo_stroke( context ); 2438 2439 cairo_move_to( context, a[1].x(), a[1].y() ); 2440 cairo_line_to( context, a[2].x(), a[2].y() ); 2441 cairo_line_to( context, a[0].x(), a[0].y() ); 2442 cairo_set_source( context, light ); 2443 cairo_stroke( context ); 2444 2445 } 2446 2447 //____________________________________________________________________________________ renderTab(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,GtkPositionType side,const StyleOptions & options,const TabOptions & tabOptions,const AnimationData & data)2448 void Style::renderTab( 2449 GdkWindow* window, 2450 GdkRectangle* clipRect, 2451 gint x, gint y, gint w, gint h, 2452 GtkPositionType side, 2453 const StyleOptions& options, 2454 const TabOptions& tabOptions, 2455 const AnimationData& data 2456 ) 2457 { 2458 2459 if( tabOptions & CurrentTab ) 2460 { 2461 2462 return renderActiveTab( window, clipRect, x, y, w, h, side, options, tabOptions ); 2463 2464 } else { 2465 2466 switch( _settings.tabStyle() ) 2467 { 2468 case QtSettings::TS_SINGLE: return renderInactiveTab_Single( window, clipRect, x, y, w, h, side, options, tabOptions, data ); 2469 case QtSettings::TS_PLAIN: return renderInactiveTab_Plain( window, clipRect, x, y, w, h, side, options, tabOptions, data ); 2470 default: return; 2471 } 2472 2473 } 2474 2475 } 2476 2477 //____________________________________________________________________________________ renderTabBarBase(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,GtkPositionType side,Gtk::Gap gap,const StyleOptions & options,const TabOptions & tabOptions)2478 void Style::renderTabBarBase( 2479 GdkWindow* window, 2480 GdkRectangle* clipRect, 2481 gint x, gint y, gint w, gint h, 2482 GtkPositionType side, 2483 Gtk::Gap gap, 2484 const StyleOptions& options, 2485 const TabOptions& tabOptions 2486 ) 2487 { 2488 2489 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 2490 2491 // adjust gap 2492 if( tabOptions & FirstTabAligned ) { gap.setX( gap.x()-3 ); gap.setWidth( gap.width()+3 ); } 2493 if( tabOptions & LastTabAligned ) { gap.setWidth( gap.width()+3 ); } 2494 2495 // create context 2496 Cairo::Context context( window, 0L ); 2497 2498 // generate mask and main slab 2499 SlabRect tabSlab; 2500 const TileSet::Tiles tabTiles( Style::tabTiles( side ) ); 2501 switch( side ) 2502 { 2503 case GTK_POS_BOTTOM: 2504 tabSlab = SlabRect( x, y+h-4, w, 15, tabTiles ); 2505 generateGapMask( context, x-1, y-4, w+2, h+8, gap ); 2506 break; 2507 2508 case GTK_POS_TOP: 2509 tabSlab = SlabRect( x, y-11, w, 15, tabTiles ); 2510 generateGapMask( context, x-1, y-4, w+2, h+8, gap ); 2511 break; 2512 2513 case GTK_POS_RIGHT: 2514 tabSlab = SlabRect( x+w-4, y, 15, h, tabTiles ); 2515 generateGapMask( context, x-4, y-1, w+8, h+2, gap ); 2516 break; 2517 2518 2519 case GTK_POS_LEFT: 2520 tabSlab = SlabRect( x-11, y, 15, h, tabTiles ); 2521 generateGapMask( context, x-4, y-1, w+8, h+2, gap ); 2522 break; 2523 2524 default: break; 2525 2526 } 2527 2528 // render 2529 _helper.slab( base, 0 ).render( context, tabSlab._x, tabSlab._y, tabSlab._w, tabSlab._h, tabSlab._tiles ); 2530 return; 2531 2532 } 2533 2534 //__________________________________________________________________ renderTabBarFrame(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,const Gtk::Gap & gap,const StyleOptions & options)2535 void Style::renderTabBarFrame( 2536 GdkWindow* window, 2537 GdkRectangle* clipRect, 2538 gint x, gint y, gint w, gint h, 2539 const Gtk::Gap& gap, 2540 const StyleOptions& options ) 2541 { 2542 2543 // define colors 2544 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 2545 2546 // create context 2547 Cairo::Context context( window, clipRect ); 2548 generateGapMask( context, x, y, w, h, gap ); 2549 renderSlab( context, x, y, w, h, base, options ); 2550 2551 } 2552 2553 //____________________________________________________________________________________ renderTreeExpander(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,GtkExpanderStyle style,const StyleOptions & options,const AnimationData & data,Palette::Role role) const2554 void Style::renderTreeExpander( 2555 GdkWindow* window, 2556 GdkRectangle* clipRect, 2557 gint x, gint y, gint w, gint h, 2558 GtkExpanderStyle style, 2559 const StyleOptions& options, 2560 const AnimationData& data, 2561 Palette::Role role 2562 ) const 2563 { 2564 2565 // retrieve colors 2566 ColorUtils::Rgba base; 2567 if( options&Disabled ) base = _settings.palette().color( Palette::Disabled, role ); 2568 else if( data._mode == AnimationHover ) base = ColorUtils::mix( 2569 _settings.palette().color( Palette::Active, role ), 2570 _settings.palette().color( Palette::Hover ), 2571 data._opacity ); 2572 else if( options&Hover ) base = _settings.palette().color( Palette::Hover ); 2573 else base = _settings.palette().color( Palette::Active, role ); 2574 2575 const int xcenter( x + w/2 ); 2576 const int ycenter( y + h/2 ); 2577 2578 // expander 'radius' (copied from oxygen-qt) 2579 const int radius( ( 9 - 4 ) / 2 ); 2580 2581 // create context and translate to center 2582 Cairo::Context context( window, clipRect ); 2583 cairo_set_line_width( context, 1.0 ); 2584 cairo_set_source( context, base ); 2585 2586 cairo_translate( context, -0.5+xcenter, -0.5+ycenter ); 2587 2588 // horizontal line 2589 cairo_move_to( context, -radius, 0 ); 2590 cairo_line_to( context, radius, 0 ); 2591 2592 // vertical line 2593 if( style == GTK_EXPANDER_COLLAPSED || style == GTK_EXPANDER_SEMI_COLLAPSED ) 2594 { 2595 cairo_move_to( context, 0, -radius ); 2596 cairo_line_to( context, 0, radius ); 2597 } 2598 2599 cairo_stroke( context ); 2600 2601 } 2602 2603 //__________________________________________________________________ renderWindowDecoration(cairo_t * context,WinDeco::Options wopt,gint x,gint y,gint w,gint h,const gchar ** windowStrings,gint titleIndentLeft,gint titleIndentRight,bool gradient)2604 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 ) 2605 { 2606 bool hasAlpha( wopt & WinDeco::Alpha ); 2607 bool drawResizeHandle( !(wopt & WinDeco::Shaded) && (wopt & WinDeco::Resizable) ); 2608 bool isMaximized( wopt & WinDeco::Maximized ); 2609 bool drawAlphaChannel( wopt & WinDeco::DrawAlphaChannel ); 2610 StyleOptions options( hasAlpha ? Alpha : Blend ); 2611 2612 if( hasAlpha && !isMaximized ) 2613 { 2614 // cut round corners using alpha 2615 cairo_rounded_rectangle(context,x,y,w,h,3.5); 2616 cairo_clip(context); 2617 } 2618 2619 if(drawAlphaChannel) 2620 options|=DrawAlphaChannel; 2621 2622 if( gradient ) renderWindowBackground( context, x, y, w, h, options, isMaximized ); 2623 else 2624 { 2625 cairo_set_source( context, _settings.palette().color( Palette::Active, Palette::Window ) ); 2626 cairo_paint( context ); 2627 } 2628 2629 options|=Round; 2630 2631 // focus 2632 if(wopt & WinDeco::Active) options|=Focus; 2633 2634 if( !isMaximized ) 2635 { drawFloatFrame( context, 0L, 0L, x, y, w, h, options ); } 2636 2637 if( drawResizeHandle ) 2638 { 2639 ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 2640 renderWindowDots( context, x, y, w, h, base, wopt); 2641 } 2642 2643 if(windowStrings) 2644 { 2645 // caption is drawn in drawWindowDecoration 2646 if( windowStrings[1] ) 2647 { 2648 // TODO: use WMCLASS and caption to enable per-window style exceptions 2649 } 2650 } 2651 } 2652 2653 //__________________________________________________________________ drawWindowDecoration(cairo_t * context,WinDeco::Options wopt,gint x,gint y,gint w,gint h,const gchar ** windowStrings,gint titleIndentLeft,gint titleIndentRight)2654 void Style::drawWindowDecoration( cairo_t* context, WinDeco::Options wopt, gint x, gint y, gint w, gint h, const gchar** windowStrings, gint titleIndentLeft, gint titleIndentRight ) 2655 { 2656 2657 #ifdef GDK_WINDOWING_X11 2658 /* 2659 (any element of windowStrings[] may be NULL - will be understood as "") 2660 windowStrings may also be NULL 2661 2662 elements: 2663 windowStrings[0]: caption 2664 windowStrings[1]: WMCLASS 2665 windowStrings[2]: (gpointer)XID 2666 */ 2667 /* 2668 caches layout: 2669 left&right border height: h 2670 top&bottom border width: w-BorderLeft-BorderRight 2671 */ 2672 2673 // enable gradient if XID is not passed 2674 bool gradient=true; 2675 2676 const int buttonSpacing(WinDeco::getMetric(WinDeco::ButtonSpacing)); 2677 titleIndentLeft+=2*buttonSpacing; 2678 titleIndentRight+=2*buttonSpacing; 2679 2680 QtSettings::WindecoBlendType blendType(_settings.windecoBlendType()); 2681 if( blendType==QtSettings::SolidColor ) 2682 { 2683 2684 gradient=false; 2685 2686 } else if( blendType==QtSettings::FollowStyleHint && windowStrings && windowStrings[2] ) { 2687 2688 Window window((Window)windowStrings[2]); 2689 Display* display( GDK_DISPLAY_XDISPLAY(gdk_display_get_default()) ); 2690 if( _animations.backgroundHintEngine().backgroundGradientAtom() != None ) 2691 { 2692 Atom typeRet; 2693 int formatRet; 2694 unsigned long itemsRet; 2695 unsigned long afterRet; 2696 unsigned char *data = 0; 2697 2698 if( !( XGetWindowProperty(display, window, _animations.backgroundHintEngine().backgroundGradientAtom(), 0, G_MAXLONG, False, 2699 XA_CARDINAL, &typeRet, &formatRet, &itemsRet, &afterRet, &data) == Success 2700 && itemsRet == 1 2701 && formatRet == 32) ) 2702 { 2703 // if the window doesn't have this property set, it's likely 2704 // non-oxygenized, thus shouldn't have windeco bg gradient 2705 gradient=false; 2706 } 2707 } 2708 } 2709 2710 WindecoBorderKey key(wopt,w,h,gradient); 2711 2712 { 2713 // draw left border with cache 2714 Cairo::Surface left( _helper.windecoLeftBorderCache().value(key) ); 2715 int sw=WinDeco::getMetric(WinDeco::BorderLeft); 2716 if(sw) 2717 { 2718 2719 if( !left ) 2720 { 2721 2722 #if OXYGEN_DEBUG 2723 std::cerr<<"drawWindowDecoration: drawing left border; width: " << w << "; height: " << h << "; wopt: " << wopt << std::endl; 2724 #endif 2725 left=_helper.createSurface(sw,h); 2726 2727 Cairo::Context context(left); 2728 renderWindowDecoration( context, wopt, 0, 0, w, h, windowStrings, titleIndentLeft, titleIndentRight, gradient); 2729 2730 _helper.windecoLeftBorderCache().insert(key,left); 2731 2732 } else { 2733 2734 #if OXYGEN_DEBUG 2735 std::cerr << "drawWindowDecoration: using saved left border" << std::endl; 2736 #endif 2737 2738 } 2739 2740 cairo_set_source_surface(context, left, x, y); 2741 cairo_rectangle(context,x,y,sw,h); 2742 cairo_fill(context); 2743 } 2744 } 2745 2746 { 2747 // draw right border with cache 2748 Cairo::Surface right( _helper.windecoRightBorderCache().value(key) ); 2749 int sw=WinDeco::getMetric(WinDeco::BorderRight); 2750 if(sw) 2751 { 2752 2753 if( !right ) 2754 { 2755 2756 #if OXYGEN_DEBUG 2757 std::cerr<<"drawWindowDecoration: drawing right border; width: " << w << "; height: " << h << "; wopt: " << wopt << std::endl; 2758 #endif 2759 2760 right=_helper.createSurface(sw,h); 2761 2762 Cairo::Context context(right); 2763 renderWindowDecoration( context, wopt, -(w-sw), 0, w, h, windowStrings, titleIndentLeft, titleIndentRight, gradient ); 2764 2765 _helper.windecoRightBorderCache().insert(key,right); 2766 2767 } else { 2768 2769 #if OXYGEN_DEBUG 2770 std::cerr << "drawWindowDecoration: using saved right border" << std::endl; 2771 #endif 2772 2773 } 2774 2775 cairo_set_source_surface(context, right, x+w-sw, y); 2776 cairo_rectangle(context,x+w-sw,y,sw,h); 2777 cairo_fill(context); 2778 } 2779 } 2780 2781 { 2782 // draw top border with cache 2783 Cairo::Surface top( _helper.windecoTopBorderCache().value(key) ); 2784 int left=WinDeco::getMetric(WinDeco::BorderLeft); 2785 int right=WinDeco::getMetric(WinDeco::BorderRight); 2786 int sh=WinDeco::getMetric(WinDeco::BorderTop); 2787 int sw=w-left-right; 2788 if(sh && sw) 2789 { 2790 if( !top ) 2791 { 2792 2793 #if OXYGEN_DEBUG 2794 std::cerr<<"drawWindowDecoration: drawing top border; width: " << w << "; height: " << h << "; wopt: " << wopt << std::endl; 2795 #endif 2796 top=_helper.createSurface(sw,sh); 2797 2798 Cairo::Context context(top); 2799 renderWindowDecoration( context, wopt, -left, 0, w, h, windowStrings, titleIndentLeft, titleIndentRight, gradient ); 2800 2801 _helper.windecoTopBorderCache().insert(key,top); 2802 2803 } else { 2804 2805 #if OXYGEN_DEBUG 2806 std::cerr << "drawWindowDecoration: using saved top border" << std::endl; 2807 #endif 2808 2809 } 2810 2811 cairo_set_source_surface(context, top, x+left, y); 2812 cairo_rectangle(context,x+left,y,sw,sh); 2813 cairo_fill(context); 2814 2815 // caption shouldn't be saved in the cache 2816 if( windowStrings && windowStrings[0] ) 2817 { 2818 // draw caption 2819 const gchar* &caption(windowStrings[0]); 2820 const FontInfo& font( _settings.WMFont() ); 2821 gint layoutWidth=w-(titleIndentLeft+titleIndentRight); 2822 if( font.isValid() && layoutWidth>0 ) 2823 { 2824 PangoFontDescription* fdesc( pango_font_description_new() ); 2825 const Palette::Group group( wopt & WinDeco::Active ? Palette::Active : Palette::Disabled ); 2826 const int H=WinDeco::getMetric(WinDeco::BorderTop); 2827 int textHeight; 2828 2829 pango_font_description_set_family( fdesc, font.family().c_str() ); 2830 pango_font_description_set_weight( fdesc, PangoWeight( (font.weight()+2)*10 ) ); 2831 pango_font_description_set_style( fdesc, font.italic() ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL ); 2832 pango_font_description_set_absolute_size( fdesc, int(font.size()*PANGO_SCALE) ); 2833 2834 PangoLayout* layout( pango_cairo_create_layout(context) ); 2835 pango_layout_set_text( layout,caption, -1 ); 2836 pango_layout_set_font_description( layout, fdesc ); 2837 pango_layout_set_width( layout, layoutWidth*PANGO_SCALE ); 2838 pango_layout_set_ellipsize( layout, PANGO_ELLIPSIZE_END ); 2839 pango_layout_set_alignment( layout, _settings.TitleAlignment() ); 2840 pango_layout_get_pixel_size( layout, NULL, &textHeight ); 2841 2842 cairo_save( context ); 2843 2844 ColorUtils::Rgba titleContrastColor(ColorUtils::lightColor(_settings.palette().color( Palette::Disabled, Palette::Window ))); 2845 cairo_set_source( context, titleContrastColor ); 2846 cairo_translate( context, x+titleIndentLeft, y+(H-textHeight)/2.+1 ); 2847 pango_cairo_update_layout( context, layout ); 2848 pango_cairo_show_layout( context, layout ); 2849 2850 ColorUtils::Rgba titleTextColor(_settings.palette().color( group, Palette::WindowText )); 2851 cairo_set_source( context, titleTextColor ); 2852 cairo_translate( context, 0, -1 ); 2853 pango_cairo_update_layout( context, layout ); 2854 pango_cairo_show_layout( context, layout ); 2855 2856 cairo_restore( context ); 2857 2858 g_object_unref(layout); 2859 pango_font_description_free(fdesc); 2860 } 2861 } 2862 } 2863 } 2864 2865 { 2866 // draw bottom border with cache 2867 Cairo::Surface bottom( _helper.windecoBottomBorderCache().value(key) ); 2868 int left=WinDeco::getMetric(WinDeco::BorderLeft); 2869 int right=WinDeco::getMetric(WinDeco::BorderRight); 2870 int sh=WinDeco::getMetric(WinDeco::BorderBottom); 2871 int sw=w-left-right; 2872 int Y=y+h-sh; 2873 if(sh && sw) 2874 { 2875 if( !bottom) 2876 { 2877 2878 #if OXYGEN_DEBUG 2879 std::cerr<<"drawWindowDecoration: drawing bottom border; width: " << w << "; height: " << h << "; wopt: " << wopt << std::endl; 2880 #endif 2881 bottom=_helper.createSurface(sw,sh); 2882 2883 Cairo::Context context(bottom); 2884 renderWindowDecoration( context, wopt, -left, y-Y, w, h, windowStrings, titleIndentLeft, titleIndentRight, gradient ); 2885 2886 _helper.windecoBottomBorderCache().insert(key,bottom); 2887 2888 } else { 2889 2890 #if OXYGEN_DEBUG 2891 std::cerr << "drawWindowDecoration: using saved bottom border" << std::endl; 2892 #endif 2893 2894 } 2895 2896 cairo_set_source_surface(context, bottom, x+left, Y); 2897 cairo_rectangle(context,x+left,Y,sw,sh); 2898 cairo_fill(context); 2899 } 2900 } 2901 2902 #endif 2903 2904 } 2905 2906 //__________________________________________________________________ drawWindowShadow(cairo_t * context,WinDeco::Options wopt,gint x,gint y,gint w,gint h)2907 void Style::drawWindowShadow( cairo_t* context, WinDeco::Options wopt, gint x, gint y, gint w, gint h ) 2908 { 2909 cairo_set_source_rgba( context, 0, 0, 0, 0 ); 2910 cairo_set_operator( context, CAIRO_OPERATOR_SOURCE ); 2911 cairo_paint( context ); 2912 cairo_set_operator( context, CAIRO_OPERATOR_OVER ); 2913 2914 WindowShadow shadow(_settings, _helper); 2915 shadow.setWindowState(wopt); 2916 shadow.render(context, x,y,w,h); 2917 } 2918 2919 //__________________________________________________________________ drawWindecoButton(cairo_t * context,WinDeco::ButtonType type,WinDeco::ButtonStatus buttonState,WinDeco::Options windowState,gint x,gint y,gint w,gint h)2920 void Style::drawWindecoButton( cairo_t* context, WinDeco::ButtonType type, WinDeco::ButtonStatus buttonState, WinDeco::Options windowState, gint x, gint y, gint w,gint h) 2921 { 2922 // validate arguments 2923 if(type>=WinDeco::ButtonTypeCount || buttonState>=WinDeco::ButtonStatusCount) 2924 { return; } 2925 2926 if( !(windowState & WinDeco::Active) && buttonState == WinDeco::Normal ) 2927 { 2928 // draw Oxygen-way disabled button on inactive window 2929 buttonState=WinDeco::Disabled; 2930 } 2931 if( !(windowState & WinDeco::Alpha) && !(windowState & WinDeco::Maximized) ) 2932 { y++; } 2933 2934 WinDeco::Button button( _settings, _helper, type ); 2935 button.setState(buttonState); 2936 int buttonSize=_settings.buttonSize(); 2937 button.render( context, x+(w-buttonSize)/2+1,y+(h-buttonSize)/2+1, buttonSize, buttonSize ); 2938 } 2939 2940 //__________________________________________________________________ drawWindecoShapeMask(cairo_t * context,WinDeco::Options wopt,gint x,gint y,gint w,gint h)2941 void Style::drawWindecoShapeMask( cairo_t* context, WinDeco::Options wopt, gint x, gint y, gint w, gint h ) 2942 { 2943 cairo_save(context); 2944 cairo_set_source_rgba(context,0,0,0,0); 2945 cairo_set_operator(context,CAIRO_OPERATOR_SOURCE); 2946 cairo_paint(context); 2947 2948 cairo_set_source_rgba(context,1,1,1,1); 2949 cairo_set_operator(context,CAIRO_OPERATOR_OVER); 2950 cairo_set_antialias(context,CAIRO_ANTIALIAS_NONE); 2951 cairo_rounded_rectangle(context,x,y,w,h,6); 2952 cairo_fill(context); 2953 cairo_restore(context); 2954 2955 } 2956 2957 //__________________________________________________________________ sanitizeSize(GdkWindow * window,gint & w,gint & h) const2958 void Style::sanitizeSize( GdkWindow* window, gint& w, gint& h ) const 2959 { 2960 if( w < 0 && h < 0 ) gdk_drawable_get_size( window, &w, &h ); 2961 else if( w < 0 ) gdk_drawable_get_size( window, &w, 0L ); 2962 else if( h < 0 ) gdk_drawable_get_size( window, 0L, &h ); 2963 } 2964 2965 //__________________________________________________________________ adjustScrollBarHole(int & x,int & y,int & w,int & h,const StyleOptions & options) const2966 void Style::adjustScrollBarHole( int& x, int& y, int& w, int& h, const StyleOptions& options ) const 2967 { 2968 2969 const int buttonSize( 12 ); 2970 const int subLineOffset( buttonSize*_settings.scrollBarSubLineButtons() ); 2971 const int addLineOffset( buttonSize*_settings.scrollBarAddLineButtons() ); 2972 if( options&Vertical ) 2973 { 2974 2975 y += subLineOffset; 2976 h -= (subLineOffset+addLineOffset); 2977 2978 } else { 2979 2980 x += subLineOffset; 2981 w -= (subLineOffset+addLineOffset); 2982 2983 } 2984 2985 return; 2986 2987 } 2988 2989 //____________________________________________________________________________________ setBackgroundSurface(const std::string & filename)2990 void Style::setBackgroundSurface( const std::string& filename ) 2991 { 2992 if( _backgroundSurface.isValid() ) _backgroundSurface.free(); 2993 _backgroundSurface.set( cairo_image_surface_create_from_png( filename.c_str() ) ); 2994 } 2995 2996 //____________________________________________________________________________________ renderActiveTab(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,GtkPositionType side,const StyleOptions & options,const TabOptions & tabOptions)2997 void Style::renderActiveTab( 2998 GdkWindow* window, 2999 GdkRectangle* clipRect, 3000 gint x, gint y, gint w, gint h, 3001 GtkPositionType side, 3002 const StyleOptions& options, 3003 const TabOptions& tabOptions 3004 ) 3005 { 3006 3007 const bool isFirstTabAligned( tabOptions & FirstTabAligned ); 3008 const bool isLastTabAligned( tabOptions & LastTabAligned ); 3009 3010 // get color 3011 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 3012 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 3013 3014 // create context 3015 Cairo::Context context( window, clipRect ); 3016 3017 // borders and connections to tabs 3018 // this is quite painfull and slipery code. 3019 // the same is true with oxygen-qt 3020 int offset = 2; 3021 int adjust = ( tabOptions&Xul ) ? 0:2; 3022 const TileSet::Tiles tabTiles( Style::tabTiles( side ) ); 3023 3024 SlabRect tabSlab; 3025 SlabRect::List slabs; 3026 switch( side ) 3027 { 3028 case GTK_POS_BOTTOM: 3029 { 3030 // main slab 3031 y += adjust; h -= 2*adjust; 3032 tabSlab = SlabRect( x, y-offset, w, h+9+offset, tabTiles ); 3033 tabSlab._h+=1; 3034 3035 if( isFirstTabAligned ) { tabSlab._x-=1; tabSlab._w+=1; } 3036 if( isLastTabAligned ) { tabSlab._w+=1; } 3037 3038 // connections to frame 3039 if( isFirstTabAligned ) slabs.push_back( SlabRect( x-1, y+h+offset-6, 8, 18, TileSet::Left ) ); 3040 if( isLastTabAligned ) slabs.push_back( SlabRect( x+w-7, y+h+offset-6, 8, 18, TileSet::Right ) ); 3041 3042 break; 3043 } 3044 3045 case GTK_POS_TOP: 3046 { 3047 3048 // main slab 3049 y += adjust; h -= 2*adjust; 3050 tabSlab = SlabRect( x, y-9, w, h+11+offset, tabTiles ); 3051 tabSlab._y-=1; tabSlab._h+=1; 3052 3053 if( isFirstTabAligned ) { tabSlab._x-=1; tabSlab._w+=1; } 3054 if( isLastTabAligned ) { tabSlab._w-=1; } 3055 3056 // connections to frame 3057 if( isFirstTabAligned ) slabs.push_back( SlabRect( x-1, y-14, 8, 18, TileSet::Left ) ); 3058 if( isLastTabAligned ) slabs.push_back( SlabRect( x+w-7, y-14, 8, 18, TileSet::Right ) ); 3059 3060 break; 3061 } 3062 3063 case GTK_POS_RIGHT: 3064 { 3065 3066 // main slab 3067 x += adjust; w -= 2*adjust; 3068 tabSlab = SlabRect( x-offset, y, w+9+offset, h, tabTiles ); 3069 tabSlab._w+=1; 3070 if( isFirstTabAligned ) { tabSlab._y-=1; tabSlab._h+=1; } 3071 if( isLastTabAligned ) { tabSlab._h+=1; } 3072 3073 // connections to frame 3074 if( isFirstTabAligned ) slabs.push_back( SlabRect( x+w+offset-6, y-1, 18, 8, TileSet::Top ) ); 3075 if( isLastTabAligned ) slabs.push_back( SlabRect( x+w+offset-6, y+h-7, 18, 8, TileSet::Top ) ); 3076 3077 break; 3078 } 3079 3080 3081 case GTK_POS_LEFT: 3082 { 3083 3084 // main slab 3085 x += adjust; w -= 2*adjust; 3086 tabSlab = SlabRect( x-9, y, w+11+offset, h, tabTiles ); 3087 tabSlab._x-=1; tabSlab._w+=1; 3088 if( isFirstTabAligned ) { tabSlab._y-=1; tabSlab._h+=1; } 3089 if( isLastTabAligned ) { tabSlab._h+=1; } 3090 3091 // connections to frame 3092 if( isFirstTabAligned ) slabs.push_back( SlabRect( x-14, y-1, 18, 8, TileSet::Top ) ); 3093 if( isLastTabAligned ) slabs.push_back( SlabRect( x-14, y+h-7, 18, 8, TileSet::Top ) ); 3094 3095 break; 3096 3097 } 3098 3099 default: return; 3100 } 3101 3102 // render tab 3103 _helper.slab( base, 0 ).render( context, tabSlab._x, tabSlab._y, tabSlab._w, tabSlab._h, tabSlab._tiles ); 3104 3105 // adjust rect for filling 3106 SlabRect fillSlab( tabSlab ); 3107 fillSlab._x += 4; 3108 fillSlab._y += 4; 3109 fillSlab._w -= 8; 3110 fillSlab._h -= 8; 3111 3112 // fill 3113 Cairo::Pattern pattern; 3114 switch( side ) 3115 { 3116 case GTK_POS_BOTTOM: 3117 fillSlab._h -= 2; 3118 pattern.set( cairo_pattern_create_linear( 0, fillSlab._y, 0, fillSlab._y + fillSlab._h ) ); 3119 break; 3120 3121 case GTK_POS_TOP: 3122 fillSlab._y += 2; 3123 fillSlab._h -= 2; 3124 pattern.set( cairo_pattern_create_linear( 0, fillSlab._y + fillSlab._h, 0, fillSlab._y ) ); 3125 break; 3126 3127 case GTK_POS_RIGHT: 3128 fillSlab._w -= 2; 3129 pattern.set( cairo_pattern_create_linear( fillSlab._x, 0, fillSlab._x + fillSlab._w, 0 ) ); 3130 break; 3131 3132 case GTK_POS_LEFT: 3133 fillSlab._x += 2; 3134 fillSlab._w -= 2; 3135 pattern.set( cairo_pattern_create_linear( fillSlab._x + fillSlab._w, 0, fillSlab._x, 0 ) ); 3136 break; 3137 3138 default: return; 3139 3140 } 3141 3142 cairo_pattern_add_color_stop( pattern, 0.1, ColorUtils::alphaColor( light, 0.5 ) ); 3143 cairo_pattern_add_color_stop( pattern, 0.25, ColorUtils::alphaColor( light, 0.3 ) ); 3144 cairo_pattern_add_color_stop( pattern, 0.5, ColorUtils::alphaColor( light, 0.2 ) ); 3145 cairo_pattern_add_color_stop( pattern, 0.75, ColorUtils::alphaColor( light, 0.1 ) ); 3146 cairo_pattern_add_color_stop( pattern, 0.9, ColorUtils::Rgba::transparent( light ) ); 3147 3148 // in firefox a solid background must be filled 3149 if( tabOptions&Xul ) 3150 { 3151 cairo_set_source( context, base ); 3152 cairo_rectangle( context, fillSlab._x, fillSlab._y, fillSlab._w, fillSlab._h ); 3153 cairo_fill( context ); 3154 } 3155 3156 // draw pattern 3157 cairo_set_source( context, pattern ); 3158 cairo_rectangle( context, fillSlab._x, fillSlab._y, fillSlab._w, fillSlab._h ); 3159 cairo_fill( context ); 3160 3161 // render connections to frame 3162 for( SlabRect::List::const_iterator iter = slabs.begin(); iter != slabs.end(); ++iter ) 3163 { _helper.slab(base, 0).render( context, iter->_x, iter->_y, iter->_w, iter->_h, iter->_tiles ); } 3164 3165 } 3166 3167 //____________________________________________________________________________________ renderInactiveTab_Single(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,GtkPositionType side,const StyleOptions & options,const TabOptions & tabOptions,const AnimationData & data)3168 void Style::renderInactiveTab_Single( 3169 GdkWindow* window, 3170 GdkRectangle* clipRect, 3171 gint x, gint y, gint w, gint h, 3172 GtkPositionType side, 3173 const StyleOptions& options, 3174 const TabOptions& tabOptions, 3175 const AnimationData& data 3176 ) 3177 { 3178 3179 // convenience flags 3180 const bool isFirstTabAligned( tabOptions & FirstTabAligned ); 3181 const bool isLastTabAligned( tabOptions & LastTabAligned ); 3182 3183 // get color 3184 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 3185 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 3186 const ColorUtils::Rgba dark( ColorUtils::darkColor( base ) ); 3187 3188 // create context 3189 Cairo::Context context( window, clipRect ); 3190 3191 // borders and connections to tabs 3192 // this is quite painfull and slipery code. 3193 // the same is true with oxygen-qt 3194 int offset = 2; 3195 int adjust = (tabOptions&Xul) ? 0:2; 3196 const TileSet::Tiles tabTiles( Style::tabTiles( side ) ); 3197 3198 SlabRect tabSlab; 3199 SlabRect::List slabs; 3200 switch( side ) 3201 { 3202 case GTK_POS_BOTTOM: 3203 { 3204 // main slab 3205 y += adjust; h -= 2*adjust; 3206 tabSlab = SlabRect( x, y-offset, w, h+9+offset, tabTiles ); 3207 if( isFirstTabAligned ) { tabSlab._x-=1; tabSlab._w+=1; } 3208 if( isLastTabAligned ) { tabSlab._w+=1; } 3209 3210 // connections to frame 3211 if( isFirstTabAligned ) slabs.push_back( SlabRect( x-1, y+h+offset-7, 8, 17, TileSet::Left, Hover ) ); 3212 if( isLastTabAligned ) slabs.push_back( SlabRect( x+w-7, y+h+offset-7, 8, 17, TileSet::Right, Hover ) ); 3213 break; 3214 } 3215 3216 case GTK_POS_TOP: 3217 { 3218 3219 // main slab 3220 y += adjust; h -= 2*adjust; 3221 tabSlab = SlabRect( x, y-9, w, h+11+offset, tabTiles ); 3222 if( isFirstTabAligned ) { tabSlab._x-=1; tabSlab._w+=1; } 3223 if( isLastTabAligned ) { tabSlab._w-=1; } 3224 3225 // connections to frame 3226 if( isFirstTabAligned ) slabs.push_back( SlabRect( x-1, y-13+offset, 8, 16, TileSet::Left, Hover ) ); 3227 if( isLastTabAligned ) slabs.push_back( SlabRect( x+w-7, y-13+offset, 8, 16, TileSet::Right, Hover ) ); 3228 break; 3229 } 3230 3231 case GTK_POS_RIGHT: 3232 { 3233 3234 // main slab 3235 x += adjust; w -= 2*adjust; 3236 tabSlab = SlabRect( x-offset, y, w+9+offset, h, tabTiles ); 3237 if( isFirstTabAligned ) { tabSlab._y-=1; tabSlab._h+=1; } 3238 if( isLastTabAligned ) { tabSlab._h+=1; } 3239 3240 // connections to frame 3241 if( isFirstTabAligned ) slabs.push_back( SlabRect( x+w+offset-7, y-1, 17, 8, TileSet::Top, Hover ) ); 3242 if( isLastTabAligned ) slabs.push_back( SlabRect( x+w+offset-7, y+h-7, 17, 8, TileSet::Top, Hover ) ); 3243 break; 3244 } 3245 3246 3247 case GTK_POS_LEFT: 3248 { 3249 3250 // main slab 3251 x += adjust; w -= 2*adjust; 3252 tabSlab = SlabRect( x-9, y, w+11+offset, h, tabTiles ); 3253 if( isFirstTabAligned ) { tabSlab._y-=1; tabSlab._h+=1; } 3254 if( isLastTabAligned ) { tabSlab._h+=1; } 3255 3256 // connections to frame 3257 SlabRect baseSlab( x-10+1, y-6, 10, h+12, TileSet::Right ); 3258 if( isFirstTabAligned ) slabs.push_back( SlabRect( x-13 + offset, y-1, 16, 8, TileSet::Top, Hover ) ); 3259 if( isLastTabAligned )slabs.push_back( SlabRect( x-13 + offset, y+h-7, 16, 8, TileSet::Top, Hover ) ); 3260 break; 3261 } 3262 3263 default: return; 3264 } 3265 3266 // render tab 3267 ColorUtils::Rgba glow; 3268 if( data._mode == AnimationHover ) glow = ColorUtils::alphaColor( _settings.palette().color( Palette::Hover ), data._opacity ); 3269 else if( options&Hover ) glow = _settings.palette().color( Palette::Hover ); 3270 3271 _helper.slab( base, glow ).render( context, tabSlab._x, tabSlab._y, tabSlab._w, tabSlab._h, tabSlab._tiles ); 3272 3273 // adjust rect for filling 3274 SlabRect fillSlab( tabSlab ); 3275 fillSlab._x += 4; 3276 fillSlab._y += 4; 3277 fillSlab._w -= 8; 3278 fillSlab._h -= 8; 3279 3280 // fill 3281 Cairo::Pattern pattern; 3282 switch( side ) 3283 { 3284 case GTK_POS_BOTTOM: 3285 fillSlab._h -= 3; 3286 pattern.set( cairo_pattern_create_linear( 0, fillSlab._y, 0, fillSlab._y + fillSlab._h ) ); 3287 break; 3288 3289 case GTK_POS_TOP: 3290 fillSlab._y += 3; 3291 fillSlab._h -= 3; 3292 pattern.set( cairo_pattern_create_linear( 0, fillSlab._y + fillSlab._h, 0, fillSlab._y ) ); 3293 break; 3294 3295 case GTK_POS_RIGHT: 3296 fillSlab._w -= 3; 3297 pattern.set( cairo_pattern_create_linear( fillSlab._x, 0, fillSlab._x + fillSlab._w, 0 ) ); 3298 break; 3299 3300 case GTK_POS_LEFT: 3301 fillSlab._x += 3; 3302 fillSlab._w -= 3; 3303 pattern.set( cairo_pattern_create_linear( fillSlab._x + fillSlab._w, 0, fillSlab._x, 0 ) ); 3304 break; 3305 3306 default: return; 3307 3308 } 3309 3310 cairo_pattern_add_color_stop( pattern, 0.0, ColorUtils::alphaColor( light, 0.1 ) ); 3311 cairo_pattern_add_color_stop( pattern, 0.4, ColorUtils::alphaColor( dark, 0.5 ) ); 3312 cairo_pattern_add_color_stop( pattern, 0.8, ColorUtils::alphaColor( dark, 0.4 ) ); 3313 3314 // draw pattern 3315 cairo_set_source( context, pattern ); 3316 cairo_rectangle( context, fillSlab._x, fillSlab._y, fillSlab._w, fillSlab._h ); 3317 cairo_fill( context ); 3318 3319 // render connections to frame 3320 for( SlabRect::List::const_iterator iter = slabs.begin(); iter != slabs.end(); ++iter ) 3321 { 3322 3323 if( (iter->_options&Hover) && glow.isValid() ) 3324 { 3325 3326 _helper.slab(base, glow).render( context, iter->_x, iter->_y, iter->_w, iter->_h, iter->_tiles ); 3327 3328 } else { 3329 3330 _helper.slab(base).render( context, iter->_x, iter->_y, iter->_w, iter->_h, iter->_tiles ); 3331 3332 } 3333 } 3334 } 3335 3336 //____________________________________________________________________________________ renderInactiveTab_Plain(GdkWindow * window,GdkRectangle * clipRect,gint x,gint y,gint w,gint h,GtkPositionType side,const StyleOptions & options,const TabOptions & tabOptions,const AnimationData & data)3337 void Style::renderInactiveTab_Plain( 3338 GdkWindow* window, 3339 GdkRectangle* clipRect, 3340 gint x, gint y, gint w, gint h, 3341 GtkPositionType side, 3342 const StyleOptions& options, 3343 const TabOptions& tabOptions, 3344 const AnimationData& data 3345 ) 3346 { 3347 // convenience flags 3348 const bool isFirstTabAligned( tabOptions & FirstTabAligned ); 3349 const bool isLastTabAligned( tabOptions & LastTabAligned ); 3350 3351 const bool isLeftOfSelected( tabOptions & LeftOfSelected ); 3352 const bool isRightOfSelected( tabOptions & RightOfSelected ); 3353 3354 // get color 3355 const ColorUtils::Rgba base( _settings.palette().color( Palette::Window ) ); 3356 3357 // create context 3358 Cairo::Context context( window, clipRect ); 3359 3360 // borders and connections to tabs 3361 // this is quite painfull and slipery code. 3362 // the same is true with oxygen-qt 3363 int offset = 2; 3364 int adjust = (tabOptions&Xul) ? 0:2; 3365 const TileSet::Tiles tabTiles( Style::tabTiles( side ) ); 3366 3367 SlabRect tabSlab; 3368 SlabRect::List slabs; 3369 switch( side ) 3370 { 3371 case GTK_POS_BOTTOM: 3372 { 3373 // main slab 3374 y += adjust; h -= 2*adjust; 3375 tabSlab = SlabRect( x, y-offset, w, h+10 + offset, tabTiles ); 3376 if( isFirstTabAligned ) { tabSlab._x-=1; tabSlab._w+=1; } 3377 if( isLastTabAligned ) { tabSlab._w+=1; } 3378 3379 // connections to frame 3380 SlabRect baseSlab( x-4-1, y+h-1, w+8+2, 10, TileSet::Top ); 3381 if( isFirstTabAligned ) 3382 { 3383 baseSlab._x += 4; baseSlab._w -= 4; baseSlab._tiles |= TileSet::Left; 3384 slabs.push_back( SlabRect( x-1, y+h+offset-6, 8, 16, TileSet::Left ) ); 3385 } 3386 3387 if( isLastTabAligned ) 3388 { 3389 baseSlab._w -= 4; baseSlab._tiles |= TileSet::Right; 3390 slabs.push_back( SlabRect( x+w-7, y+h+offset-6, 8, 16, TileSet::Right ) ); 3391 } 3392 3393 if( isLeftOfSelected ) { baseSlab._w += 3; } 3394 else if( isRightOfSelected ) { baseSlab._x -= 3; baseSlab._w += 4; } 3395 else { baseSlab._w += 2; } 3396 3397 slabs.push_back( baseSlab ); 3398 break; 3399 } 3400 3401 case GTK_POS_TOP: 3402 { 3403 3404 // main slab 3405 y += adjust; h -= 2*adjust; 3406 tabSlab = SlabRect( x, y-10, w, h+10+offset, tabTiles ); 3407 if( isFirstTabAligned ) { tabSlab._x-=1; tabSlab._w+=1; } 3408 if( isLastTabAligned ) { tabSlab._w-=1; } 3409 3410 // connections to frame 3411 SlabRect baseSlab( x-4-1, y-10+1, w+8+2, 10, TileSet::Bottom ); 3412 if( isFirstTabAligned ) { baseSlab._x += 4; baseSlab._w -= 4; baseSlab._tiles |= TileSet::Left; } 3413 if( isLastTabAligned ) { baseSlab._w -=4; baseSlab._tiles |= TileSet::Right; } 3414 if( isLeftOfSelected ) { baseSlab._w += 3; } 3415 else if( isRightOfSelected ) { baseSlab._x -= 3; baseSlab._w += 4; } 3416 else { baseSlab._w += 2; } 3417 3418 slabs.push_back( baseSlab ); 3419 break; 3420 } 3421 3422 case GTK_POS_RIGHT: 3423 { 3424 3425 // main slab 3426 x += adjust; w -= 2*adjust; 3427 tabSlab = SlabRect( x-offset, y, w+10+offset, h, tabTiles ); 3428 if( isFirstTabAligned ) { tabSlab._y-=1; tabSlab._h+=1; } 3429 if( isLastTabAligned ) { tabSlab._h+=1; } 3430 3431 // connections to frame 3432 SlabRect baseSlab( x+w-1, y-4-1, 10, h+8+3, TileSet::Left ); 3433 if( isFirstTabAligned ) 3434 { 3435 baseSlab._y += 4; baseSlab._h -= 4; baseSlab._tiles |= TileSet::Top; 3436 slabs.push_back( SlabRect( x+w+offset-6, y-1, 16, 8, TileSet::Top ) ); 3437 } 3438 3439 if( isLastTabAligned ) 3440 { 3441 baseSlab._h -= 4; baseSlab._tiles |= TileSet::Bottom; 3442 slabs.push_back( SlabRect( x+w+offset-6, y+h-7, 16, 8, TileSet::Top ) ); 3443 } 3444 3445 if( isLeftOfSelected ) { baseSlab._h += 3; } 3446 else if( isRightOfSelected ) { baseSlab._y -= 3; baseSlab._h += 3; } 3447 else { baseSlab._h += 1; } 3448 3449 slabs.push_back( baseSlab ); 3450 break; 3451 } 3452 3453 3454 case GTK_POS_LEFT: 3455 { 3456 3457 // main slab 3458 x += adjust; w -= 2*adjust; 3459 tabSlab = SlabRect( x-10, y, w+10+offset, h, tabTiles ); 3460 if( isFirstTabAligned ) { tabSlab._y-=1; tabSlab._h+=1; } 3461 if( isLastTabAligned ) { tabSlab._h+=1; } 3462 3463 // connections to frame 3464 SlabRect baseSlab( x-10+1, y-4-1, 10, h+8+3, TileSet::Right ); 3465 if( isFirstTabAligned ) 3466 { 3467 baseSlab._y += 4; baseSlab._h -= 4; baseSlab._tiles |= TileSet::Top; 3468 slabs.push_back( SlabRect( x-10+1 + offset-5, y-1, 16, 8, TileSet::Top ) ); 3469 } 3470 3471 if( isLastTabAligned ) 3472 { 3473 baseSlab._h -= 4; baseSlab._tiles |= TileSet::Bottom; 3474 slabs.push_back( SlabRect( x-10+1 + offset-5, y+h-7, 16, 8, TileSet::Top ) ); 3475 } 3476 3477 if( isLeftOfSelected ) { baseSlab._h += 3; } 3478 else if( isRightOfSelected ) { baseSlab._y -= 3; baseSlab._h += 3; } 3479 else { baseSlab._h += 1; } 3480 3481 slabs.push_back( baseSlab ); 3482 break; 3483 } 3484 3485 default: return; 3486 } 3487 3488 const bool isFirstTab( tabOptions & FirstTab ); 3489 const bool isLastTab( tabOptions & LastTab ); 3490 3491 const double radius( 5 ); 3492 double xF( 0.5 + x ); 3493 double yF( 0.5 + y ); 3494 double wF( w-1 ); 3495 double hF( h-1 ); 3496 3497 switch( side ) 3498 { 3499 3500 case GTK_POS_BOTTOM: 3501 { 3502 xF += 1.0; 3503 wF -= 1.0; 3504 hF += 2; 3505 if( isLeftOfSelected ) wF += 1; 3506 else if( isRightOfSelected ) { xF -= 2; wF += 2; } 3507 3508 if( isFirstTab ) 3509 { 3510 3511 if( isFirstTabAligned ) cairo_move_to( context, xF, yF + hF + 2 ); 3512 else cairo_move_to( context, xF, yF + hF ); 3513 3514 cairo_line_to( context, xF, yF + radius ); 3515 cairo_arc( context, xF + radius, yF + radius, radius, M_PI, 3.0*M_PI/2 ); 3516 cairo_line_to( context, xF + wF, yF ); 3517 cairo_line_to( context, xF + wF, yF + hF ); 3518 3519 } else if( isLastTab ) { 3520 3521 cairo_move_to( context, xF, yF + hF ); 3522 cairo_line_to( context, xF, yF ); 3523 cairo_line_to( context, xF + wF - radius, yF ); 3524 cairo_arc( context, xF + wF - radius, yF + radius, radius, 3.0*M_PI/2, 2.0*M_PI ); 3525 if( isLastTabAligned ) cairo_line_to( context, xF + wF, yF + hF + 2 ); 3526 else cairo_line_to( context, xF + wF, yF + hF ); 3527 3528 } else { 3529 3530 cairo_move_to( context, xF, yF + hF ); 3531 cairo_line_to( context, xF, yF ); 3532 cairo_line_to( context, xF + wF, yF ); 3533 cairo_line_to( context, xF + wF, yF + hF ); 3534 3535 } 3536 3537 } 3538 3539 break; 3540 3541 case GTK_POS_TOP: 3542 { 3543 xF += 1.0; 3544 wF -= 1.0; 3545 yF -= 1; 3546 hF += 1; 3547 if( isLeftOfSelected ) wF += 1; 3548 else if( isRightOfSelected ) { xF -= 2; wF += 2; } 3549 3550 3551 if( isFirstTab ) 3552 { 3553 3554 cairo_move_to( context, xF+wF, yF ); 3555 cairo_line_to( context, xF+wF, yF + hF ); 3556 cairo_line_to( context, xF+radius, yF + hF ); 3557 cairo_arc( context, xF+radius, yF + hF -radius, radius, M_PI/2, M_PI ); 3558 if( isFirstTabAligned ) cairo_line_to( context, xF, yF - 2 ); 3559 else cairo_line_to( context, xF, yF ); 3560 3561 } else if( isLastTab ) { 3562 3563 if( isLastTabAligned ) cairo_move_to( context, xF+wF, yF-2 ); 3564 else cairo_move_to( context, xF+wF, yF-2 ); 3565 cairo_line_to( context, xF+wF, yF+hF-radius ); 3566 cairo_arc( context, xF+wF-radius, yF+hF-radius, radius, 0, M_PI/2 ); 3567 cairo_line_to( context, xF, yF+hF ); 3568 cairo_line_to( context, xF, yF ); 3569 3570 } else { 3571 3572 cairo_move_to( context, xF+wF, yF ); 3573 cairo_line_to( context, xF+wF, yF + hF ); 3574 cairo_line_to( context, xF, yF+hF ); 3575 cairo_line_to( context, xF, yF ); 3576 3577 } 3578 3579 } 3580 3581 break; 3582 3583 case GTK_POS_RIGHT: 3584 { 3585 3586 yF += 1.0; 3587 hF -= 1.0; 3588 wF += 2; 3589 3590 if( isLeftOfSelected ) hF += 1; 3591 else if( isRightOfSelected ) { yF -= 2; hF += 2; } 3592 3593 if( isFirstTab ) 3594 { 3595 3596 cairo_move_to( context, xF+wF, yF+hF ); 3597 cairo_line_to( context, xF, yF+hF ); 3598 cairo_line_to( context, xF, yF+radius ); 3599 cairo_arc( context, xF+radius, yF+radius, radius, M_PI, 3.0*M_PI/2 ); 3600 if( isFirstTabAligned ) cairo_line_to( context, xF+wF+2, yF ); 3601 else cairo_line_to( context, xF+wF, yF ); 3602 3603 } else if( isLastTab ) { 3604 3605 if( isLastTabAligned ) cairo_line_to( context, xF + wF + 2, yF + hF ); 3606 else cairo_line_to( context, xF + wF, yF + hF ); 3607 cairo_line_to( context, xF+radius, yF+hF ); 3608 cairo_arc( context, xF+radius, yF+hF - radius, radius, M_PI/2, M_PI ); 3609 cairo_line_to( context, xF, yF ); 3610 cairo_line_to( context, xF + wF, yF ); 3611 3612 } else { 3613 3614 cairo_move_to( context, xF+wF, yF+hF ); 3615 cairo_line_to( context, xF, yF+hF ); 3616 cairo_line_to( context, xF, yF ); 3617 cairo_line_to( context, xF+wF, yF ); 3618 3619 } 3620 } 3621 break; 3622 3623 case GTK_POS_LEFT: 3624 { 3625 yF += 1.0; 3626 hF -= 1.0; 3627 xF -= 2; 3628 wF += 2; 3629 3630 if( isLeftOfSelected ) hF += 1; 3631 else if( isRightOfSelected ) { yF -= 2; hF += 2; } 3632 3633 if( isFirstTab ) 3634 { 3635 3636 if( isFirstTabAligned ) cairo_move_to( context, xF-2, yF ); 3637 else cairo_move_to( context, xF, yF ); 3638 cairo_line_to( context, xF + wF - radius, yF ); 3639 cairo_arc( context, xF + wF - radius, yF + radius, radius, 3.0*M_PI/2, 2*M_PI ); 3640 cairo_line_to( context, xF+wF, yF+hF ); 3641 cairo_line_to( context, xF, yF+hF ); 3642 3643 } else if( isLastTab ) { 3644 3645 cairo_move_to( context, xF, yF ); 3646 cairo_line_to( context, xF+wF, yF ); 3647 cairo_line_to( context, xF+wF, yF + hF - radius ); 3648 cairo_arc( context, xF+wF-radius, yF + hF - radius, radius, 0, M_PI/2 ); 3649 if( isLastTabAligned ) cairo_line_to( context, xF-2, yF+hF ); 3650 else cairo_line_to( context, xF, yF+hF ); 3651 3652 } else { 3653 3654 cairo_move_to( context, xF, yF ); 3655 cairo_line_to( context, xF+wF, yF ); 3656 cairo_line_to( context, xF+wF, yF+hF ); 3657 cairo_line_to( context, xF, yF+hF ); 3658 3659 } 3660 } 3661 break; 3662 3663 default: return; 3664 3665 } 3666 3667 ColorUtils::Rgba backgroundColor( base ); 3668 { 3669 3670 gint wh, wy; 3671 Gtk::gdk_map_to_toplevel( window, 0L, &wy, 0L, &wh ); 3672 if( wh > 0 ) 3673 { backgroundColor = ColorUtils::backgroundColor( _settings.palette().color( Palette::Window ), wh, y+wy+h/2 ); } 3674 3675 } 3676 3677 const ColorUtils::Rgba midColor( ColorUtils::alphaColor( ColorUtils::darkColor( backgroundColor ), 0.4 ) ); 3678 const ColorUtils::Rgba darkColor( ColorUtils::alphaColor( ColorUtils::darkColor( backgroundColor ), 0.8 ) ); 3679 3680 cairo_set_line_width( context, 1.0 ); 3681 cairo_set_source( context, midColor ); 3682 cairo_fill_preserve( context ); 3683 3684 cairo_set_source( context, darkColor ); 3685 cairo_stroke( context ); 3686 3687 ColorUtils::Rgba glow; 3688 if( data._mode == AnimationHover ) glow = ColorUtils::alphaColor( _settings.palette().color( Palette::Hover ), data._opacity ); 3689 else if( options&Hover ) glow = _settings.palette().color( Palette::Hover ); 3690 3691 for( SlabRect::List::const_iterator iter = slabs.begin(); iter != slabs.end(); ++iter ) 3692 { _helper.slab(base, glow, 0).render( context, iter->_x, iter->_y, iter->_w, iter->_h, iter->_tiles ); } 3693 3694 } 3695 3696 //____________________________________________________________________________________ slabShadowColor(const StyleOptions & options,const AnimationData & data) const3697 ColorUtils::Rgba Style::slabShadowColor( const StyleOptions& options, const AnimationData& data ) const 3698 { 3699 3700 // no glow when widget is disabled 3701 if( options&Disabled ) return ColorUtils::Rgba(); 3702 3703 if( (options&Flat) && !(options&Sunken) ) 3704 { 3705 3706 /* 3707 flat buttons have special handling of colors: hover and focus are both assigned 3708 the hover color. This is consistent with oxygen-qt, though quite inconsistent with 3709 other widgets. 3710 */ 3711 if( 3712 ( data._mode == AnimationHover && (options&Focus) ) || 3713 ( data._mode == AnimationFocus && (options&Hover) ) ) 3714 { 3715 return _settings.palette().color( Palette::Focus ); 3716 3717 } else if( data._mode & (AnimationHover|AnimationFocus) ) { 3718 3719 return ColorUtils::alphaColor( _settings.palette().color( Palette::Focus ), data._opacity ); 3720 3721 } else if( options&(Focus|Hover) ) { 3722 3723 return _settings.palette().color( Palette::Focus ); 3724 3725 } else return ColorUtils::Rgba(); 3726 3727 } else if( data._mode == AnimationHover ) { 3728 3729 if( options & Focus ) 3730 { 3731 return ColorUtils::mix( 3732 _settings.palette().color( Palette::Focus ), 3733 _settings.palette().color( Palette::Hover ), data._opacity ); 3734 3735 } else { 3736 3737 return ColorUtils::alphaColor( _settings.palette().color( Palette::Hover ), data._opacity ); 3738 3739 } 3740 3741 } else if( options&Hover ) { 3742 3743 return _settings.palette().color( Palette::Hover ); 3744 3745 } else if( data._mode == AnimationFocus ) { 3746 3747 return ColorUtils::alphaColor( _settings.palette().color( Palette::Focus ), data._opacity ); 3748 3749 } else if( options&Focus ) { 3750 3751 return _settings.palette().color( Palette::Focus ); 3752 3753 } else return ColorUtils::Rgba(); 3754 3755 } 3756 3757 //____________________________________________________________________________________ holeShadowColor(const StyleOptions & options,const AnimationData & data) const3758 ColorUtils::Rgba Style::holeShadowColor( const StyleOptions& options, const AnimationData& data ) const 3759 { 3760 3761 // no glow when widget is disabled 3762 if( options&Disabled ) return ColorUtils::Rgba(); 3763 3764 if( data._mode == AnimationFocus && data._opacity >= 0 ) 3765 { 3766 3767 if( options & Hover ) 3768 { 3769 3770 return ColorUtils::mix( 3771 _settings.palette().color( Palette::Hover ), 3772 _settings.palette().color( Palette::Focus ), data._opacity ); 3773 3774 } else return ColorUtils::alphaColor( _settings.palette().color( Palette::Focus ), data._opacity ); 3775 3776 } else if( options & Focus ) { 3777 3778 return _settings.palette().color( Palette::Focus ); 3779 3780 } else if( data._mode == AnimationHover && data._opacity >= 0 ) { 3781 3782 return ColorUtils::alphaColor( _settings.palette().color( Palette::Hover ), data._opacity ); 3783 3784 } else if( options & Hover ) { 3785 3786 return _settings.palette().color( Palette::Hover ); 3787 3788 } else return ColorUtils::Rgba(); 3789 3790 } 3791 3792 //__________________________________________________________________ renderGroupBox(cairo_t * context,const ColorUtils::Rgba & base,gint x,gint y,gint w,gint h,const StyleOptions & options)3793 void Style::renderGroupBox( 3794 cairo_t* context, 3795 const ColorUtils::Rgba& base, 3796 gint x, gint y, gint w, gint h, 3797 const StyleOptions& options ) 3798 { 3799 3800 cairo_push_group( context ); 3801 Cairo::Pattern pattern( cairo_pattern_create_linear( 0, y - h + 12, 0, y + 2*h - 19 ) ); 3802 const ColorUtils::Rgba light( ColorUtils::lightColor( base ) ); 3803 cairo_pattern_add_color_stop( pattern, 0, ColorUtils::alphaColor( light, 0.4 ) ); 3804 cairo_pattern_add_color_stop( pattern, 1, ColorUtils::Rgba::transparent( light ) ); 3805 cairo_set_source( context, pattern ); 3806 3807 if( !_settings.applicationName().useFlatBackground( 0L ) ) 3808 _helper.fillSlab( context, x, y, w, h ); 3809 3810 if( !(options&NoFill) ) 3811 { _helper.slope( base, 0.0 ).render( context, x, y, w, h ); } 3812 3813 cairo_pop_group_to_source( context ); 3814 3815 Cairo::Pattern mask( cairo_pattern_create_linear( 0, y + h - 19, 0, y + h ) ); 3816 cairo_pattern_add_color_stop( mask, 0, ColorUtils::Rgba::black() ); 3817 cairo_pattern_add_color_stop( mask, 1.0, ColorUtils::Rgba::transparent() ); 3818 cairo_mask( context, mask ); 3819 3820 return; 3821 3822 } 3823 3824 //__________________________________________________________________ renderSlab(Cairo::Context & context,gint x,gint y,gint w,gint h,const ColorUtils::Rgba & base,const StyleOptions & options,const AnimationData & animationData,TileSet::Tiles tiles)3825 void Style::renderSlab( 3826 Cairo::Context& context, 3827 gint x, gint y, gint w, gint h, 3828 const ColorUtils::Rgba& base, 3829 const StyleOptions& options, 3830 const AnimationData& animationData, 3831 TileSet::Tiles tiles ) 3832 { 3833 3834 // do nothing if not enough room 3835 if( w<14 || h<14 ) return; 3836 3837 // additional adjustment for sunken frames 3838 // TODO: double check 3839 if( options & Sunken) 3840 { 3841 3842 x -= 1; 3843 w += 2; 3844 h += 2; 3845 3846 } 3847 3848 // fill 3849 if( !(options & NoFill)) 3850 { 3851 3852 Cairo::Pattern pattern; 3853 const ColorUtils::Rgba shadow( ColorUtils::shadowColor( base ) ); 3854 if( shadow.value() > base.value() && (options & Sunken) ) 3855 { 3856 3857 pattern.set( cairo_pattern_create_linear( 0, y, 0, y+2*h ) ); 3858 cairo_pattern_add_color_stop( pattern, 0, base ); 3859 cairo_pattern_add_color_stop( pattern, 1.0, ColorUtils::lightColor( base ) ); 3860 3861 } else { 3862 3863 pattern.set( cairo_pattern_create_linear( 0, y-h, 0, y+h ) ); 3864 cairo_pattern_add_color_stop( pattern, 0, ColorUtils::lightColor( base ) ); 3865 cairo_pattern_add_color_stop( pattern, 1.0, base ); 3866 3867 } 3868 3869 cairo_set_source( context, pattern ); 3870 _helper.fillSlab( context, x, y, w, h, tiles ); 3871 3872 } 3873 3874 if( !(options&Sunken) ) { 3875 3876 // calculate glow color 3877 const TileSet* tile; 3878 const ColorUtils::Rgba glow( slabShadowColor( options, animationData ) ); 3879 if( glow.isValid() || base.isValid() ) tile = &_helper.slab( base, glow , 0); 3880 else return; 3881 3882 if( tile ) tile->render( context, x, y, w, h ); 3883 3884 } else if( base.isValid() ) { 3885 3886 _helper.slabSunken( base ).render( context, x, y, w, h ); 3887 3888 } 3889 3890 } 3891 3892 //__________________________________________________________________ renderScrollBarHole(Cairo::Context & context,gint x,gint y,gint w,gint h,const ColorUtils::Rgba & base,bool vertical,TileSet::Tiles tiles)3893 void Style::renderScrollBarHole( Cairo::Context& context, gint x, gint y, gint w, gint h, const ColorUtils::Rgba& base, bool vertical, TileSet::Tiles tiles ) 3894 { 3895 3896 // use tileset from helper 3897 _helper.scrollHole( base, vertical ).render( context, x, y, w, h, tiles ); 3898 3899 } 3900 3901 //__________________________________________________________________ genericArrow(GtkArrowType orientation,QtSettings::ArrowSize size) const3902 Polygon Style::genericArrow( GtkArrowType orientation, QtSettings::ArrowSize size ) const 3903 { 3904 3905 Polygon a; 3906 switch( orientation ) 3907 { 3908 3909 case GTK_ARROW_UP: 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,2.5 ) << Point( 0.5, -1.5 ) << Point( 4,2.5 ); 3914 break; 3915 } 3916 3917 case GTK_ARROW_DOWN: 3918 { 3919 if( size == QtSettings::ArrowTiny ) a << Point( -1.75, -1.125 ) << Point( 0.5, 1.125 ) << Point( 2.75, -1.125 ); 3920 else if( size == QtSettings::ArrowSmall ) a << Point( -2,-1.5 ) << Point( 0.5, 1.5 ) << Point( 3,-1.5 ); 3921 else a << Point( -3,-1.5 ) << Point( 0.5, 2.5 ) << Point( 4,-1.5 ); 3922 break; 3923 } 3924 3925 case GTK_ARROW_LEFT: 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( 2.5,-3 ) << Point( -1.5, 0.5 ) << Point( 2.5,4 ); 3930 break; 3931 } 3932 3933 case GTK_ARROW_RIGHT: 3934 { 3935 if( size == QtSettings::ArrowTiny ) a << Point( -1.125, -1.75 ) << Point( 1.125, 0.5 ) << Point( -1.125, 2.75 ); 3936 else if( size == QtSettings::ArrowSmall ) a << Point( -1.5,-2 ) << Point( 1.5, 0.5 ) << Point( -1.5,3 ); 3937 else a << Point( -1.5,-3 ) << Point( 2.5, 0.5 ) << Point( -1.5,4 ); 3938 break; 3939 } 3940 3941 default: break; 3942 3943 } 3944 3945 return a; 3946 3947 3948 3949 } 3950 3951 //__________________________________________________________________ renderWindowDots(cairo_t * context,gint x,gint y,gint w,gint h,const ColorUtils::Rgba & color,WinDeco::Options wopt)3952 void Style::renderWindowDots(cairo_t* context, gint x, gint y, gint w, gint h, const ColorUtils::Rgba& color, WinDeco::Options wopt) 3953 { 3954 bool isMaximized( wopt & WinDeco::Maximized ); 3955 bool hasAlpha( wopt & WinDeco::Alpha ); 3956 int offset( hasAlpha ? 0 : -1 ); 3957 if( _settings.frameBorder() >= QtSettings::BorderTiny ) 3958 { 3959 if( !isMaximized ) 3960 { 3961 // Draw right side 3-dots resize handles 3962 int cenY = int(h/2+y); 3963 int posX = int(w+x-3) + 1; 3964 _helper.renderDot(context,color,posX+offset, cenY-3); 3965 _helper.renderDot(context,color,posX+offset, cenY); 3966 _helper.renderDot(context,color,posX+offset, cenY+3); 3967 } 3968 3969 // Draw bottom-right corner 3-dots resize handles 3970 // if( !config.drawSizeGrip ) 3971 { 3972 cairo_save(context); 3973 cairo_translate(context,x+w-8,y+h-8); 3974 _helper.renderDot(context,color,2+offset,6+offset); 3975 _helper.renderDot(context,color,5+offset,5+offset); 3976 _helper.renderDot(context,color,6+offset,2+offset); 3977 cairo_restore(context); 3978 } 3979 } 3980 } 3981 3982 //__________________________________________________________________ centerRect(GdkRectangle * parent,GdkRectangle * child) const3983 void Style::centerRect( GdkRectangle* parent, GdkRectangle* child ) const 3984 { 3985 if( !( parent && child ) ) return; 3986 child->x = parent->x + (parent->width - child->width)/2; 3987 child->y = parent->y + (parent->height - child->height)/2; 3988 return; 3989 } 3990 3991 //__________________________________________________________________ generateGapMask(Cairo::Context & context,gint x,gint y,gint w,gint h,const Gtk::Gap & gap) const3992 void Style::generateGapMask( Cairo::Context& context, gint x, gint y, gint w, gint h, const Gtk::Gap& gap ) const 3993 { 3994 3995 if( gap.width() <= 0 ) return; 3996 3997 // store current rect in 3998 GdkRectangle mask( Gtk::gdk_rectangle() ); 3999 4000 switch( gap.position() ) 4001 { 4002 case GTK_POS_TOP: 4003 { 4004 mask = Gtk::gdk_rectangle( x+gap.x(), y, gap.width(), gap.height() ); 4005 break; 4006 } 4007 4008 case GTK_POS_BOTTOM: 4009 { 4010 mask = Gtk::gdk_rectangle( x+gap.x(), y+h-gap.height(), gap.width(), gap.height() ); 4011 break; 4012 } 4013 4014 case GTK_POS_LEFT: 4015 { 4016 mask = Gtk::gdk_rectangle( x, y+gap.x(), gap.height(), gap.width() ); 4017 break; 4018 } 4019 4020 case GTK_POS_RIGHT: 4021 { 4022 mask = Gtk::gdk_rectangle( x + w - gap.height(), y+gap.x(), gap.height(), gap.width() ); 4023 break; 4024 } 4025 4026 default: return; 4027 } 4028 4029 if( false ) 4030 { 4031 cairo_set_source( context, ColorUtils::Rgba( 1, 0, 0, 0.3 ) ); 4032 gdk_cairo_rectangle( context, &mask ); 4033 cairo_fill( context ); 4034 } 4035 4036 cairo_rectangle( context, x, y, w, h ); 4037 cairo_rectangle_negative( context, mask.x, mask.y, mask.width, mask.height ); 4038 cairo_clip( context ); 4039 4040 return; 4041 4042 } 4043 4044 //_________________________________________________________ fileChanged(GFileMonitor *,GFile * file,GFile *,GFileMonitorEvent event,gpointer data)4045 void Style::fileChanged( GFileMonitor*, GFile* file, GFile*, GFileMonitorEvent event, gpointer data ) 4046 { 4047 4048 #if OXYGEN_DEBUG 4049 std::cerr << "Oxygen::Style::fileChanged -" 4050 << " file: " << g_file_get_path( file ) 4051 << " event: " << Gtk::TypeNames::fileMonitorEvent( event ) 4052 << std::endl; 4053 #endif 4054 4055 Style& style( *static_cast<Style*>( data ) ); 4056 if( style.initialize( QtSettings::All|QtSettings::Forced ) ) 4057 { gtk_rc_reset_styles( gtk_settings_get_default() ); } 4058 4059 } 4060 4061 //_______________________________________________________________________ renderTabCloseIcon(cairo_t * context,GdkRectangle * r) const4062 void Style::renderTabCloseIcon(cairo_t* context, GdkRectangle* r) const 4063 { 4064 cairo_save(context); 4065 cairo_translate(context,r->x,r->y); 4066 4067 cairo_move_to( context, 5.5, 5.5 ); cairo_line_to( context, 10.5, 10.5 ); 4068 cairo_move_to( context, 10.5, 5.5 ); cairo_line_to( context, 5.5, 10.5 ); 4069 cairo_stroke( context ); 4070 4071 cairo_restore(context); 4072 } 4073 4074 //_______________________________________________________________________________ renderTabCloseButton(cairo_t * context,GdkRectangle * r,const ColorUtils::Rgba & base,const ColorUtils::Rgba & color)4075 void Style::renderTabCloseButton(cairo_t* context, GdkRectangle* r, const ColorUtils::Rgba& base, const ColorUtils::Rgba& color) 4076 { 4077 cairo_save(context); 4078 4079 cairo_set_source_surface(context,_helper.dockWidgetButton(base,true,r->width),0,0); 4080 cairo_rectangle(context,r->x,r->y,r->width,r->height); 4081 cairo_fill(context); 4082 4083 const double width(1.1); 4084 4085 // contrast 4086 cairo_translate(context,0,0.5); 4087 cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND ); 4088 cairo_set_line_join( context, CAIRO_LINE_JOIN_ROUND ); 4089 cairo_set_line_width(context,width); 4090 cairo_set_source(context,ColorUtils::lightColor( base )); 4091 4092 renderTabCloseIcon(context,r); 4093 4094 // main icon painting 4095 cairo_translate(context,0,-1); 4096 cairo_set_source(context,color); 4097 4098 renderTabCloseIcon(context,r); 4099 4100 cairo_restore(context); 4101 } 4102 4103 //_________________________________________________________ setWindowBlur(GdkWindow * window,bool enable)4104 void Style::setWindowBlur(GdkWindow* window,bool enable) 4105 { 4106 4107 #ifdef GDK_WINDOWING_X11 4108 4109 // Make whole window blurred 4110 // FIXME: should roundedness be taken into account? 4111 #if GTK_CHECK_VERSION(2,24,0) 4112 const int w( gdk_window_get_width( window ) ); 4113 const int h( gdk_window_get_height( window ) ); 4114 GdkDisplay* gdkDisplay = gdk_window_get_display( window ); 4115 #else 4116 int w(0), h(0); 4117 gdk_drawable_get_size( window, &w, &h ); 4118 GdkDisplay* gdkDisplay = gdk_drawable_get_display( window ); 4119 #endif 4120 4121 const unsigned long rects[4] = { 0, 0, (unsigned long)w, (unsigned long)h }; 4122 const XID id( GDK_WINDOW_XID( window ) ); 4123 Display* display( GDK_DISPLAY_XDISPLAY( gdkDisplay ) ); 4124 4125 if(enable) 4126 { 4127 4128 XChangeProperty( display, id, _blurAtom, XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<const unsigned char*>(rects), 4 ); 4129 4130 } else XDeleteProperty( display, id, _blurAtom ); 4131 4132 #endif 4133 4134 } 4135 4136 } 4137