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