1/* 2 * Copyright 2001-2014 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan A��mus, superstippi@gmx.de 7 * DarkWyrm, bpmagic@columbus.rr.com 8 * John Scipione, jscipione@gmail.com 9 * Clemens Zeidler, haiku@clemens-zeidler.de 10 */ 11 12 13/*! Decorator resembling BeOS R5 */ 14 15 16#include "BeDecorator.h" 17 18#include <algorithm> 19#include <cmath> 20#include <new> 21#include <stdio.h> 22 23#include <WindowPrivate.h> 24 25#include <Autolock.h> 26#include <Debug.h> 27#include <GradientLinear.h> 28#include <Rect.h> 29#include <Region.h> 30#include <View.h> 31 32#include "BitmapDrawingEngine.h" 33#include "Desktop.h" 34#include "DesktopSettings.h" 35#include "DrawingEngine.h" 36#include "DrawState.h" 37#include "FontManager.h" 38#include "PatternHandler.h" 39#include "RGBColor.h" 40#include "ServerBitmap.h" 41 42 43//#define DEBUG_DECORATOR 44#ifdef DEBUG_DECORATOR 45# define STRACE(x) printf x 46#else 47# define STRACE(x) ; 48#endif 49 50 51static const float kBorderResizeLength = 22.0; 52static const float kResizeKnobSize = 18.0; 53 54 55static const unsigned char f = 0xff; // way to write 0xff shorter 56 57static const unsigned char kInnerShadowBits[] = { 58 f, f, f, f, f, f, f, f, f, 0, 59 f, f, f, f, f, f, 0, f, 0, f, 60 f, f, f, f, f, 0, f, 0, f, 0, 61 f, f, f, f, 0, f, 0, 0, 0, 0, 62 f, f, f, 0, f, 0, 0, 0, 0, 0, 63 f, f, 0, f, 0, 0, 0, 0, 0, 0, 64 f, 0, f, 0, 0, 0, 0, 0, 0, 0, 65 f, f, 0, 0, 0, 0, 0, 0, 0, 0, 66 f, 0, f, 0, 0, 0, 0, 0, 0, 0, 67 0, f, 0, 0, 0, 0, 0, 0, 0, 0 68}; 69 70static const unsigned char kOuterShadowBits[] = { 71 f, f, f, f, f, f, f, f, f, f, 72 f, f, f, f, f, f, f, f, f, f, 73 f, f, f, f, f, f, f, f, f, f, 74 f, f, f, f, f, f, f, f, f, f, 75 f, f, f, f, f, f, f, f, f, 0, 76 f, f, f, f, f, f, f, 0, 0, 0, 77 f, f, f, f, f, f, 0, f, 0, 0, 78 f, f, f, f, f, 0, f, 0, 0, 0, 79 f, f, f, f, f, 0, 0, 0, 0, 0, 80 f, f, f, f, 0, 0, 0, 0, 0, 0 81}; 82 83static const unsigned char kBigInnerShadowBits[] = { 84 f, f, f, f, f, f, f, 85 f, f, f, f, f, f, 0, 86 f, f, f, f, f, 0, 0, 87 f, f, f, f, 0, f, 0, 88 f, f, f, 0, f, 0, 0, 89 f, f, 0, f, 0, 0, 0, 90 f, 0, 0, 0, 0, 0, 0 91}; 92 93static const unsigned char kBigOuterShadowBits[] = { 94 f, f, f, f, f, f, f, 95 f, f, f, f, f, f, 0, 96 f, f, f, f, f, f, 0, 97 f, f, f, f, f, f, 0, 98 f, f, f, f, f, f, 0, 99 f, f, f, f, f, f, 0, 100 f, 0, 0, 0, 0, 0, 0 101}; 102 103static const unsigned char kSmallInnerShadowBits[] = { 104 f, f, f, 0, 0, 105 f, f, 0, f, 0, 106 f, 0, f, 0, 0, 107 0, f, 0, 0, 0, 108 0, 0, 0, 0, 0 109}; 110 111static const unsigned char kSmallOuterShadowBits[] = { 112 f, f, f, f, f, 113 f, f, f, f, f, 114 f, f, f, f, f, 115 f, f, f, f, 0, 116 f, f, 0, 0, 0 117}; 118 119static const unsigned char kGlintBits[] = { 120 0, f, 0, 121 f, 0, f, 122 0, f, f 123}; 124 125 126// #pragma mark - BeDecorAddOn 127 128 129BeDecorAddOn::BeDecorAddOn(image_id id, const char* name) 130 : 131 DecorAddOn(id, name) 132{ 133} 134 135 136Decorator* 137BeDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect, 138 Desktop* desktop) 139{ 140 return new (std::nothrow)BeDecorator(settings, rect, desktop); 141} 142 143 144// #pragma mark - BeDecorator 145 146 147// TODO: get rid of DesktopSettings here, and introduce private accessor 148// methods to the Decorator base class 149BeDecorator::BeDecorator(DesktopSettings& settings, BRect rect, 150 Desktop* desktop) 151 : 152 SATDecorator(settings, rect, desktop), 153 fCStatus(B_NO_INIT) 154{ 155 STRACE(("BeDecorator:\n")); 156 STRACE(("\tFrame (%.1f,%.1f,%.1f,%.1f)\n", 157 rect.left, rect.top, rect.right, rect.bottom)); 158 159 fCloseBitmap = _CreateTemporaryBitmap(BRect(0, 0, 9, 9)); 160 fBigZoomBitmap = _CreateTemporaryBitmap(BRect(0, 0, 6, 6)); 161 fSmallZoomBitmap = _CreateTemporaryBitmap(BRect(0, 0, 4, 4)); 162 fGlintBitmap = _CreateTemporaryBitmap(BRect(0, 0, 2, 2)); 163 // glint bitmap is used by close and zoom buttons 164 165 if (fCloseBitmap == NULL || fBigZoomBitmap == NULL 166 || fSmallZoomBitmap == NULL || fGlintBitmap == NULL) { 167 fCStatus = B_NO_MEMORY; 168 } else 169 fCStatus = B_OK; 170} 171 172 173BeDecorator::~BeDecorator() 174{ 175 STRACE(("BeDecorator: ~BeDecorator()\n")); 176 //delete[] fFrameColors; 177 178 if (fCloseBitmap != NULL) 179 fCloseBitmap->ReleaseReference(); 180 181 if (fBigZoomBitmap != NULL) 182 fBigZoomBitmap->ReleaseReference(); 183 184 if (fSmallZoomBitmap != NULL) 185 fSmallZoomBitmap->ReleaseReference(); 186 187 if (fGlintBitmap != NULL) 188 fGlintBitmap->ReleaseReference(); 189} 190 191 192// #pragma mark - Public methods 193 194 195/*! Returns the frame colors for the specified decorator component. 196 197 The meaning of the color array elements depends on the specified component. 198 For some components some array elements are unused. 199 200 \param component The component for which to return the frame colors. 201 \param highlight The highlight set for the component. 202 \param colors An array of colors to be initialized by the function. 203*/ 204void 205BeDecorator::GetComponentColors(Component component, uint8 highlight, 206 ComponentColors _colors, Decorator::Tab* _tab) 207{ 208 Decorator::Tab* tab = static_cast<Decorator::Tab*>(_tab); 209 switch (component) { 210 case COMPONENT_TAB: 211 if (highlight == HIGHLIGHT_STACK_AND_TILE) { 212 _colors[COLOR_TAB_FRAME_LIGHT] 213 = tint_color(fFocusFrameColor, B_DARKEN_3_TINT); 214 _colors[COLOR_TAB_FRAME_DARK] 215 = tint_color(fFocusFrameColor, B_DARKEN_4_TINT); 216 _colors[COLOR_TAB] = tint_color(fFocusTabColor, 217 B_DARKEN_1_TINT); 218 _colors[COLOR_TAB_LIGHT] = tint_color(fFocusTabColorLight, 219 B_DARKEN_1_TINT); 220 _colors[COLOR_TAB_BEVEL] = fFocusTabColorBevel; 221 _colors[COLOR_TAB_SHADOW] = fFocusTabColorShadow; 222 _colors[COLOR_TAB_TEXT] = fFocusTextColor; 223 } else if (tab && tab->buttonFocus) { 224 _colors[COLOR_TAB_FRAME_LIGHT] 225 = tint_color(fFocusFrameColor, B_DARKEN_2_TINT); 226 _colors[COLOR_TAB_FRAME_DARK] 227 = tint_color(fFocusFrameColor, B_DARKEN_3_TINT); 228 _colors[COLOR_TAB] = fFocusTabColor; 229 _colors[COLOR_TAB_LIGHT] = fFocusTabColorLight; 230 _colors[COLOR_TAB_BEVEL] = fFocusTabColorBevel; 231 _colors[COLOR_TAB_SHADOW] = fFocusTabColorShadow; 232 _colors[COLOR_TAB_TEXT] = fFocusTextColor; 233 } else { 234 _colors[COLOR_TAB_FRAME_LIGHT] 235 = tint_color(fNonFocusFrameColor, B_DARKEN_2_TINT); 236 _colors[COLOR_TAB_FRAME_DARK] 237 = tint_color(fNonFocusFrameColor, B_DARKEN_3_TINT); 238 _colors[COLOR_TAB] = fNonFocusTabColor; 239 _colors[COLOR_TAB_LIGHT] = fNonFocusTabColorLight; 240 _colors[COLOR_TAB_BEVEL] = fNonFocusTabColorBevel; 241 _colors[COLOR_TAB_SHADOW] = fNonFocusTabColorShadow; 242 _colors[COLOR_TAB_TEXT] = fNonFocusTextColor; 243 } 244 break; 245 246 case COMPONENT_CLOSE_BUTTON: 247 case COMPONENT_ZOOM_BUTTON: 248 if (highlight == HIGHLIGHT_STACK_AND_TILE) { 249 _colors[COLOR_BUTTON] = tint_color(fFocusTabColor, 250 B_DARKEN_1_TINT); 251 _colors[COLOR_BUTTON_LIGHT] = tint_color(fFocusTabColorLight, 252 B_DARKEN_1_TINT); 253 } else if (tab && tab->buttonFocus) { 254 _colors[COLOR_BUTTON] = fFocusTabColor; 255 _colors[COLOR_BUTTON_LIGHT] = fFocusTabColorLight; 256 } else { 257 _colors[COLOR_BUTTON] = fNonFocusTabColor; 258 _colors[COLOR_BUTTON_LIGHT] = fNonFocusTabColorLight; 259 } 260 break; 261 262 case COMPONENT_LEFT_BORDER: 263 case COMPONENT_RIGHT_BORDER: 264 case COMPONENT_TOP_BORDER: 265 case COMPONENT_BOTTOM_BORDER: 266 case COMPONENT_RESIZE_CORNER: 267 default: 268 { 269 rgb_color base; 270 if (highlight == HIGHLIGHT_STACK_AND_TILE) 271 base = tint_color(fFocusFrameColor, B_DARKEN_3_TINT); 272 else if (tab && tab->buttonFocus) 273 base = fFocusFrameColor; 274 else 275 base = fNonFocusFrameColor; 276 277 //_colors[0].SetColor(152, 152, 152); 278 //_colors[1].SetColor(255, 255, 255); 279 //_colors[2].SetColor(216, 216, 216); 280 //_colors[3].SetColor(136, 136, 136); 281 //_colors[4].SetColor(152, 152, 152); 282 //_colors[5].SetColor(96, 96, 96); 283 284 _colors[0].red = std::max(0, base.red - 72); 285 _colors[0].green = std::max(0, base.green - 72); 286 _colors[0].blue = std::max(0, base.blue - 72); 287 _colors[0].alpha = 255; 288 289 _colors[1].red = std::min(255, base.red + 64); 290 _colors[1].green = std::min(255, base.green + 64); 291 _colors[1].blue = std::min(255, base.blue + 64); 292 _colors[1].alpha = 255; 293 294 _colors[2].red = std::max(0, base.red - 8); 295 _colors[2].green = std::max(0, base.green - 8); 296 _colors[2].blue = std::max(0, base.blue - 8); 297 _colors[2].alpha = 255; 298 299 _colors[3].red = std::max(0, base.red - 88); 300 _colors[3].green = std::max(0, base.green - 88); 301 _colors[3].blue = std::max(0, base.blue - 88); 302 _colors[3].alpha = 255; 303 304 _colors[4].red = std::max(0, base.red - 72); 305 _colors[4].green = std::max(0, base.green - 72); 306 _colors[4].blue = std::max(0, base.blue - 72); 307 _colors[4].alpha = 255; 308 309 _colors[5].red = std::max(0, base.red - 128); 310 _colors[5].green = std::max(0, base.green - 128); 311 _colors[5].blue = std::max(0, base.blue - 128); 312 _colors[5].alpha = 255; 313 314 // for the resize-border highlight dye everything bluish. 315 if (highlight == HIGHLIGHT_RESIZE_BORDER) { 316 for (int32 i = 0; i < 6; i++) { 317 _colors[i].red = std::max((int)_colors[i].red - 80, 0); 318 _colors[i].green = std::max((int)_colors[i].green - 80, 0); 319 _colors[i].blue = 255; 320 } 321 } 322 break; 323 } 324 } 325} 326 327 328// #pragma mark - Protected methods 329 330 331void 332BeDecorator::_DrawFrame(BRect invalid) 333{ 334 STRACE(("_DrawFrame(%f,%f,%f,%f)\n", invalid.left, invalid.top, 335 invalid.right, invalid.bottom)); 336 337 // NOTE: the DrawingEngine needs to be locked for the entire 338 // time for the clipping to stay valid for this decorator 339 340 if (fTopTab->look == B_NO_BORDER_WINDOW_LOOK) 341 return; 342 343 if (fBorderWidth <= 0) 344 return; 345 346 // Draw the border frame 347 BRect r = BRect(fTopBorder.LeftTop(), fBottomBorder.RightBottom()); 348 switch ((int)fTopTab->look) { 349 case B_TITLED_WINDOW_LOOK: 350 case B_DOCUMENT_WINDOW_LOOK: 351 case B_MODAL_WINDOW_LOOK: 352 { 353 // top 354 if (invalid.Intersects(fTopBorder)) { 355 ComponentColors colors; 356 _GetComponentColors(COMPONENT_TOP_BORDER, colors, fTopTab); 357 358 for (int8 i = 0; i < 5; i++) { 359 fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i), 360 BPoint(r.right - i, r.top + i), colors[i]); 361 } 362 if (fTitleBarRect.IsValid()) { 363 // grey along the bottom of the tab 364 // (overwrites "white" from frame) 365 fDrawingEngine->StrokeLine( 366 BPoint(fTitleBarRect.left + 2, 367 fTitleBarRect.bottom + 1), 368 BPoint(fTitleBarRect.right - 2, 369 fTitleBarRect.bottom + 1), 370 colors[2]); 371 } 372 } 373 // left 374 if (invalid.Intersects(fLeftBorder.InsetByCopy(0, -fBorderWidth))) { 375 ComponentColors colors; 376 _GetComponentColors(COMPONENT_LEFT_BORDER, colors, fTopTab); 377 378 for (int8 i = 0; i < 5; i++) { 379 fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i), 380 BPoint(r.left + i, r.bottom - i), colors[i]); 381 } 382 } 383 // bottom 384 if (invalid.Intersects(fBottomBorder)) { 385 ComponentColors colors; 386 _GetComponentColors(COMPONENT_BOTTOM_BORDER, colors, fTopTab); 387 388 for (int8 i = 0; i < 5; i++) { 389 fDrawingEngine->StrokeLine(BPoint(r.left + i, r.bottom - i), 390 BPoint(r.right - i, r.bottom - i), 391 colors[(4 - i) == 4 ? 5 : (4 - i)]); 392 } 393 } 394 // right 395 if (invalid.Intersects( 396 fRightBorder.InsetByCopy(0, -fBorderWidth))) { 397 ComponentColors colors; 398 _GetComponentColors(COMPONENT_RIGHT_BORDER, colors, fTopTab); 399 400 for (int8 i = 0; i < 5; i++) { 401 fDrawingEngine->StrokeLine(BPoint(r.right - i, r.top + i), 402 BPoint(r.right - i, r.bottom - i), 403 colors[(4 - i) == 4 ? 5 : (4 - i)]); 404 } 405 } 406 break; 407 } 408 409 case B_FLOATING_WINDOW_LOOK: 410 case kLeftTitledWindowLook: 411 { 412 // top 413 if (invalid.Intersects(fTopBorder)) { 414 ComponentColors colors; 415 _GetComponentColors(COMPONENT_TOP_BORDER, colors, fTopTab); 416 417 for (int8 i = 0; i < 3; i++) { 418 fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i), 419 BPoint(r.right - i, r.top + i), colors[i * 2]); 420 } 421 if (fTitleBarRect.IsValid() 422 && fTopTab->look != kLeftTitledWindowLook) { 423 // grey along the bottom of the tab 424 // (overwrites "white" from frame) 425 fDrawingEngine->StrokeLine( 426 BPoint(fTitleBarRect.left + 2, 427 fTitleBarRect.bottom + 1), 428 BPoint(fTitleBarRect.right - 2, 429 fTitleBarRect.bottom + 1), colors[2]); 430 } 431 } 432 // left 433 if (invalid.Intersects(fLeftBorder.InsetByCopy(0, -fBorderWidth))) { 434 ComponentColors colors; 435 _GetComponentColors(COMPONENT_LEFT_BORDER, colors, fTopTab); 436 437 for (int8 i = 0; i < 3; i++) { 438 fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i), 439 BPoint(r.left + i, r.bottom - i), colors[i * 2]); 440 } 441 if (fTopTab->look == kLeftTitledWindowLook 442 && fTitleBarRect.IsValid()) { 443 // grey along the right side of the tab 444 // (overwrites "white" from frame) 445 fDrawingEngine->StrokeLine( 446 BPoint(fTitleBarRect.right + 1, 447 fTitleBarRect.top + 2), 448 BPoint(fTitleBarRect.right + 1, 449 fTitleBarRect.bottom - 2), colors[2]); 450 } 451 } 452 // bottom 453 if (invalid.Intersects(fBottomBorder)) { 454 ComponentColors colors; 455 _GetComponentColors(COMPONENT_BOTTOM_BORDER, colors, fTopTab); 456 457 for (int8 i = 0; i < 3; i++) { 458 fDrawingEngine->StrokeLine(BPoint(r.left + i, r.bottom - i), 459 BPoint(r.right - i, r.bottom - i), 460 colors[(2 - i) == 2 ? 5 : (2 - i) * 2]); 461 } 462 } 463 // right 464 if (invalid.Intersects(fRightBorder.InsetByCopy(0, -fBorderWidth))) { 465 ComponentColors colors; 466 _GetComponentColors(COMPONENT_RIGHT_BORDER, colors, fTopTab); 467 468 for (int8 i = 0; i < 3; i++) { 469 fDrawingEngine->StrokeLine(BPoint(r.right - i, r.top + i), 470 BPoint(r.right - i, r.bottom - i), 471 colors[(2 - i) == 2 ? 5 : (2 - i) * 2]); 472 } 473 } 474 break; 475 } 476 477 case B_BORDERED_WINDOW_LOOK: 478 { 479 // TODO: Draw the borders individually! 480 ComponentColors colors; 481 _GetComponentColors(COMPONENT_LEFT_BORDER, colors, fTopTab); 482 483 fDrawingEngine->StrokeRect(r, colors[5]); 484 break; 485 } 486 487 default: 488 // don't draw a border frame 489 break; 490 } 491 492 // Draw the resize knob if we're supposed to 493 if (!(fTopTab->flags & B_NOT_RESIZABLE)) { 494 r = fResizeRect; 495 496 ComponentColors colors; 497 _GetComponentColors(COMPONENT_RESIZE_CORNER, colors, fTopTab); 498 499 switch ((int)fTopTab->look) { 500 case B_DOCUMENT_WINDOW_LOOK: 501 { 502 if (!invalid.Intersects(r)) 503 break; 504 505 float x = r.right - 3; 506 float y = r.bottom - 3; 507 508 BRect bg(x - 13, y - 13, x, y); 509 510 BGradientLinear gradient; 511 gradient.SetStart(bg.LeftTop()); 512 gradient.SetEnd(bg.RightBottom()); 513 gradient.AddColor(colors[1], 0); 514 gradient.AddColor(colors[2], 255); 515 516 fDrawingEngine->FillRect(bg, gradient); 517 518 fDrawingEngine->StrokeLine(BPoint(x - 15, y - 15), 519 BPoint(x - 15, y - 2), colors[0]); 520 fDrawingEngine->StrokeLine(BPoint(x - 14, y - 14), 521 BPoint(x - 14, y - 1), colors[1]); 522 fDrawingEngine->StrokeLine(BPoint(x - 15, y - 15), 523 BPoint(x - 2, y - 15), colors[0]); 524 fDrawingEngine->StrokeLine(BPoint(x - 14, y - 14), 525 BPoint(x - 1, y - 14), colors[1]); 526 527 if (fTopTab && !IsFocus(fTopTab)) 528 break; 529 530 static const rgb_color kWhite 531 = (rgb_color){ 255, 255, 255, 255 }; 532 for (int8 i = 1; i <= 4; i++) { 533 for (int8 j = 1; j <= i; j++) { 534 BPoint pt1(x - (3 * j) + 1, y - (3 * (5 - i)) + 1); 535 BPoint pt2(x - (3 * j) + 2, y - (3 * (5 - i)) + 2); 536 fDrawingEngine->StrokePoint(pt1, colors[0]); 537 fDrawingEngine->StrokePoint(pt2, kWhite); 538 } 539 } 540 break; 541 } 542 543 case B_TITLED_WINDOW_LOOK: 544 case B_FLOATING_WINDOW_LOOK: 545 case B_MODAL_WINDOW_LOOK: 546 case kLeftTitledWindowLook: 547 { 548 if (!invalid.Intersects(BRect(fRightBorder.right 549 - kBorderResizeLength, 550 fBottomBorder.bottom - kBorderResizeLength, 551 fRightBorder.right - 1, fBottomBorder.bottom - 1))) { 552 break; 553 } 554 555 fDrawingEngine->StrokeLine(BPoint(fRightBorder.left, 556 fBottomBorder.bottom - kBorderResizeLength), 557 BPoint(fRightBorder.right - 1, 558 fBottomBorder.bottom - kBorderResizeLength), 559 colors[0]); 560 fDrawingEngine->StrokeLine( 561 BPoint(fRightBorder.right - kBorderResizeLength, 562 fBottomBorder.top), 563 BPoint(fRightBorder.right - kBorderResizeLength, 564 fBottomBorder.bottom - 1), 565 colors[0]); 566 break; 567 } 568 569 default: 570 // don't draw resize corner 571 break; 572 } 573 } 574} 575 576 577/*! \brief Actually draws the tab 578 579 This function is called when the tab itself needs drawn. Other items, 580 like the window title or buttons, should not be drawn here. 581 582 \param tab The \a tab to update. 583 \param invalid The area of the \a tab to update. 584*/ 585void 586BeDecorator::_DrawTab(Decorator::Tab* tab, BRect invalid) 587{ 588 STRACE(("_DrawTab(%.1f, %.1f, %.1f, %.1f)\n", 589 invalid.left, invalid.top, invalid.right, invalid.bottom)); 590 const BRect& tabRect = tab->tabRect; 591 // If a window has a tab, this will draw it and any buttons which are 592 // in it. 593 if (!tabRect.IsValid() || !invalid.Intersects(tabRect)) 594 return; 595 596 ComponentColors colors; 597 _GetComponentColors(COMPONENT_TAB, colors, tab); 598 599 // outer frame 600 fDrawingEngine->StrokeLine(tabRect.LeftTop(), tabRect.LeftBottom(), 601 colors[COLOR_TAB_FRAME_LIGHT]); 602 fDrawingEngine->StrokeLine(tabRect.LeftTop(), tabRect.RightTop(), 603 colors[COLOR_TAB_FRAME_LIGHT]); 604 if (tab->look != kLeftTitledWindowLook) { 605 fDrawingEngine->StrokeLine(tabRect.RightTop(), tabRect.RightBottom(), 606 colors[COLOR_TAB_FRAME_DARK]); 607 } else { 608 fDrawingEngine->StrokeLine(tabRect.LeftBottom(), 609 tabRect.RightBottom(), colors[COLOR_TAB_FRAME_DARK]); 610 } 611 612 float tabBotton = tabRect.bottom; 613 if (fTopTab != tab) 614 tabBotton -= 1; 615 616 // bevel 617 fDrawingEngine->StrokeLine(BPoint(tabRect.left + 1, tabRect.top + 1), 618 BPoint(tabRect.left + 1, 619 tabBotton - (tab->look == kLeftTitledWindowLook ? 1 : 0)), 620 colors[COLOR_TAB_BEVEL]); 621 fDrawingEngine->StrokeLine(BPoint(tabRect.left + 1, tabRect.top + 1), 622 BPoint(tabRect.right - (tab->look == kLeftTitledWindowLook ? 0 : 1), 623 tabRect.top + 1), 624 colors[COLOR_TAB_BEVEL]); 625 626 if (tab->look != kLeftTitledWindowLook) { 627 fDrawingEngine->StrokeLine(BPoint(tabRect.right - 1, tabRect.top + 2), 628 BPoint(tabRect.right - 1, tabBotton), 629 colors[COLOR_TAB_SHADOW]); 630 } else { 631 fDrawingEngine->StrokeLine( 632 BPoint(tabRect.left + 2, tabRect.bottom - 1), 633 BPoint(tabRect.right, tabRect.bottom - 1), 634 colors[COLOR_TAB_SHADOW]); 635 } 636 637 // fill 638 if (fTopTab->look != kLeftTitledWindowLook) { 639 fDrawingEngine->FillRect(BRect(tabRect.left + 2, tabRect.top + 2, 640 tabRect.right - 2, tabRect.bottom), colors[COLOR_TAB]); 641 } else { 642 fDrawingEngine->FillRect(BRect(tabRect.left + 2, tabRect.top + 2, 643 tabRect.right, tabRect.bottom - 2), colors[COLOR_TAB]); 644 } 645 646 _DrawTitle(tab, tabRect); 647 648 _DrawButtons(tab, invalid); 649} 650 651 652/*! \brief Actually draws the title 653 654 The main tasks for this function are to ensure that the decorator draws 655 the title only in its own area and drawing the title itself. 656 Using B_OP_COPY for drawing the title is recommended because of the marked 657 performance hit of the other drawing modes, but it is not a requirement. 658 659 \param _tab The \a tab to update. 660 \param r area of the title to update. 661*/ 662void 663BeDecorator::_DrawTitle(Decorator::Tab* _tab, BRect r) 664{ 665 STRACE(("_DrawTitle(%f, %f, %f, %f)\n", r.left, r.top, r.right, r.bottom)); 666 667 Decorator::Tab* tab = static_cast<Decorator::Tab*>(_tab); 668 669 const BRect& tabRect = tab->tabRect; 670 const BRect& closeRect = tab->closeRect; 671 const BRect& zoomRect = tab->zoomRect; 672 673 ComponentColors colors; 674 _GetComponentColors(COMPONENT_TAB, colors, tab); 675 676 fDrawingEngine->SetDrawingMode(B_OP_OVER); 677 fDrawingEngine->SetHighColor(colors[COLOR_TAB_TEXT]); 678 fDrawingEngine->SetLowColor(colors[COLOR_TAB]); 679 fDrawingEngine->SetFont(fDrawState.Font()); 680 681 // figure out position of text 682 font_height fontHeight; 683 fDrawState.Font().GetHeight(fontHeight); 684 685 BPoint titlePos; 686 if (fTopTab->look != kLeftTitledWindowLook) { 687 titlePos.x = closeRect.IsValid() ? closeRect.right + tab->textOffset 688 : tabRect.left + tab->textOffset; 689 titlePos.y = floorf(((tabRect.top + 2.0) + tabRect.bottom 690 + fontHeight.ascent + fontHeight.descent) / 2.0 691 - fontHeight.descent + 0.5); 692 } else { 693 titlePos.x = floorf(((tabRect.left + 2.0) + tabRect.right 694 + fontHeight.ascent + fontHeight.descent) / 2.0 695 - fontHeight.descent + 0.5); 696 titlePos.y = zoomRect.IsValid() ? zoomRect.top - tab->textOffset 697 : tabRect.bottom - tab->textOffset; 698 } 699 700 fDrawingEngine->SetFont(fDrawState.Font()); 701 702 fDrawingEngine->DrawString(tab->truncatedTitle.String(), 703 tab->truncatedTitleLength, titlePos); 704 705 fDrawingEngine->SetDrawingMode(B_OP_COPY); 706} 707 708 709/*! \brief Actually draws the close button 710 711 Unless a subclass has a particularly large button, it is probably 712 unnecessary to check the update rectangle. 713 714 \param _tab The \a tab to update. 715 \param direct Draw without double buffering. 716 \param rect The area of the button to update. 717*/ 718void 719BeDecorator::_DrawClose(Decorator::Tab* _tab, bool direct, BRect rect) 720{ 721 STRACE(("_DrawClose(%f,%f,%f,%f)\n", rect.left, rect.top, rect.right, 722 rect.bottom)); 723 724 Decorator::Tab* tab = static_cast<Decorator::Tab*>(_tab); 725 726 int32 index = (tab->buttonFocus ? 0 : 1) + (tab->closePressed ? 0 : 2); 727 ServerBitmap* bitmap = tab->closeBitmaps[index]; 728 if (bitmap == NULL) { 729 bitmap = _GetBitmapForButton(tab, COMPONENT_CLOSE_BUTTON, 730 tab->closePressed, rect.IntegerWidth(), rect.IntegerHeight()); 731 tab->closeBitmaps[index] = bitmap; 732 } 733 734 _DrawButtonBitmap(bitmap, direct, rect); 735} 736 737 738/*! \brief Actually draws the zoom button 739 740 Unless a subclass has a particularly large button, it is probably 741 unnecessary to check the update rectangle. 742 743 \param _tab The \a tab to update. 744 \param direct Draw without double buffering. 745 \param rect The area of the button to update. 746*/ 747void 748BeDecorator::_DrawZoom(Decorator::Tab* _tab, bool direct, BRect rect) 749{ 750 STRACE(("_DrawZoom(%f,%f,%f,%f)\n", rect.left, rect.top, rect.right, 751 rect.bottom)); 752 753 if (rect.IntegerWidth() < 1) 754 return; 755 756 Decorator::Tab* tab = static_cast<Decorator::Tab*>(_tab); 757 int32 index = (tab->buttonFocus ? 0 : 1) + (tab->zoomPressed ? 0 : 2); 758 ServerBitmap* bitmap = tab->zoomBitmaps[index]; 759 if (bitmap == NULL) { 760 bitmap = _GetBitmapForButton(tab, COMPONENT_ZOOM_BUTTON, 761 tab->zoomPressed, rect.IntegerWidth(), rect.IntegerHeight()); 762 tab->zoomBitmaps[index] = bitmap; 763 } 764 765 _DrawButtonBitmap(bitmap, direct, rect); 766} 767 768 769void 770BeDecorator::_DrawMinimize(Decorator::Tab* tab, bool direct, BRect rect) 771{ 772 // This decorator doesn't have this button 773} 774 775 776void 777BeDecorator::_GetButtonSizeAndOffset(const BRect& tabRect, float* _offset, 778 float* _size, float* _inset) const 779{ 780 float tabSize = fTopTab->look == kLeftTitledWindowLook ? 781 tabRect.Width() : tabRect.Height(); 782 783 *_offset = 5.0f; 784 *_inset = 0.0f; 785 786 *_size = std::max(0.0f, tabSize - 7.0f); 787} 788 789 790// #pragma mark - Private methods 791 792 793/*! 794 \brief Draws a bevel around a rectangle. 795 \param rect The rectangular area to draw in. 796 \param down Whether or not the button is pressed down. 797 \param light The light color to use. 798 \param shadow The shadow color to use. 799*/ 800void 801BeDecorator::_DrawBevelRect(DrawingEngine* engine, const BRect rect, bool down, 802 rgb_color light, rgb_color shadow) 803{ 804 if (down) { 805 BRect inner(rect.InsetByCopy(1.0f, 1.0f)); 806 807 engine->StrokeLine(rect.LeftBottom(), rect.LeftTop(), shadow); 808 engine->StrokeLine(rect.LeftTop(), rect.RightTop(), shadow); 809 engine->StrokeLine(inner.LeftBottom(), inner.LeftTop(), shadow); 810 engine->StrokeLine(inner.LeftTop(), inner.RightTop(), shadow); 811 812 engine->StrokeLine(rect.RightTop(), rect.RightBottom(), light); 813 engine->StrokeLine(rect.RightBottom(), rect.LeftBottom(), light); 814 engine->StrokeLine(inner.RightTop(), inner.RightBottom(), light); 815 engine->StrokeLine(inner.RightBottom(), inner.LeftBottom(), light); 816 } else { 817 BRect r1(rect); 818 r1.left += 1.0f; 819 r1.top += 1.0f; 820 821 BRect r2(rect); 822 r2.bottom -= 1.0f; 823 r2.right -= 1.0f; 824 825 engine->StrokeRect(r2, shadow); 826 // inner dark box 827 engine->StrokeRect(rect, shadow); 828 // outer dark box 829 engine->StrokeRect(r1, light); 830 // light box 831 } 832} 833 834 835/*! 836 \brief Draws a framed rectangle with a gradient. 837 \param rect The rectangular area to draw in. 838 \param startColor The start color of the gradient. 839 \param endColor The end color of the gradient. 840*/ 841void 842BeDecorator::_DrawBlendedRect(DrawingEngine* engine, const BRect rect, 843 bool down, rgb_color colorA, rgb_color colorB, rgb_color colorC, 844 rgb_color colorD) 845{ 846 BRect fillRect(rect.InsetByCopy(1.0f, 1.0f)); 847 848 BGradientLinear gradient; 849 if (down) { 850 gradient.SetStart(fillRect.RightBottom()); 851 gradient.SetEnd(fillRect.LeftTop()); 852 } else { 853 gradient.SetStart(fillRect.LeftTop()); 854 gradient.SetEnd(fillRect.RightBottom()); 855 } 856 857 gradient.AddColor(colorA, 0); 858 gradient.AddColor(colorB, 95); 859 gradient.AddColor(colorC, 159); 860 gradient.AddColor(colorD, 255); 861 862 engine->FillRect(fillRect, gradient); 863} 864 865 866void 867BeDecorator::_DrawButtonBitmap(ServerBitmap* bitmap, bool direct, BRect rect) 868{ 869 if (bitmap == NULL) 870 return; 871 872 bool copyToFrontEnabled = fDrawingEngine->CopyToFrontEnabled(); 873 fDrawingEngine->SetCopyToFrontEnabled(direct); 874 drawing_mode oldMode; 875 fDrawingEngine->SetDrawingMode(B_OP_OVER, oldMode); 876 fDrawingEngine->DrawBitmap(bitmap, rect.OffsetToCopy(0, 0), rect); 877 fDrawingEngine->SetDrawingMode(oldMode); 878 fDrawingEngine->SetCopyToFrontEnabled(copyToFrontEnabled); 879} 880 881 882ServerBitmap* 883BeDecorator::_GetBitmapForButton(Decorator::Tab* tab, Component item, 884 bool down, int32 width, int32 height) 885{ 886 uint8* data; 887 size_t size; 888 size_t offset; 889 890 // TODO: the list of shared bitmaps is never freed 891 struct decorator_bitmap { 892 Component item; 893 bool down; 894 int32 width; 895 int32 height; 896 rgb_color baseColor; 897 rgb_color lightColor; 898 UtilityBitmap* bitmap; 899 decorator_bitmap* next; 900 }; 901 902 static BLocker sBitmapListLock("decorator lock", true); 903 static decorator_bitmap* sBitmapList = NULL; 904 905 // BeOS R5 colors 906 // button: active: 255, 203, 0 inactive: 232, 232, 232 907 // light1: active: 255, 238, 0 inactive: 255, 255, 255 908 // light2: active: 255, 255, 26 inactive: 255, 255, 255 909 // shadow1: active: 235, 183, 0 inactive: 211, 211, 211 910 // shadow2 is a bit lighter on zoom than on close button 911 912 ComponentColors colors; 913 _GetComponentColors(item, colors, tab); 914 915 const rgb_color buttonColor(colors[COLOR_BUTTON]); 916 917 bool isGrayscale = buttonColor.red == buttonColor.green 918 && buttonColor.green == buttonColor.blue; 919 920 rgb_color buttonColorLight1(buttonColor); 921 buttonColorLight1.red = std::min(255, buttonColor.red + 35), 922 buttonColorLight1.green = std::min(255, buttonColor.green + 35), 923 buttonColorLight1.blue = std::min(255, buttonColor.blue 924 + (isGrayscale ? 35 : 0)); 925 // greyscale color stays grayscale 926 927 rgb_color buttonColorLight2(buttonColor); 928 buttonColorLight2.red = std::min(255, buttonColor.red + 52), 929 buttonColorLight2.green = std::min(255, buttonColor.green + 52), 930 buttonColorLight2.blue = std::min(255, buttonColor.blue + 26); 931 932 rgb_color buttonColorShadow1(buttonColor); 933 buttonColorShadow1.red = std::max(0, buttonColor.red - 21), 934 buttonColorShadow1.green = std::max(0, buttonColor.green - 21), 935 buttonColorShadow1.blue = std::max(0, buttonColor.blue - 21); 936 937 BAutolock locker(sBitmapListLock); 938 939 // search our list for a matching bitmap 940 // TODO: use a hash map instead? 941 decorator_bitmap* current = sBitmapList; 942 while (current) { 943 if (current->item == item && current->down == down 944 && current->width == width && current->height == height 945 && current->baseColor == colors[COLOR_BUTTON] 946 && current->lightColor == colors[COLOR_BUTTON_LIGHT]) { 947 return current->bitmap; 948 } 949 950 current = current->next; 951 } 952 953 static BitmapDrawingEngine* sBitmapDrawingEngine = NULL; 954 955 // didn't find any bitmap, create a new one 956 if (sBitmapDrawingEngine == NULL) 957 sBitmapDrawingEngine = new(std::nothrow) BitmapDrawingEngine(); 958 if (sBitmapDrawingEngine == NULL 959 || sBitmapDrawingEngine->SetSize(width, height) != B_OK) { 960 return NULL; 961 } 962 963 BRect rect(0, 0, width - 1, height - 1); 964 965 STRACE(("BeDecorator creating bitmap for %s %s at size %ldx%ld\n", 966 item == COMPONENT_CLOSE_BUTTON ? "close" : "zoom", 967 down ? "down" : "up", width, height)); 968 switch (item) { 969 case COMPONENT_CLOSE_BUTTON: 970 { 971 // BeOS R5 shadow2: active: 183, 131, 0 inactive: 160, 160, 160 972 rgb_color buttonColorShadow2(buttonColor); 973 buttonColorShadow2.red = std::max(0, buttonColor.red - 72), 974 buttonColorShadow2.green = std::max(0, buttonColor.green - 72), 975 buttonColorShadow2.blue = std::max(0, buttonColor.blue - 72); 976 977 // fill the background 978 sBitmapDrawingEngine->FillRect(rect, buttonColor); 979 980 // draw outer bevel 981 _DrawBevelRect(sBitmapDrawingEngine, rect, tab->closePressed, 982 buttonColorLight2, buttonColorShadow2); 983 984 if (fCStatus != B_OK) { 985 // If we ran out of memory while initializing bitmaps 986 // fall back to a linear gradient. 987 rect.InsetBy(1, 1); 988 _DrawBlendedRect(sBitmapDrawingEngine, rect, tab->closePressed, 989 buttonColorLight2, buttonColorLight1, buttonColor, 990 buttonColorShadow1); 991 992 break; 993 } 994 995 // inset by bevel 996 rect.InsetBy(2, 2); 997 998 // fill bg 999 sBitmapDrawingEngine->FillRect(rect, buttonColorLight1); 1000 1001 // treat background color as transparent 1002 sBitmapDrawingEngine->SetDrawingMode(B_OP_OVER); 1003 sBitmapDrawingEngine->SetLowColor(buttonColorLight1); 1004 1005 if (tab->closePressed) { 1006 // Draw glint in bottom right, then combined inner and outer 1007 // shadow in top left. 1008 // Read the source bitmap in forward while writing the 1009 // destination in reverse to rotate the bitmap by 180��. 1010 1011 data = fGlintBitmap->Bits(); 1012 size = sizeof(kGlintBits); 1013 for (size_t i = 0; i < size; i++) { 1014 offset = (size - 1 - i) * 4; 1015 if (kGlintBits[i] == 0) { 1016 // draw glint color 1017 data[offset + 0] = buttonColorLight2.blue; 1018 data[offset + 1] = buttonColorLight2.green; 1019 data[offset + 2] = buttonColorLight2.red; 1020 } else { 1021 // draw background color 1022 data[offset + 0] = buttonColorLight1.blue; 1023 data[offset + 1] = buttonColorLight1.green; 1024 data[offset + 2] = buttonColorLight1.red; 1025 } 1026 } 1027 // glint is 3x3 1028 const BRect rightBottom(BRect(rect.right - 2, rect.bottom - 2, 1029 rect.right, rect.bottom)); 1030 sBitmapDrawingEngine->DrawBitmap(fGlintBitmap, 1031 fGlintBitmap->Bounds(), rightBottom); 1032 1033 data = fCloseBitmap->Bits(); 1034 size = sizeof(kOuterShadowBits); 1035 for (size_t i = 0; i < size; i++) { 1036 offset = (size - 1 - i) * 4; 1037 if (kOuterShadowBits[i] == 0) { 1038 // draw outer shadow 1039 data[offset + 0] = buttonColorShadow1.blue; 1040 data[offset + 1] = buttonColorShadow1.green; 1041 data[offset + 2] = buttonColorShadow1.red; 1042 } else if (kInnerShadowBits[i] == 0) { 1043 // draw inner shadow 1044 data[offset + 0] = buttonColor.blue; 1045 data[offset + 1] = buttonColor.green; 1046 data[offset + 2] = buttonColor.red; 1047 } else { 1048 // draw background color 1049 data[offset + 0] = buttonColorLight1.blue; 1050 data[offset + 1] = buttonColorLight1.green; 1051 data[offset + 2] = buttonColorLight1.red; 1052 } 1053 } 1054 // shadow is 10x10 1055 const BRect leftTop(rect.left, rect.top, 1056 rect.left + 9, rect.top + 9); 1057 sBitmapDrawingEngine->DrawBitmap(fCloseBitmap, 1058 fCloseBitmap->Bounds(), leftTop); 1059 } else { 1060 // draw glint, then draw combined outer and inner shadows 1061 1062 data = fGlintBitmap->Bits(); 1063 size = sizeof(kGlintBits); 1064 for (size_t i = 0; i < size; i++) { 1065 offset = i * 4 + 0; 1066 if (kGlintBits[i] == 0) { 1067 // draw glint color 1068 data[offset + 0] = buttonColorLight2.blue; 1069 data[offset + 1] = buttonColorLight2.green; 1070 data[offset + 2] = buttonColorLight2.red; 1071 } else { 1072 // draw background color 1073 data[offset + 0] = buttonColorLight1.blue; 1074 data[offset + 1] = buttonColorLight1.green; 1075 data[offset + 2] = buttonColorLight1.red; 1076 } 1077 } 1078 // glint is 3x3 1079 const BRect leftTop(rect.left, rect.top, 1080 rect.left + 2, rect.top + 2); 1081 sBitmapDrawingEngine->DrawBitmap(fGlintBitmap, 1082 fGlintBitmap->Bounds(), leftTop); 1083 1084 data = fCloseBitmap->Bits(); 1085 size = sizeof(kOuterShadowBits); 1086 for (size_t i = 0; i < size; i++) { 1087 offset = i * 4 + 0; 1088 if (kOuterShadowBits[i] == 0) { 1089 // draw outer shadow 1090 data[offset + 0] = buttonColorShadow1.blue; 1091 data[offset + 1] = buttonColorShadow1.green; 1092 data[offset + 2] = buttonColorShadow1.red; 1093 } else if (kInnerShadowBits[i] == 0) { 1094 // draw inner shadow 1095 data[offset + 0] = buttonColor.blue; 1096 data[offset + 1] = buttonColor.green; 1097 data[offset + 2] = buttonColor.red; 1098 } else { 1099 // draw background color 1100 data[offset + 0] = buttonColorLight1.blue; 1101 data[offset + 1] = buttonColorLight1.green; 1102 data[offset + 2] = buttonColorLight1.red; 1103 } 1104 } 1105 // shadow is 10x10 1106 const BRect rightBottom(BRect(rect.right - 9, rect.bottom - 9, 1107 rect.right, rect.bottom)); 1108 sBitmapDrawingEngine->DrawBitmap(fCloseBitmap, 1109 fCloseBitmap->Bounds(), rightBottom); 1110 } 1111 1112 // restore drawing mode 1113 sBitmapDrawingEngine->SetDrawingMode(B_OP_COPY); 1114 1115 break; 1116 } 1117 1118 case COMPONENT_ZOOM_BUTTON: 1119 { 1120 // BeOS R5 shadow2: active: 210, 158, 0 inactive: 187, 187, 187 1121 rgb_color buttonColorShadow2(buttonColor); 1122 buttonColorShadow2.red = std::max(0, buttonColor.red - 45), 1123 buttonColorShadow2.green = std::max(0, buttonColor.green - 45), 1124 buttonColorShadow2.blue = std::max(0, buttonColor.blue - 45); 1125 1126 // fill the background 1127 sBitmapDrawingEngine->FillRect(rect, buttonColor); 1128 1129 // big rect 1130 BRect bigRect(rect); 1131 bigRect.left += floorf(width * 3.0f / 14.0f); 1132 bigRect.top += floorf(height * 3.0f / 14.0f); 1133 1134 // small rect 1135 BRect smallRect(rect); 1136 smallRect.right -= floorf(width * 5.0f / 14.0f); 1137 smallRect.bottom -= floorf(height * 5.0f / 14.0f); 1138 1139 // draw big rect bevel 1140 _DrawBevelRect(sBitmapDrawingEngine, bigRect, tab->zoomPressed, 1141 buttonColorLight2, buttonColorShadow2); 1142 1143 if (fCStatus != B_OK) { 1144 // If we ran out of memory while initializing bitmaps 1145 // fall back to a linear gradient. 1146 1147 // already drew bigRect bevel, fill with linear gradient 1148 bigRect.InsetBy(1, 1); 1149 _DrawBlendedRect(sBitmapDrawingEngine, bigRect, 1150 tab->zoomPressed, buttonColorLight2, buttonColorLight1, 1151 buttonColor, buttonColorShadow1); 1152 1153 // draw small rect bevel then fill with linear gradient 1154 _DrawBevelRect(sBitmapDrawingEngine, smallRect, 1155 tab->zoomPressed, buttonColorLight2, buttonColorShadow2); 1156 if (!tab->zoomPressed) { 1157 // undraw bottom left and top right corners 1158 sBitmapDrawingEngine->StrokePoint(smallRect.LeftBottom(), 1159 buttonColor); 1160 sBitmapDrawingEngine->StrokePoint(smallRect.RightTop(), 1161 buttonColor); 1162 } 1163 smallRect.InsetBy(1, 1); 1164 _DrawBlendedRect(sBitmapDrawingEngine, smallRect, 1165 tab->zoomPressed, buttonColorLight2, buttonColorLight1, 1166 buttonColor, buttonColorShadow1); 1167 1168 break; 1169 } 1170 1171 // inset past bevel 1172 bigRect.InsetBy(2, 2); 1173 1174 // fill big rect bg 1175 sBitmapDrawingEngine->FillRect(bigRect, buttonColorLight1); 1176 1177 // some elements are covered by the small rect 1178 // so only draw the parts that get shown 1179 if (tab->zoomPressed) { 1180 // draw glint 1181 // Read the source bitmap in forward while writing the 1182 // destination in reverse to rotate the bitmap by 180��. 1183 data = fGlintBitmap->Bits(); 1184 size = sizeof(kGlintBits); 1185 for (size_t i = 0; i < sizeof(kGlintBits); i++) { 1186 offset = (size - 1 - i) * 4; 1187 if (kGlintBits[i] == 0) { 1188 // draw glint 1189 data[offset + 0] = buttonColorLight2.blue; 1190 data[offset + 1] = buttonColorLight2.green; 1191 data[offset + 2] = buttonColorLight2.red; 1192 } else { 1193 // draw background color 1194 data[offset + 0] = buttonColorLight1.blue; 1195 data[offset + 1] = buttonColorLight1.green; 1196 data[offset + 2] = buttonColorLight1.red; 1197 } 1198 } 1199 // glint is 3x3 1200 const BRect rightBottom(BRect(bigRect.right - 2, 1201 bigRect.bottom - 2, bigRect.right, bigRect.bottom)); 1202 sBitmapDrawingEngine->DrawBitmap(fGlintBitmap, 1203 fGlintBitmap->Bounds(), rightBottom); 1204 } else { 1205 // draw combined inner and outer shadow 1206 data = fBigZoomBitmap->Bits(); 1207 for (size_t i = 0; i < sizeof(kBigOuterShadowBits); i++) { 1208 offset = i * 4; 1209 if (kBigOuterShadowBits[i] == 0) { 1210 // draw outer shadow 1211 data[offset + 0] = buttonColorShadow1.blue; 1212 data[offset + 1] = buttonColorShadow1.green; 1213 data[offset + 2] = buttonColorShadow1.red; 1214 } else if (kBigInnerShadowBits[i] == 0) { 1215 // draw inner shadow 1216 data[offset + 0] = buttonColor.blue; 1217 data[offset + 1] = buttonColor.green; 1218 data[offset + 2] = buttonColor.red; 1219 } else { 1220 // draw background color 1221 data[offset + 0] = buttonColorLight1.blue; 1222 data[offset + 1] = buttonColorLight1.green; 1223 data[offset + 2] = buttonColorLight1.red; 1224 } 1225 } 1226 // shadow is 7x7 1227 const BRect rightBottom(BRect(bigRect.right - 6, 1228 bigRect.bottom - 6, bigRect.right, bigRect.bottom)); 1229 sBitmapDrawingEngine->DrawBitmap(fBigZoomBitmap, 1230 fBigZoomBitmap->Bounds(), rightBottom); 1231 } 1232 1233 sBitmapDrawingEngine->SetDrawingMode(B_OP_COPY); 1234 1235 // draw small rect bevel 1236 _DrawBevelRect(sBitmapDrawingEngine, smallRect, tab->zoomPressed, 1237 buttonColorLight2, buttonColorShadow2); 1238 1239 if (!tab->zoomPressed) { 1240 // undraw bottom left and top right corners 1241 sBitmapDrawingEngine->StrokePoint(smallRect.LeftBottom(), 1242 buttonColor); 1243 sBitmapDrawingEngine->StrokePoint(smallRect.RightTop(), 1244 buttonColor); 1245 } 1246 1247 // inset past bevel 1248 smallRect.InsetBy(2, 2); 1249 1250 // fill small rect bg 1251 sBitmapDrawingEngine->FillRect(smallRect, buttonColorLight1); 1252 1253 // treat background color as transparent 1254 sBitmapDrawingEngine->SetDrawingMode(B_OP_OVER); 1255 sBitmapDrawingEngine->SetLowColor(buttonColorLight1); 1256 1257 // draw small bitmap 1258 data = fSmallZoomBitmap->Bits(); 1259 size = sizeof(kSmallOuterShadowBits); 1260 if (tab->zoomPressed) { 1261 // draw combined inner and outer shadow 1262 // Read the source bitmap in forward while writing the 1263 // destination in reverse to rotate the bitmap by 180��. 1264 for (size_t i = 0; i < size; i++) { 1265 offset = (size - 1 - i) * 4; 1266 if (kSmallOuterShadowBits[i] == 0) { 1267 // draw outer shadow 1268 data[offset + 0] = buttonColorShadow1.blue; 1269 data[offset + 1] = buttonColorShadow1.green; 1270 data[offset + 2] = buttonColorShadow1.red; 1271 } else if (kSmallInnerShadowBits[i] == 0) { 1272 // draw inner shadow 1273 data[offset + 0] = buttonColor.blue; 1274 data[offset + 1] = buttonColor.green; 1275 data[offset + 2] = buttonColor.red; 1276 } else { 1277 // draw background color 1278 data[offset + 0] = buttonColorLight1.blue; 1279 data[offset + 1] = buttonColorLight1.green; 1280 data[offset + 2] = buttonColorLight1.red; 1281 } 1282 } 1283 // shadow is 5x5 1284 const BRect smallLeftTop(BRect(smallRect.left, 1285 smallRect.top, smallRect.left + 4, smallRect.top + 4)); 1286 sBitmapDrawingEngine->DrawBitmap(fSmallZoomBitmap, 1287 fSmallZoomBitmap->Bounds(), smallLeftTop); 1288 } else { 1289 // draw combined inner and outer shadow 1290 for (size_t i = 0; i < size; i++) { 1291 offset = i * 4; 1292 if (kSmallOuterShadowBits[i] == 0) { 1293 // draw outer shadow 1294 data[offset + 0] = buttonColorShadow1.blue; 1295 data[offset + 1] = buttonColorShadow1.green; 1296 data[offset + 2] = buttonColorShadow1.red; 1297 } else if (kSmallInnerShadowBits[i] == 0) { 1298 // draw inner shadow 1299 data[offset + 0] = buttonColor.blue; 1300 data[offset + 1] = buttonColor.green; 1301 data[offset + 2] = buttonColor.red; 1302 } else { 1303 // draw background color 1304 data[offset + 0] = buttonColorLight1.blue; 1305 data[offset + 1] = buttonColorLight1.green; 1306 data[offset + 2] = buttonColorLight1.red; 1307 } 1308 } 1309 // shadow is 5x5 1310 const BRect smallRightBottom(BRect(smallRect.right - 4, 1311 smallRect.bottom - 4, smallRect.right, smallRect.bottom)); 1312 sBitmapDrawingEngine->DrawBitmap(fSmallZoomBitmap, 1313 fSmallZoomBitmap->Bounds(), smallRightBottom); 1314 } 1315 1316 // draw glint last (single pixel) 1317 sBitmapDrawingEngine->StrokePoint(tab->zoomPressed 1318 ? smallRect.RightBottom() : smallRect.LeftTop(), 1319 buttonColorLight2); 1320 1321 // restore drawing mode 1322 sBitmapDrawingEngine->SetDrawingMode(B_OP_COPY); 1323 1324 break; 1325 } 1326 1327 default: 1328 break; 1329 } 1330 1331 UtilityBitmap* bitmap = sBitmapDrawingEngine->ExportToBitmap(width, height, 1332 B_RGB32); 1333 if (bitmap == NULL) 1334 return NULL; 1335 1336 // bitmap ready, put it into the list 1337 decorator_bitmap* entry = new(std::nothrow) decorator_bitmap; 1338 if (entry == NULL) { 1339 delete bitmap; 1340 return NULL; 1341 } 1342 1343 entry->item = item; 1344 entry->down = down; 1345 entry->width = width; 1346 entry->height = height; 1347 entry->bitmap = bitmap; 1348 entry->baseColor = colors[COLOR_BUTTON]; 1349 entry->lightColor = colors[COLOR_BUTTON_LIGHT]; 1350 entry->next = sBitmapList; 1351 sBitmapList = entry; 1352 return bitmap; 1353} 1354 1355 1356ServerBitmap* 1357BeDecorator::_CreateTemporaryBitmap(BRect bounds) const 1358{ 1359 UtilityBitmap* bitmap = new(std::nothrow) UtilityBitmap(bounds, 1360 B_RGB32, 0); 1361 if (bitmap == NULL) 1362 return NULL; 1363 1364 if (!bitmap->IsValid()) { 1365 delete bitmap; 1366 return NULL; 1367 } 1368 1369 memset(bitmap->Bits(), 0, bitmap->BitsLength()); 1370 // background opacity is 0 1371 1372 return bitmap; 1373} 1374 1375 1376void 1377BeDecorator::_GetComponentColors(Component component, 1378 ComponentColors _colors, Decorator::Tab* tab) 1379{ 1380 // get the highlight for our component 1381 Region region = REGION_NONE; 1382 switch (component) { 1383 case COMPONENT_TAB: 1384 region = REGION_TAB; 1385 break; 1386 case COMPONENT_CLOSE_BUTTON: 1387 region = REGION_CLOSE_BUTTON; 1388 break; 1389 case COMPONENT_ZOOM_BUTTON: 1390 region = REGION_ZOOM_BUTTON; 1391 break; 1392 case COMPONENT_LEFT_BORDER: 1393 region = REGION_LEFT_BORDER; 1394 break; 1395 case COMPONENT_RIGHT_BORDER: 1396 region = REGION_RIGHT_BORDER; 1397 break; 1398 case COMPONENT_TOP_BORDER: 1399 region = REGION_TOP_BORDER; 1400 break; 1401 case COMPONENT_BOTTOM_BORDER: 1402 region = REGION_BOTTOM_BORDER; 1403 break; 1404 case COMPONENT_RESIZE_CORNER: 1405 region = REGION_RIGHT_BOTTOM_CORNER; 1406 break; 1407 } 1408 1409 return GetComponentColors(component, RegionHighlight(region), _colors, tab); 1410} 1411 1412 1413extern "C" DecorAddOn* (instantiate_decor_addon)(image_id id, const char* name) 1414{ 1415 return new (std::nothrow)BeDecorAddOn(id, name); 1416} 1417