1 /* 2 * Copyright 2009, Stephan Aßmus <superstippi@gmx.de> 3 * Copyright 2012-2020 Haiku, Inc. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 * 6 * Authors: 7 * Stephan Aßmus, superstippi@gmx.de 8 * John Scipione, jscipione@gmail.com 9 */ 10 11 12 #include <HaikuControlLook.h> 13 14 #include <algorithm> 15 16 #include <Bitmap.h> 17 #include <Control.h> 18 #include <GradientLinear.h> 19 #include <LayoutUtils.h> 20 #include <Region.h> 21 #include <Shape.h> 22 #include <String.h> 23 #include <TabView.h> 24 #include <View.h> 25 #include <Window.h> 26 #include <WindowPrivate.h> 27 28 29 namespace BPrivate { 30 31 static const float kEdgeBevelLightTint = 0.59; 32 static const float kEdgeBevelShadowTint = 1.0735; 33 static const float kHoverTintFactor = 0.85; 34 35 static const int32 kButtonPopUpIndicatorWidth = B_USE_ITEM_SPACING; 36 37 38 HaikuControlLook::HaikuControlLook() 39 : 40 fCachedOutline(false) 41 { 42 } 43 44 45 HaikuControlLook::~HaikuControlLook() 46 { 47 } 48 49 50 BAlignment 51 HaikuControlLook::DefaultLabelAlignment() const 52 { 53 return BAlignment(B_ALIGN_LEFT, B_ALIGN_VERTICAL_CENTER); 54 } 55 56 57 float 58 HaikuControlLook::DefaultLabelSpacing() const 59 { 60 return ceilf(be_plain_font->Size() / 2.0); 61 } 62 63 64 float 65 HaikuControlLook::DefaultItemSpacing() const 66 { 67 return ceilf(be_plain_font->Size() * 0.85); 68 } 69 70 71 uint32 72 HaikuControlLook::Flags(BControl* control) const 73 { 74 uint32 flags = B_IS_CONTROL; 75 76 if (!control->IsEnabled()) 77 flags |= B_DISABLED; 78 79 if (control->IsFocus() && control->Window() != NULL 80 && control->Window()->IsActive()) { 81 flags |= B_FOCUSED; 82 } 83 84 switch (control->Value()) { 85 case B_CONTROL_ON: 86 flags |= B_ACTIVATED; 87 break; 88 case B_CONTROL_PARTIALLY_ON: 89 flags |= B_PARTIALLY_ACTIVATED; 90 break; 91 } 92 93 if (control->Parent() != NULL 94 && (control->Parent()->Flags() & B_DRAW_ON_CHILDREN) != 0) { 95 // In this constellation, assume we want to render the control 96 // against the already existing view contents of the parent view. 97 flags |= B_BLEND_FRAME; 98 } 99 100 return flags; 101 } 102 103 104 // #pragma mark - 105 106 107 void 108 HaikuControlLook::DrawButtonFrame(BView* view, BRect& rect, const BRect& updateRect, 109 const rgb_color& base, const rgb_color& background, uint32 flags, 110 uint32 borders) 111 { 112 _DrawButtonFrame(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f, base, 113 background, 1.0, 1.0, flags, borders); 114 } 115 116 117 void 118 HaikuControlLook::DrawButtonFrame(BView* view, BRect& rect, const BRect& updateRect, 119 float radius, const rgb_color& base, const rgb_color& background, uint32 flags, 120 uint32 borders) 121 { 122 _DrawButtonFrame(view, rect, updateRect, radius, radius, radius, radius, 123 base, background, 1.0, 1.0, flags, borders); 124 } 125 126 127 void 128 HaikuControlLook::DrawButtonFrame(BView* view, BRect& rect, 129 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 130 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 131 const rgb_color& background, uint32 flags, 132 uint32 borders) 133 { 134 _DrawButtonFrame(view, rect, updateRect, leftTopRadius, rightTopRadius, 135 leftBottomRadius, rightBottomRadius, base, background, 136 1.0, 1.0, flags, borders); 137 } 138 139 140 void 141 HaikuControlLook::DrawButtonBackground(BView* view, BRect& rect, 142 const BRect& updateRect, const rgb_color& base, uint32 flags, 143 uint32 borders, orientation orientation) 144 { 145 _DrawButtonBackground(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f, 146 base, false, flags, borders, orientation); 147 } 148 149 150 void 151 HaikuControlLook::DrawButtonBackground(BView* view, BRect& rect, 152 const BRect& updateRect, float radius, const rgb_color& base, uint32 flags, 153 uint32 borders, orientation orientation) 154 { 155 _DrawButtonBackground(view, rect, updateRect, radius, radius, radius, 156 radius, base, false, flags, borders, orientation); 157 } 158 159 160 void 161 HaikuControlLook::DrawButtonBackground(BView* view, BRect& rect, 162 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 163 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 164 uint32 flags, uint32 borders, orientation orientation) 165 { 166 _DrawButtonBackground(view, rect, updateRect, leftTopRadius, 167 rightTopRadius, leftBottomRadius, rightBottomRadius, base, false, flags, 168 borders, orientation); 169 } 170 171 172 void 173 HaikuControlLook::DrawMenuBarBackground(BView* view, BRect& rect, 174 const BRect& updateRect, const rgb_color& base, uint32 flags, 175 uint32 borders) 176 { 177 if (!ShouldDraw(view, rect, updateRect)) 178 return; 179 180 // the surface edges 181 182 // colors 183 float topTint; 184 float bottomTint; 185 186 if ((flags & B_ACTIVATED) != 0) { 187 rgb_color bevelColor1 = tint_color(base, 1.40); 188 rgb_color bevelColor2 = tint_color(base, 1.25); 189 190 topTint = 1.25; 191 bottomTint = 1.20; 192 193 _DrawFrame(view, rect, 194 bevelColor1, bevelColor1, 195 bevelColor2, bevelColor2, 196 borders & B_TOP_BORDER); 197 } else { 198 rgb_color cornerColor = tint_color(base, 0.9); 199 rgb_color bevelColorTop = tint_color(base, 0.5); 200 rgb_color bevelColorLeft = tint_color(base, 0.7); 201 rgb_color bevelColorRightBottom = tint_color(base, 1.08); 202 203 topTint = 0.69; 204 bottomTint = 1.03; 205 206 _DrawFrame(view, rect, 207 bevelColorLeft, bevelColorTop, 208 bevelColorRightBottom, bevelColorRightBottom, 209 cornerColor, cornerColor, 210 borders); 211 } 212 213 // draw surface top 214 _FillGradient(view, rect, base, topTint, bottomTint); 215 } 216 217 218 void 219 HaikuControlLook::DrawMenuFieldFrame(BView* view, BRect& rect, 220 const BRect& updateRect, const rgb_color& base, 221 const rgb_color& background, uint32 flags, uint32 borders) 222 { 223 _DrawButtonFrame(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f, base, 224 background, 0.6, 1.0, flags, borders); 225 } 226 227 228 void 229 HaikuControlLook::DrawMenuFieldFrame(BView* view, BRect& rect, 230 const BRect& updateRect, float radius, const rgb_color& base, 231 const rgb_color& background, uint32 flags, uint32 borders) 232 { 233 _DrawButtonFrame(view, rect, updateRect, radius, radius, radius, radius, 234 base, background, 0.6, 1.0, flags, borders); 235 } 236 237 238 void 239 HaikuControlLook::DrawMenuFieldFrame(BView* view, BRect& rect, 240 const BRect& updateRect, float leftTopRadius, 241 float rightTopRadius, float leftBottomRadius, 242 float rightBottomRadius, const rgb_color& base, 243 const rgb_color& background, uint32 flags, uint32 borders) 244 { 245 _DrawButtonFrame(view, rect, updateRect, leftTopRadius, rightTopRadius, 246 leftBottomRadius, rightBottomRadius, base, background, 0.6, 1.0, 247 flags, borders); 248 } 249 250 251 void 252 HaikuControlLook::DrawMenuFieldBackground(BView* view, BRect& rect, 253 const BRect& updateRect, const rgb_color& base, bool popupIndicator, 254 uint32 flags) 255 { 256 _DrawMenuFieldBackgroundOutside(view, rect, updateRect, 257 0.0f, 0.0f, 0.0f, 0.0f, base, popupIndicator, flags); 258 } 259 260 261 void 262 HaikuControlLook::DrawMenuFieldBackground(BView* view, BRect& rect, 263 const BRect& updateRect, const rgb_color& base, uint32 flags, 264 uint32 borders) 265 { 266 _DrawMenuFieldBackgroundInside(view, rect, updateRect, 267 0.0f, 0.0f, 0.0f, 0.0f, base, flags, borders); 268 } 269 270 271 void 272 HaikuControlLook::DrawMenuFieldBackground(BView* view, BRect& rect, 273 const BRect& updateRect, float radius, const rgb_color& base, 274 bool popupIndicator, uint32 flags) 275 { 276 _DrawMenuFieldBackgroundOutside(view, rect, updateRect, radius, radius, 277 radius, radius, base, popupIndicator, flags); 278 } 279 280 281 void 282 HaikuControlLook::DrawMenuFieldBackground(BView* view, BRect& rect, 283 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 284 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 285 bool popupIndicator, uint32 flags) 286 { 287 _DrawMenuFieldBackgroundOutside(view, rect, updateRect, leftTopRadius, 288 rightTopRadius, leftBottomRadius, rightBottomRadius, base, 289 popupIndicator, flags); 290 } 291 292 293 void 294 HaikuControlLook::DrawMenuBackground(BView* view, BRect& rect, 295 const BRect& updateRect, const rgb_color& base, uint32 flags, 296 uint32 borders) 297 { 298 if (!ShouldDraw(view, rect, updateRect)) 299 return; 300 301 // inner bevel colors 302 rgb_color bevelLightColor; 303 rgb_color bevelShadowColor; 304 305 if ((flags & B_DISABLED) != 0) { 306 bevelLightColor = tint_color(base, 0.80); 307 bevelShadowColor = tint_color(base, 1.07); 308 } else { 309 bevelLightColor = tint_color(base, 0.6); 310 bevelShadowColor = tint_color(base, 1.12); 311 } 312 313 // draw inner bevel 314 _DrawFrame(view, rect, 315 bevelLightColor, bevelLightColor, 316 bevelShadowColor, bevelShadowColor, 317 borders); 318 319 // draw surface top 320 view->SetHighColor(base); 321 view->FillRect(rect); 322 } 323 324 325 void 326 HaikuControlLook::DrawMenuItemBackground(BView* view, BRect& rect, 327 const BRect& updateRect, const rgb_color& base, uint32 flags, 328 uint32 borders) 329 { 330 if (!ShouldDraw(view, rect, updateRect)) 331 return; 332 333 // surface edges 334 float topTint; 335 float bottomTint; 336 rgb_color selectedColor = base; 337 338 if ((flags & B_ACTIVATED) != 0) { 339 topTint = 0.9; 340 bottomTint = 1.05; 341 } else if ((flags & B_DISABLED) != 0) { 342 topTint = 0.80; 343 bottomTint = 1.07; 344 } else { 345 topTint = 0.6; 346 bottomTint = 1.12; 347 } 348 349 rgb_color bevelLightColor = tint_color(selectedColor, topTint); 350 rgb_color bevelShadowColor = tint_color(selectedColor, bottomTint); 351 352 // draw surface edges 353 _DrawFrame(view, rect, 354 bevelLightColor, bevelLightColor, 355 bevelShadowColor, bevelShadowColor, 356 borders); 357 358 // draw surface top 359 view->SetLowColor(selectedColor); 360 // _FillGradient(view, rect, selectedColor, topTint, bottomTint); 361 _FillGradient(view, rect, selectedColor, bottomTint, topTint); 362 } 363 364 365 void 366 HaikuControlLook::DrawStatusBar(BView* view, BRect& rect, const BRect& updateRect, 367 const rgb_color& base, const rgb_color& barColor, float progressPosition) 368 { 369 if (!ShouldDraw(view, rect, updateRect)) 370 return; 371 372 _DrawOuterResessedFrame(view, rect, base, 0.6); 373 374 // colors 375 rgb_color dark1BorderColor = tint_color(base, 1.3); 376 rgb_color dark2BorderColor = tint_color(base, 1.2); 377 rgb_color dark1FilledBorderColor = tint_color(barColor, 1.20); 378 rgb_color dark2FilledBorderColor = tint_color(barColor, 1.45); 379 380 BRect filledRect(rect); 381 filledRect.right = progressPosition - 1; 382 383 BRect nonfilledRect(rect); 384 nonfilledRect.left = progressPosition; 385 386 bool filledSurface = filledRect.Width() > 0; 387 bool nonfilledSurface = nonfilledRect.Width() > 0; 388 389 if (filledSurface) { 390 _DrawFrame(view, filledRect, 391 dark1FilledBorderColor, dark1FilledBorderColor, 392 dark2FilledBorderColor, dark2FilledBorderColor); 393 394 _FillGlossyGradient(view, filledRect, barColor, 0.55, 0.68, 0.76, 0.90); 395 } 396 397 if (nonfilledSurface) { 398 _DrawFrame(view, nonfilledRect, dark1BorderColor, dark1BorderColor, 399 dark2BorderColor, dark2BorderColor, 400 B_TOP_BORDER | B_BOTTOM_BORDER | B_RIGHT_BORDER); 401 402 if (nonfilledRect.left < nonfilledRect.right) { 403 // shadow from fill bar, or left border 404 rgb_color leftBorder = dark1BorderColor; 405 if (filledSurface) 406 leftBorder = tint_color(base, 0.50); 407 view->SetHighColor(leftBorder); 408 view->StrokeLine(nonfilledRect.LeftTop(), 409 nonfilledRect.LeftBottom()); 410 nonfilledRect.left++; 411 } 412 413 _FillGradient(view, nonfilledRect, base, 0.25, 0.06); 414 } 415 } 416 417 418 void 419 HaikuControlLook::DrawCheckBox(BView* view, BRect& rect, const BRect& updateRect, 420 const rgb_color& base, uint32 flags) 421 { 422 if (!ShouldDraw(view, rect, updateRect)) 423 return; 424 425 rgb_color dark1BorderColor; 426 rgb_color dark2BorderColor; 427 rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 428 429 if ((flags & B_DISABLED) != 0) { 430 _DrawOuterResessedFrame(view, rect, base, 0.0, 1.0, flags); 431 432 dark1BorderColor = tint_color(base, 1.15); 433 dark2BorderColor = tint_color(base, 1.15); 434 } else if ((flags & B_CLICKED) != 0) { 435 dark1BorderColor = tint_color(base, 1.50); 436 dark2BorderColor = tint_color(base, 1.48); 437 438 _DrawFrame(view, rect, 439 dark1BorderColor, dark1BorderColor, 440 dark2BorderColor, dark2BorderColor); 441 442 dark2BorderColor = dark1BorderColor; 443 } else { 444 _DrawOuterResessedFrame(view, rect, base, 0.6, 1.0, flags); 445 446 dark1BorderColor = tint_color(base, 1.40); 447 dark2BorderColor = tint_color(base, 1.38); 448 } 449 450 if ((flags & B_FOCUSED) != 0) { 451 dark1BorderColor = navigationColor; 452 dark2BorderColor = navigationColor; 453 } 454 455 _DrawFrame(view, rect, 456 dark1BorderColor, dark1BorderColor, 457 dark2BorderColor, dark2BorderColor); 458 459 if ((flags & B_DISABLED) != 0) 460 _FillGradient(view, rect, base, 0.4, 0.2); 461 else 462 _FillGradient(view, rect, base, 0.15, 0.0); 463 464 rgb_color markColor; 465 if (_RadioButtonAndCheckBoxMarkColor(base, markColor, flags)) { 466 view->SetHighColor(markColor); 467 468 BFont font; 469 view->GetFont(&font); 470 float inset = std::max(2.0f, roundf(font.Size() / 6)); 471 rect.InsetBy(inset, inset); 472 473 float penSize = std::max(1.0f, ceilf(rect.Width() / 3.5f)); 474 if (penSize > 1.0f && fmodf(penSize, 2.0f) == 0.0f) { 475 // Tweak ends to "include" the pixel at the index, 476 // we need to do this in order to produce results like R5, 477 // where coordinates were inclusive 478 rect.right++; 479 rect.bottom++; 480 } 481 482 view->SetPenSize(penSize); 483 view->SetDrawingMode(B_OP_OVER); 484 view->StrokeLine(rect.LeftTop(), rect.RightBottom()); 485 view->StrokeLine(rect.LeftBottom(), rect.RightTop()); 486 } 487 } 488 489 490 void 491 HaikuControlLook::DrawRadioButton(BView* view, BRect& rect, const BRect& updateRect, 492 const rgb_color& base, uint32 flags) 493 { 494 if (!ShouldDraw(view, rect, updateRect)) 495 return; 496 497 rgb_color borderColor; 498 rgb_color bevelLight; 499 rgb_color bevelShadow; 500 rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 501 502 if ((flags & B_DISABLED) != 0) { 503 borderColor = tint_color(base, 1.15); 504 bevelLight = base; 505 bevelShadow = base; 506 } else if ((flags & B_CLICKED) != 0) { 507 borderColor = tint_color(base, 1.50); 508 bevelLight = borderColor; 509 bevelShadow = borderColor; 510 } else { 511 borderColor = tint_color(base, 1.45); 512 bevelLight = tint_color(base, 0.55); 513 bevelShadow = tint_color(base, 1.11); 514 } 515 516 if ((flags & B_FOCUSED) != 0) { 517 borderColor = navigationColor; 518 } 519 520 BGradientLinear bevelGradient; 521 bevelGradient.AddColor(bevelShadow, 0); 522 bevelGradient.AddColor(bevelLight, 255); 523 bevelGradient.SetStart(rect.LeftTop()); 524 bevelGradient.SetEnd(rect.RightBottom()); 525 526 view->FillEllipse(rect, bevelGradient); 527 rect.InsetBy(1, 1); 528 529 bevelGradient.MakeEmpty(); 530 bevelGradient.AddColor(borderColor, 0); 531 bevelGradient.AddColor(tint_color(borderColor, 0.8), 255); 532 view->FillEllipse(rect, bevelGradient); 533 rect.InsetBy(1, 1); 534 535 float topTint; 536 float bottomTint; 537 if ((flags & B_DISABLED) != 0) { 538 topTint = 0.4; 539 bottomTint = 0.2; 540 } else { 541 topTint = 0.15; 542 bottomTint = 0.0; 543 } 544 545 BGradientLinear gradient; 546 _MakeGradient(gradient, rect, base, topTint, bottomTint); 547 view->FillEllipse(rect, gradient); 548 549 rgb_color markColor; 550 if (_RadioButtonAndCheckBoxMarkColor(base, markColor, flags)) { 551 view->SetHighColor(markColor); 552 BFont font; 553 view->GetFont(&font); 554 float inset = roundf(font.Size() / 4); 555 rect.InsetBy(inset, inset); 556 view->FillEllipse(rect); 557 } 558 } 559 560 561 void 562 HaikuControlLook::DrawScrollBarBorder(BView* view, BRect rect, 563 const BRect& updateRect, const rgb_color& base, uint32 flags, 564 orientation orientation) 565 { 566 if (!ShouldDraw(view, rect, updateRect)) 567 return; 568 569 view->PushState(); 570 571 // set clipping constraints to rect 572 view->ClipToRect(rect); 573 574 bool isEnabled = (flags & B_DISABLED) == 0; 575 bool isFocused = (flags & B_FOCUSED) != 0; 576 577 view->SetHighColor(tint_color(base, B_DARKEN_2_TINT)); 578 579 // stroke a line around the entire scrollbar 580 // take care of border highlighting, scroll target is focus view 581 if (isEnabled && isFocused) { 582 rgb_color borderColor = view->HighColor(); 583 rgb_color highlightColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 584 585 view->BeginLineArray(4); 586 587 view->AddLine(BPoint(rect.left + 1, rect.bottom), 588 BPoint(rect.right, rect.bottom), borderColor); 589 view->AddLine(BPoint(rect.right, rect.top + 1), 590 BPoint(rect.right, rect.bottom - 1), borderColor); 591 592 if (orientation == B_HORIZONTAL) { 593 view->AddLine(BPoint(rect.left, rect.top + 1), 594 BPoint(rect.left, rect.bottom), borderColor); 595 } else { 596 view->AddLine(BPoint(rect.left, rect.top), 597 BPoint(rect.left, rect.bottom), highlightColor); 598 } 599 600 if (orientation == B_HORIZONTAL) { 601 view->AddLine(BPoint(rect.left, rect.top), 602 BPoint(rect.right, rect.top), highlightColor); 603 } else { 604 view->AddLine(BPoint(rect.left + 1, rect.top), 605 BPoint(rect.right, rect.top), borderColor); 606 } 607 608 view->EndLineArray(); 609 } else 610 view->StrokeRect(rect); 611 612 view->PopState(); 613 } 614 615 616 void 617 HaikuControlLook::DrawScrollBarButton(BView* view, BRect rect, 618 const BRect& updateRect, const rgb_color& base, uint32 flags, 619 int32 direction, orientation orientation, bool down) 620 { 621 if (!ShouldDraw(view, rect, updateRect)) 622 return; 623 624 view->PushState(); 625 626 // clip to button 627 view->ClipToRect(rect); 628 629 bool isEnabled = (flags & B_DISABLED) == 0; 630 631 rgb_color buttonColor = isEnabled ? base 632 : tint_color(base, B_LIGHTEN_1_TINT); 633 DrawButtonBackground(view, rect, updateRect, buttonColor, flags, 634 BControlLook::B_ALL_BORDERS, orientation); 635 636 rect.InsetBy(-1, -1); 637 DrawArrowShape(view, rect, updateRect, base, direction, flags, 1.9f); 638 // almost but not quite B_DARKEN_MAX_TINT 639 640 // revert clipping constraints 641 view->PopState(); 642 } 643 644 void 645 HaikuControlLook::DrawScrollBarBackground(BView* view, BRect& rect1, 646 BRect& rect2, const BRect& updateRect, const rgb_color& base, uint32 flags, 647 orientation orientation) 648 { 649 DrawScrollBarBackground(view, rect1, updateRect, base, flags, orientation); 650 DrawScrollBarBackground(view, rect2, updateRect, base, flags, orientation); 651 } 652 653 654 void 655 HaikuControlLook::DrawScrollBarBackground(BView* view, BRect& rect, 656 const BRect& updateRect, const rgb_color& base, uint32 flags, 657 orientation orientation) 658 { 659 if (!ShouldDraw(view, rect, updateRect)) 660 return; 661 662 view->PushState(); 663 664 // set clipping constraints to rect 665 view->ClipToRect(rect); 666 667 bool isEnabled = (flags & B_DISABLED) == 0; 668 669 // fill background, we'll draw arrows and thumb on top 670 view->SetDrawingMode(B_OP_COPY); 671 672 float gradient1Tint; 673 float gradient2Tint; 674 float darkEdge1Tint; 675 float darkEdge2Tint; 676 float shadowTint; 677 678 if (isEnabled) { 679 gradient1Tint = 1.10; 680 gradient2Tint = 1.05; 681 darkEdge1Tint = B_DARKEN_3_TINT; 682 darkEdge2Tint = B_DARKEN_2_TINT; 683 shadowTint = gradient1Tint; 684 } else { 685 gradient1Tint = 0.9; 686 gradient2Tint = 0.8; 687 darkEdge1Tint = B_DARKEN_2_TINT; 688 darkEdge2Tint = B_DARKEN_2_TINT; 689 shadowTint = gradient1Tint; 690 } 691 692 rgb_color darkEdge1 = tint_color(base, darkEdge1Tint); 693 rgb_color darkEdge2 = tint_color(base, darkEdge2Tint); 694 rgb_color shadow = tint_color(base, shadowTint); 695 696 if (orientation == B_HORIZONTAL) { 697 // dark vertical line on left edge 698 if (rect.Width() > 0) { 699 view->SetHighColor(darkEdge1); 700 view->StrokeLine(rect.LeftTop(), rect.LeftBottom()); 701 rect.left++; 702 } 703 // dark vertical line on right edge 704 if (rect.Width() >= 0) { 705 view->SetHighColor(darkEdge2); 706 view->StrokeLine(rect.RightTop(), rect.RightBottom()); 707 rect.right--; 708 } 709 // vertical shadow line after left edge 710 if (rect.Width() >= 0) { 711 view->SetHighColor(shadow); 712 view->StrokeLine(rect.LeftTop(), rect.LeftBottom()); 713 rect.left++; 714 } 715 // fill 716 if (rect.Width() >= 0) { 717 _FillGradient(view, rect, base, gradient1Tint, gradient2Tint, 718 orientation); 719 } 720 } else { 721 // dark vertical line on top edge 722 if (rect.Height() > 0) { 723 view->SetHighColor(darkEdge1); 724 view->StrokeLine(rect.LeftTop(), rect.RightTop()); 725 rect.top++; 726 } 727 // dark vertical line on bottom edge 728 if (rect.Height() >= 0) { 729 view->SetHighColor(darkEdge2); 730 view->StrokeLine(rect.LeftBottom(), rect.RightBottom()); 731 rect.bottom--; 732 } 733 // horizontal shadow line after top edge 734 if (rect.Height() >= 0) { 735 view->SetHighColor(shadow); 736 view->StrokeLine(rect.LeftTop(), rect.RightTop()); 737 rect.top++; 738 } 739 // fill 740 if (rect.Height() >= 0) { 741 _FillGradient(view, rect, base, gradient1Tint, gradient2Tint, 742 orientation); 743 } 744 } 745 746 view->PopState(); 747 } 748 749 750 void 751 HaikuControlLook::DrawScrollBarThumb(BView* view, BRect& rect, 752 const BRect& updateRect, const rgb_color& base, uint32 flags, 753 orientation orientation, uint32 knobStyle) 754 { 755 if (!ShouldDraw(view, rect, updateRect)) 756 return; 757 758 view->PushState(); 759 760 // set clipping constraints to rect 761 view->ClipToRect(rect); 762 763 // flags 764 bool isEnabled = (flags & B_DISABLED) == 0; 765 766 // colors 767 rgb_color thumbColor = ui_color(B_SCROLL_BAR_THUMB_COLOR); 768 const float bgTint = 1.06; 769 770 rgb_color light, dark, dark1, dark2; 771 if (isEnabled) { 772 light = tint_color(base, B_LIGHTEN_MAX_TINT); 773 dark = tint_color(base, B_DARKEN_3_TINT); 774 dark1 = tint_color(base, B_DARKEN_1_TINT); 775 dark2 = tint_color(base, B_DARKEN_2_TINT); 776 } else { 777 light = tint_color(base, B_LIGHTEN_MAX_TINT); 778 dark = tint_color(base, B_DARKEN_2_TINT); 779 dark1 = tint_color(base, B_LIGHTEN_2_TINT); 780 dark2 = tint_color(base, B_LIGHTEN_1_TINT); 781 } 782 783 // draw thumb over background 784 view->SetDrawingMode(B_OP_OVER); 785 view->SetHighColor(dark1); 786 787 // draw scroll thumb 788 if (isEnabled) { 789 // fill the clickable surface of the thumb 790 DrawButtonBackground(view, rect, updateRect, thumbColor, 0, 791 B_ALL_BORDERS, orientation); 792 } else { 793 // thumb bevel 794 view->BeginLineArray(4); 795 view->AddLine(BPoint(rect.left, rect.bottom), 796 BPoint(rect.left, rect.top), light); 797 view->AddLine(BPoint(rect.left + 1, rect.top), 798 BPoint(rect.right, rect.top), light); 799 view->AddLine(BPoint(rect.right, rect.top + 1), 800 BPoint(rect.right, rect.bottom), dark2); 801 view->AddLine(BPoint(rect.right - 1, rect.bottom), 802 BPoint(rect.left + 1, rect.bottom), dark2); 803 view->EndLineArray(); 804 805 // thumb fill 806 rect.InsetBy(1, 1); 807 view->SetHighColor(dark1); 808 view->FillRect(rect); 809 } 810 811 // draw knob style 812 if (knobStyle != B_KNOB_NONE) { 813 rgb_color knobLight = isEnabled 814 ? tint_color(thumbColor, B_LIGHTEN_MAX_TINT) 815 : tint_color(dark1, bgTint); 816 rgb_color knobDark = isEnabled 817 ? tint_color(thumbColor, 1.22) 818 : tint_color(knobLight, B_DARKEN_1_TINT); 819 820 if (knobStyle == B_KNOB_DOTS) { 821 // draw dots on the scroll bar thumb 822 float hcenter = rect.left + rect.Width() / 2; 823 float vmiddle = rect.top + rect.Height() / 2; 824 BRect knob(hcenter, vmiddle, hcenter, vmiddle); 825 826 if (orientation == B_HORIZONTAL) { 827 view->SetHighColor(knobDark); 828 view->FillRect(knob); 829 view->SetHighColor(knobLight); 830 view->FillRect(knob.OffsetByCopy(1, 1)); 831 832 float spacer = rect.Height(); 833 834 if (rect.left + 3 < hcenter - spacer) { 835 view->SetHighColor(knobDark); 836 view->FillRect(knob.OffsetByCopy(-spacer, 0)); 837 view->SetHighColor(knobLight); 838 view->FillRect(knob.OffsetByCopy(-spacer + 1, 1)); 839 } 840 841 if (rect.right - 3 > hcenter + spacer) { 842 view->SetHighColor(knobDark); 843 view->FillRect(knob.OffsetByCopy(spacer, 0)); 844 view->SetHighColor(knobLight); 845 view->FillRect(knob.OffsetByCopy(spacer + 1, 1)); 846 } 847 } else { 848 // B_VERTICAL 849 view->SetHighColor(knobDark); 850 view->FillRect(knob); 851 view->SetHighColor(knobLight); 852 view->FillRect(knob.OffsetByCopy(1, 1)); 853 854 float spacer = rect.Width(); 855 856 if (rect.top + 3 < vmiddle - spacer) { 857 view->SetHighColor(knobDark); 858 view->FillRect(knob.OffsetByCopy(0, -spacer)); 859 view->SetHighColor(knobLight); 860 view->FillRect(knob.OffsetByCopy(1, -spacer + 1)); 861 } 862 863 if (rect.bottom - 3 > vmiddle + spacer) { 864 view->SetHighColor(knobDark); 865 view->FillRect(knob.OffsetByCopy(0, spacer)); 866 view->SetHighColor(knobLight); 867 view->FillRect(knob.OffsetByCopy(1, spacer + 1)); 868 } 869 } 870 } else if (knobStyle == B_KNOB_LINES) { 871 // draw lines on the scroll bar thumb 872 if (orientation == B_HORIZONTAL) { 873 float middle = rect.Width() / 2; 874 875 view->BeginLineArray(6); 876 view->AddLine( 877 BPoint(rect.left + middle - 3, rect.top + 2), 878 BPoint(rect.left + middle - 3, rect.bottom - 2), 879 knobDark); 880 view->AddLine( 881 BPoint(rect.left + middle, rect.top + 2), 882 BPoint(rect.left + middle, rect.bottom - 2), 883 knobDark); 884 view->AddLine( 885 BPoint(rect.left + middle + 3, rect.top + 2), 886 BPoint(rect.left + middle + 3, rect.bottom - 2), 887 knobDark); 888 view->AddLine( 889 BPoint(rect.left + middle - 2, rect.top + 2), 890 BPoint(rect.left + middle - 2, rect.bottom - 2), 891 knobLight); 892 view->AddLine( 893 BPoint(rect.left + middle + 1, rect.top + 2), 894 BPoint(rect.left + middle + 1, rect.bottom - 2), 895 knobLight); 896 view->AddLine( 897 BPoint(rect.left + middle + 4, rect.top + 2), 898 BPoint(rect.left + middle + 4, rect.bottom - 2), 899 knobLight); 900 view->EndLineArray(); 901 } else { 902 // B_VERTICAL 903 float middle = rect.Height() / 2; 904 905 view->BeginLineArray(6); 906 view->AddLine( 907 BPoint(rect.left + 2, rect.top + middle - 3), 908 BPoint(rect.right - 2, rect.top + middle - 3), 909 knobDark); 910 view->AddLine( 911 BPoint(rect.left + 2, rect.top + middle), 912 BPoint(rect.right - 2, rect.top + middle), 913 knobDark); 914 view->AddLine( 915 BPoint(rect.left + 2, rect.top + middle + 3), 916 BPoint(rect.right - 2, rect.top + middle + 3), 917 knobDark); 918 view->AddLine( 919 BPoint(rect.left + 2, rect.top + middle - 2), 920 BPoint(rect.right - 2, rect.top + middle - 2), 921 knobLight); 922 view->AddLine( 923 BPoint(rect.left + 2, rect.top + middle + 1), 924 BPoint(rect.right - 2, rect.top + middle + 1), 925 knobLight); 926 view->AddLine( 927 BPoint(rect.left + 2, rect.top + middle + 4), 928 BPoint(rect.right - 2, rect.top + middle + 4), 929 knobLight); 930 view->EndLineArray(); 931 } 932 } 933 } 934 935 view->PopState(); 936 } 937 938 939 void 940 HaikuControlLook::DrawScrollViewFrame(BView* view, BRect& rect, 941 const BRect& updateRect, BRect verticalScrollBarFrame, 942 BRect horizontalScrollBarFrame, const rgb_color& base, 943 border_style borderStyle, uint32 flags, uint32 _borders) 944 { 945 // calculate scroll corner rect before messing with the "rect" 946 BRect scrollCornerFillRect(rect.right, rect.bottom, 947 rect.right, rect.bottom); 948 949 if (horizontalScrollBarFrame.IsValid()) 950 scrollCornerFillRect.left = horizontalScrollBarFrame.right + 1; 951 952 if (verticalScrollBarFrame.IsValid()) 953 scrollCornerFillRect.top = verticalScrollBarFrame.bottom + 1; 954 955 if (borderStyle == B_NO_BORDER) { 956 if (scrollCornerFillRect.IsValid()) { 957 view->SetHighColor(base); 958 view->FillRect(scrollCornerFillRect); 959 } 960 return; 961 } 962 963 bool excludeScrollCorner = borderStyle == B_FANCY_BORDER 964 && horizontalScrollBarFrame.IsValid() 965 && verticalScrollBarFrame.IsValid(); 966 967 uint32 borders = _borders; 968 if (excludeScrollCorner) { 969 rect.bottom = horizontalScrollBarFrame.top; 970 rect.right = verticalScrollBarFrame.left; 971 borders &= ~(B_RIGHT_BORDER | B_BOTTOM_BORDER); 972 } 973 974 rgb_color scrollbarFrameColor = tint_color(base, B_DARKEN_2_TINT); 975 976 if (borderStyle == B_FANCY_BORDER) 977 _DrawOuterResessedFrame(view, rect, base, 1.0, 1.0, flags, borders); 978 979 if ((flags & B_FOCUSED) != 0) { 980 rgb_color focusColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 981 _DrawFrame(view, rect, focusColor, focusColor, focusColor, focusColor, 982 borders); 983 } else { 984 _DrawFrame(view, rect, scrollbarFrameColor, scrollbarFrameColor, 985 scrollbarFrameColor, scrollbarFrameColor, borders); 986 } 987 988 if (excludeScrollCorner) { 989 horizontalScrollBarFrame.InsetBy(-1, -1); 990 // do not overdraw the top edge 991 horizontalScrollBarFrame.top += 2; 992 borders = _borders; 993 borders &= ~B_TOP_BORDER; 994 _DrawOuterResessedFrame(view, horizontalScrollBarFrame, base, 995 1.0, 1.0, flags, borders); 996 _DrawFrame(view, horizontalScrollBarFrame, scrollbarFrameColor, 997 scrollbarFrameColor, scrollbarFrameColor, scrollbarFrameColor, 998 borders); 999 1000 verticalScrollBarFrame.InsetBy(-1, -1); 1001 // do not overdraw the left edge 1002 verticalScrollBarFrame.left += 2; 1003 borders = _borders; 1004 borders &= ~B_LEFT_BORDER; 1005 _DrawOuterResessedFrame(view, verticalScrollBarFrame, base, 1006 1.0, 1.0, flags, borders); 1007 _DrawFrame(view, verticalScrollBarFrame, scrollbarFrameColor, 1008 scrollbarFrameColor, scrollbarFrameColor, scrollbarFrameColor, 1009 borders); 1010 1011 // exclude recessed frame 1012 scrollCornerFillRect.top++; 1013 scrollCornerFillRect.left++; 1014 } 1015 1016 if (scrollCornerFillRect.IsValid()) { 1017 view->SetHighColor(base); 1018 view->FillRect(scrollCornerFillRect); 1019 } 1020 } 1021 1022 1023 void 1024 HaikuControlLook::DrawArrowShape(BView* view, BRect& rect, 1025 const BRect& updateRect, const rgb_color& base, uint32 direction, 1026 uint32 flags, float tint) 1027 { 1028 BPoint tri1, tri2, tri3; 1029 float hInset = rect.Width() / 3; 1030 float vInset = rect.Height() / 3; 1031 rect.InsetBy(hInset, vInset); 1032 1033 switch (direction) { 1034 case B_LEFT_ARROW: 1035 tri1.Set(rect.right, rect.top); 1036 tri2.Set(rect.right - rect.Width() / 1.33, 1037 (rect.top + rect.bottom + 1) / 2); 1038 tri3.Set(rect.right, rect.bottom + 1); 1039 break; 1040 case B_RIGHT_ARROW: 1041 tri1.Set(rect.left + 1, rect.bottom + 1); 1042 tri2.Set(rect.left + 1 + rect.Width() / 1.33, 1043 (rect.top + rect.bottom + 1) / 2); 1044 tri3.Set(rect.left + 1, rect.top); 1045 break; 1046 case B_UP_ARROW: 1047 tri1.Set(rect.left, rect.bottom); 1048 tri2.Set((rect.left + rect.right + 1) / 2, 1049 rect.bottom - rect.Height() / 1.33); 1050 tri3.Set(rect.right + 1, rect.bottom); 1051 break; 1052 case B_DOWN_ARROW: 1053 default: 1054 tri1.Set(rect.left, rect.top + 1); 1055 tri2.Set((rect.left + rect.right + 1) / 2, 1056 rect.top + 1 + rect.Height() / 1.33); 1057 tri3.Set(rect.right + 1, rect.top + 1); 1058 break; 1059 case B_LEFT_UP_ARROW: 1060 tri1.Set(rect.left, rect.bottom); 1061 tri2.Set(rect.left, rect.top); 1062 tri3.Set(rect.right - 1, rect.top); 1063 break; 1064 case B_RIGHT_UP_ARROW: 1065 tri1.Set(rect.left + 1, rect.top); 1066 tri2.Set(rect.right, rect.top); 1067 tri3.Set(rect.right, rect.bottom); 1068 break; 1069 case B_RIGHT_DOWN_ARROW: 1070 tri1.Set(rect.right, rect.top); 1071 tri2.Set(rect.right, rect.bottom); 1072 tri3.Set(rect.left + 1, rect.bottom); 1073 break; 1074 case B_LEFT_DOWN_ARROW: 1075 tri1.Set(rect.right - 1, rect.bottom); 1076 tri2.Set(rect.left, rect.bottom); 1077 tri3.Set(rect.left, rect.top); 1078 break; 1079 } 1080 1081 BShape arrowShape; 1082 arrowShape.MoveTo(tri1); 1083 arrowShape.LineTo(tri2); 1084 arrowShape.LineTo(tri3); 1085 1086 if ((flags & B_DISABLED) != 0) 1087 tint = (tint + B_NO_TINT + B_NO_TINT) / 3; 1088 1089 view->SetHighColor(tint_color(base, tint)); 1090 1091 float penSize = view->PenSize(); 1092 drawing_mode mode = view->DrawingMode(); 1093 1094 view->MovePenTo(BPoint(0, 0)); 1095 1096 view->SetPenSize(ceilf(hInset / 2.0)); 1097 view->SetDrawingMode(B_OP_OVER); 1098 view->StrokeShape(&arrowShape); 1099 1100 view->SetPenSize(penSize); 1101 view->SetDrawingMode(mode); 1102 } 1103 1104 1105 rgb_color 1106 HaikuControlLook::SliderBarColor(const rgb_color& base) 1107 { 1108 return tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_DARKEN_1_TINT); 1109 } 1110 1111 1112 void 1113 HaikuControlLook::DrawSliderBar(BView* view, BRect rect, const BRect& updateRect, 1114 const rgb_color& base, rgb_color leftFillColor, rgb_color rightFillColor, 1115 float sliderScale, uint32 flags, orientation orientation) 1116 { 1117 if (!ShouldDraw(view, rect, updateRect)) 1118 return; 1119 1120 // separate the bar in two sides 1121 float sliderPosition; 1122 BRect leftBarSide = rect; 1123 BRect rightBarSide = rect; 1124 1125 if (orientation == B_HORIZONTAL) { 1126 sliderPosition = floorf(rect.left + 2 + (rect.Width() - 2) 1127 * sliderScale); 1128 leftBarSide.right = sliderPosition - 1; 1129 rightBarSide.left = sliderPosition; 1130 } else { 1131 // NOTE: position is reverse of coords 1132 sliderPosition = floorf(rect.top + 2 + (rect.Height() - 2) 1133 * (1.0 - sliderScale)); 1134 leftBarSide.top = sliderPosition; 1135 rightBarSide.bottom = sliderPosition - 1; 1136 } 1137 1138 view->PushState(); 1139 view->ClipToRect(leftBarSide); 1140 DrawSliderBar(view, rect, updateRect, base, leftFillColor, flags, 1141 orientation); 1142 view->PopState(); 1143 1144 view->PushState(); 1145 view->ClipToRect(rightBarSide); 1146 DrawSliderBar(view, rect, updateRect, base, rightFillColor, flags, 1147 orientation); 1148 view->PopState(); 1149 } 1150 1151 1152 void 1153 HaikuControlLook::DrawSliderBar(BView* view, BRect rect, const BRect& updateRect, 1154 const rgb_color& base, rgb_color fillColor, uint32 flags, 1155 orientation orientation) 1156 { 1157 if (!ShouldDraw(view, rect, updateRect)) 1158 return; 1159 1160 // separate the rect into corners 1161 BRect leftCorner(rect); 1162 BRect rightCorner(rect); 1163 BRect barRect(rect); 1164 1165 if (orientation == B_HORIZONTAL) { 1166 leftCorner.right = leftCorner.left + leftCorner.Height(); 1167 rightCorner.left = rightCorner.right - rightCorner.Height(); 1168 barRect.left += ceilf(barRect.Height() / 2); 1169 barRect.right -= ceilf(barRect.Height() / 2); 1170 } else { 1171 leftCorner.bottom = leftCorner.top + leftCorner.Width(); 1172 rightCorner.top = rightCorner.bottom - rightCorner.Width(); 1173 barRect.top += ceilf(barRect.Width() / 2); 1174 barRect.bottom -= ceilf(barRect.Width() / 2); 1175 } 1176 1177 // fill the background for the corners, exclude the middle bar for now 1178 view->PushState(); 1179 view->ClipToRect(rect); 1180 view->ClipToInverseRect(barRect); 1181 1182 if ((flags & B_BLEND_FRAME) == 0) { 1183 view->SetHighColor(base); 1184 view->FillRect(rect); 1185 } 1186 1187 // figure out the tints to be used 1188 float edgeLightTint; 1189 float edgeShadowTint; 1190 float frameLightTint; 1191 float frameShadowTint; 1192 float fillLightTint; 1193 float fillShadowTint; 1194 uint8 edgeLightAlpha; 1195 uint8 edgeShadowAlpha; 1196 uint8 frameLightAlpha; 1197 uint8 frameShadowAlpha; 1198 1199 if ((flags & B_DISABLED) != 0) { 1200 edgeLightTint = 1.0; 1201 edgeShadowTint = 1.0; 1202 frameLightTint = 1.20; 1203 frameShadowTint = 1.25; 1204 fillLightTint = 0.9; 1205 fillShadowTint = 1.05; 1206 edgeLightAlpha = 12; 1207 edgeShadowAlpha = 12; 1208 frameLightAlpha = 40; 1209 frameShadowAlpha = 45; 1210 1211 fillColor.red = uint8(fillColor.red * 0.4 + base.red * 0.6); 1212 fillColor.green = uint8(fillColor.green * 0.4 + base.green * 0.6); 1213 fillColor.blue = uint8(fillColor.blue * 0.4 + base.blue * 0.6); 1214 } else { 1215 edgeLightTint = 0.65; 1216 edgeShadowTint = 1.07; 1217 frameLightTint = 1.40; 1218 frameShadowTint = 1.50; 1219 fillLightTint = 0.8; 1220 fillShadowTint = 1.1; 1221 edgeLightAlpha = 15; 1222 edgeShadowAlpha = 15; 1223 frameLightAlpha = 92; 1224 frameShadowAlpha = 107; 1225 } 1226 1227 rgb_color edgeLightColor; 1228 rgb_color edgeShadowColor; 1229 rgb_color frameLightColor; 1230 rgb_color frameShadowColor; 1231 rgb_color fillLightColor = tint_color(fillColor, fillLightTint); 1232 rgb_color fillShadowColor = tint_color(fillColor, fillShadowTint); 1233 1234 drawing_mode oldMode = view->DrawingMode(); 1235 1236 if ((flags & B_BLEND_FRAME) != 0) { 1237 edgeLightColor = (rgb_color){ 255, 255, 255, edgeLightAlpha }; 1238 edgeShadowColor = (rgb_color){ 0, 0, 0, edgeShadowAlpha }; 1239 frameLightColor = (rgb_color){ 0, 0, 0, frameLightAlpha }; 1240 frameShadowColor = (rgb_color){ 0, 0, 0, frameShadowAlpha }; 1241 1242 view->SetDrawingMode(B_OP_ALPHA); 1243 } else { 1244 edgeLightColor = tint_color(base, edgeLightTint); 1245 edgeShadowColor = tint_color(base, edgeShadowTint); 1246 frameLightColor = tint_color(fillColor, frameLightTint); 1247 frameShadowColor = tint_color(fillColor, frameShadowTint); 1248 } 1249 1250 if (orientation == B_HORIZONTAL) { 1251 _DrawRoundBarCorner(view, leftCorner, updateRect, edgeLightColor, 1252 edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor, 1253 fillShadowColor, 1.0, 1.0, 0.0, -1.0, orientation); 1254 1255 _DrawRoundBarCorner(view, rightCorner, updateRect, edgeLightColor, 1256 edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor, 1257 fillShadowColor, 0.0, 1.0, -1.0, -1.0, orientation); 1258 } else { 1259 _DrawRoundBarCorner(view, leftCorner, updateRect, edgeLightColor, 1260 edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor, 1261 fillShadowColor, 1.0, 1.0, -1.0, 0.0, orientation); 1262 1263 _DrawRoundBarCorner(view, rightCorner, updateRect, edgeLightColor, 1264 edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor, 1265 fillShadowColor, 1.0, 0.0, -1.0, -1.0, orientation); 1266 } 1267 1268 view->PopState(); 1269 if ((flags & B_BLEND_FRAME) != 0) 1270 view->SetDrawingMode(B_OP_ALPHA); 1271 1272 view->BeginLineArray(4); 1273 if (orientation == B_HORIZONTAL) { 1274 view->AddLine(barRect.LeftTop(), barRect.RightTop(), 1275 edgeShadowColor); 1276 view->AddLine(barRect.LeftBottom(), barRect.RightBottom(), 1277 edgeLightColor); 1278 barRect.InsetBy(0, 1); 1279 view->AddLine(barRect.LeftTop(), barRect.RightTop(), 1280 frameShadowColor); 1281 view->AddLine(barRect.LeftBottom(), barRect.RightBottom(), 1282 frameLightColor); 1283 barRect.InsetBy(0, 1); 1284 } else { 1285 view->AddLine(barRect.LeftTop(), barRect.LeftBottom(), 1286 edgeShadowColor); 1287 view->AddLine(barRect.RightTop(), barRect.RightBottom(), 1288 edgeLightColor); 1289 barRect.InsetBy(1, 0); 1290 view->AddLine(barRect.LeftTop(), barRect.LeftBottom(), 1291 frameShadowColor); 1292 view->AddLine(barRect.RightTop(), barRect.RightBottom(), 1293 frameLightColor); 1294 barRect.InsetBy(1, 0); 1295 } 1296 view->EndLineArray(); 1297 1298 view->SetDrawingMode(oldMode); 1299 1300 _FillGradient(view, barRect, fillColor, fillShadowTint, fillLightTint, 1301 orientation); 1302 } 1303 1304 1305 void 1306 HaikuControlLook::DrawSliderThumb(BView* view, BRect& rect, const BRect& updateRect, 1307 const rgb_color& base, uint32 flags, orientation orientation) 1308 { 1309 if (!ShouldDraw(view, rect, updateRect)) 1310 return; 1311 1312 // figure out frame color 1313 rgb_color frameLightColor; 1314 rgb_color frameShadowColor; 1315 rgb_color shadowColor = (rgb_color){ 0, 0, 0, 60 }; 1316 1317 if ((flags & B_FOCUSED) != 0) { 1318 // focused 1319 frameLightColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 1320 frameShadowColor = frameLightColor; 1321 } else { 1322 // figure out the tints to be used 1323 float frameLightTint; 1324 float frameShadowTint; 1325 1326 if ((flags & B_DISABLED) != 0) { 1327 frameLightTint = 1.30; 1328 frameShadowTint = 1.35; 1329 shadowColor.alpha = 30; 1330 } else { 1331 frameLightTint = 1.6; 1332 frameShadowTint = 1.65; 1333 } 1334 1335 frameLightColor = tint_color(base, frameLightTint); 1336 frameShadowColor = tint_color(base, frameShadowTint); 1337 } 1338 1339 BRect originalRect(rect); 1340 rect.right--; 1341 rect.bottom--; 1342 1343 _DrawFrame(view, rect, frameLightColor, frameLightColor, 1344 frameShadowColor, frameShadowColor); 1345 1346 flags &= ~B_ACTIVATED; 1347 DrawButtonBackground(view, rect, updateRect, base, flags); 1348 1349 // thumb shadow 1350 view->SetDrawingMode(B_OP_ALPHA); 1351 view->SetHighColor(shadowColor); 1352 originalRect.left++; 1353 originalRect.top++; 1354 view->StrokeLine(originalRect.LeftBottom(), originalRect.RightBottom()); 1355 originalRect.bottom--; 1356 view->StrokeLine(originalRect.RightTop(), originalRect.RightBottom()); 1357 1358 // thumb edge 1359 if (orientation == B_HORIZONTAL) { 1360 rect.InsetBy(0, floorf(rect.Height() / 4)); 1361 rect.left = floorf((rect.left + rect.right) / 2); 1362 rect.right = rect.left + 1; 1363 shadowColor = tint_color(base, B_DARKEN_2_TINT); 1364 shadowColor.alpha = 128; 1365 view->SetHighColor(shadowColor); 1366 view->StrokeLine(rect.LeftTop(), rect.LeftBottom()); 1367 rgb_color lightColor = tint_color(base, B_LIGHTEN_2_TINT); 1368 lightColor.alpha = 128; 1369 view->SetHighColor(lightColor); 1370 view->StrokeLine(rect.RightTop(), rect.RightBottom()); 1371 } else { 1372 rect.InsetBy(floorf(rect.Width() / 4), 0); 1373 rect.top = floorf((rect.top + rect.bottom) / 2); 1374 rect.bottom = rect.top + 1; 1375 shadowColor = tint_color(base, B_DARKEN_2_TINT); 1376 shadowColor.alpha = 128; 1377 view->SetHighColor(shadowColor); 1378 view->StrokeLine(rect.LeftTop(), rect.RightTop()); 1379 rgb_color lightColor = tint_color(base, B_LIGHTEN_2_TINT); 1380 lightColor.alpha = 128; 1381 view->SetHighColor(lightColor); 1382 view->StrokeLine(rect.LeftBottom(), rect.RightBottom()); 1383 } 1384 1385 view->SetDrawingMode(B_OP_COPY); 1386 } 1387 1388 1389 void 1390 HaikuControlLook::DrawSliderTriangle(BView* view, BRect& rect, 1391 const BRect& updateRect, const rgb_color& base, uint32 flags, 1392 orientation orientation) 1393 { 1394 DrawSliderTriangle(view, rect, updateRect, base, base, flags, orientation); 1395 } 1396 1397 1398 void 1399 HaikuControlLook::DrawSliderTriangle(BView* view, BRect& rect, 1400 const BRect& updateRect, const rgb_color& base, const rgb_color& fill, 1401 uint32 flags, orientation orientation) 1402 { 1403 if (!ShouldDraw(view, rect, updateRect)) 1404 return; 1405 1406 // figure out frame color 1407 rgb_color frameLightColor; 1408 rgb_color frameShadowColor; 1409 rgb_color shadowColor = (rgb_color){ 0, 0, 0, 60 }; 1410 1411 float topTint = 0.49; 1412 float middleTint1 = 0.62; 1413 float middleTint2 = 0.76; 1414 float bottomTint = 0.90; 1415 1416 if ((flags & B_DISABLED) != 0) { 1417 topTint = (topTint + B_NO_TINT) / 2; 1418 middleTint1 = (middleTint1 + B_NO_TINT) / 2; 1419 middleTint2 = (middleTint2 + B_NO_TINT) / 2; 1420 bottomTint = (bottomTint + B_NO_TINT) / 2; 1421 } else if ((flags & B_HOVER) != 0) { 1422 topTint *= kHoverTintFactor; 1423 middleTint1 *= kHoverTintFactor; 1424 middleTint2 *= kHoverTintFactor; 1425 bottomTint *= kHoverTintFactor; 1426 } 1427 1428 if ((flags & B_FOCUSED) != 0) { 1429 // focused 1430 frameLightColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 1431 frameShadowColor = frameLightColor; 1432 } else { 1433 // figure out the tints to be used 1434 float frameLightTint; 1435 float frameShadowTint; 1436 1437 if ((flags & B_DISABLED) != 0) { 1438 frameLightTint = 1.30; 1439 frameShadowTint = 1.35; 1440 shadowColor.alpha = 30; 1441 } else { 1442 frameLightTint = 1.6; 1443 frameShadowTint = 1.65; 1444 } 1445 1446 frameLightColor = tint_color(base, frameLightTint); 1447 frameShadowColor = tint_color(base, frameShadowTint); 1448 } 1449 1450 // make room for the shadow 1451 rect.right--; 1452 rect.bottom--; 1453 1454 uint32 viewFlags = view->Flags(); 1455 view->SetFlags(viewFlags | B_SUBPIXEL_PRECISE); 1456 view->SetLineMode(B_ROUND_CAP, B_ROUND_JOIN); 1457 1458 float centerh = (rect.left + rect.right) / 2; 1459 float centerv = (rect.top + rect.bottom) / 2; 1460 1461 BShape shape; 1462 if (orientation == B_HORIZONTAL) { 1463 shape.MoveTo(BPoint(rect.left + 0.5, rect.bottom + 0.5)); 1464 shape.LineTo(BPoint(rect.right + 0.5, rect.bottom + 0.5)); 1465 shape.LineTo(BPoint(rect.right + 0.5, rect.bottom - 1 + 0.5)); 1466 shape.LineTo(BPoint(centerh + 0.5, rect.top + 0.5)); 1467 shape.LineTo(BPoint(rect.left + 0.5, rect.bottom - 1 + 0.5)); 1468 } else { 1469 shape.MoveTo(BPoint(rect.right + 0.5, rect.top + 0.5)); 1470 shape.LineTo(BPoint(rect.right + 0.5, rect.bottom + 0.5)); 1471 shape.LineTo(BPoint(rect.right - 1 + 0.5, rect.bottom + 0.5)); 1472 shape.LineTo(BPoint(rect.left + 0.5, centerv + 0.5)); 1473 shape.LineTo(BPoint(rect.right - 1 + 0.5, rect.top + 0.5)); 1474 } 1475 shape.Close(); 1476 1477 view->MovePenTo(BPoint(1, 1)); 1478 1479 view->SetDrawingMode(B_OP_ALPHA); 1480 view->SetHighColor(shadowColor); 1481 view->StrokeShape(&shape); 1482 1483 view->MovePenTo(B_ORIGIN); 1484 1485 view->SetDrawingMode(B_OP_COPY); 1486 view->SetHighColor(frameLightColor); 1487 view->StrokeShape(&shape); 1488 1489 rect.InsetBy(1, 1); 1490 shape.Clear(); 1491 if (orientation == B_HORIZONTAL) { 1492 shape.MoveTo(BPoint(rect.left, rect.bottom + 1)); 1493 shape.LineTo(BPoint(rect.right + 1, rect.bottom + 1)); 1494 shape.LineTo(BPoint(centerh + 0.5, rect.top)); 1495 } else { 1496 shape.MoveTo(BPoint(rect.right + 1, rect.top)); 1497 shape.LineTo(BPoint(rect.right + 1, rect.bottom + 1)); 1498 shape.LineTo(BPoint(rect.left, centerv + 0.5)); 1499 } 1500 shape.Close(); 1501 1502 BGradientLinear gradient; 1503 if ((flags & B_DISABLED) != 0) { 1504 _MakeGradient(gradient, rect, fill, topTint, bottomTint); 1505 } else { 1506 _MakeGlossyGradient(gradient, rect, fill, topTint, middleTint1, 1507 middleTint2, bottomTint); 1508 } 1509 1510 view->FillShape(&shape, gradient); 1511 1512 view->SetFlags(viewFlags); 1513 } 1514 1515 1516 void 1517 HaikuControlLook::DrawSliderHashMarks(BView* view, BRect& rect, 1518 const BRect& updateRect, const rgb_color& base, int32 count, 1519 hash_mark_location location, uint32 flags, orientation orientation) 1520 { 1521 if (!ShouldDraw(view, rect, updateRect)) 1522 return; 1523 1524 rgb_color lightColor; 1525 rgb_color darkColor; 1526 1527 if ((flags & B_DISABLED) != 0) { 1528 lightColor = tint_color(base, 0.9); 1529 darkColor = tint_color(base, 1.07); 1530 } else { 1531 lightColor = tint_color(base, 0.8); 1532 darkColor = tint_color(base, 1.14); 1533 } 1534 1535 int32 hashMarkCount = std::max(count, (int32)2); 1536 // draw at least two hashmarks at min/max if 1537 // fHashMarks != B_HASH_MARKS_NONE 1538 float factor; 1539 float startPos; 1540 if (orientation == B_HORIZONTAL) { 1541 factor = (rect.Width() - 2) / (hashMarkCount - 1); 1542 startPos = rect.left + 1; 1543 } else { 1544 factor = (rect.Height() - 2) / (hashMarkCount - 1); 1545 startPos = rect.top + 1; 1546 } 1547 1548 if (location & B_HASH_MARKS_TOP) { 1549 view->BeginLineArray(hashMarkCount * 2); 1550 1551 if (orientation == B_HORIZONTAL) { 1552 float pos = startPos; 1553 for (int32 i = 0; i < hashMarkCount; i++) { 1554 view->AddLine(BPoint(pos, rect.top), 1555 BPoint(pos, rect.top + 4), darkColor); 1556 view->AddLine(BPoint(pos + 1, rect.top), 1557 BPoint(pos + 1, rect.top + 4), lightColor); 1558 1559 pos += factor; 1560 } 1561 } else { 1562 float pos = startPos; 1563 for (int32 i = 0; i < hashMarkCount; i++) { 1564 view->AddLine(BPoint(rect.left, pos), 1565 BPoint(rect.left + 4, pos), darkColor); 1566 view->AddLine(BPoint(rect.left, pos + 1), 1567 BPoint(rect.left + 4, pos + 1), lightColor); 1568 1569 pos += factor; 1570 } 1571 } 1572 1573 view->EndLineArray(); 1574 } 1575 1576 if ((location & B_HASH_MARKS_BOTTOM) != 0) { 1577 view->BeginLineArray(hashMarkCount * 2); 1578 1579 if (orientation == B_HORIZONTAL) { 1580 float pos = startPos; 1581 for (int32 i = 0; i < hashMarkCount; i++) { 1582 view->AddLine(BPoint(pos, rect.bottom - 4), 1583 BPoint(pos, rect.bottom), darkColor); 1584 view->AddLine(BPoint(pos + 1, rect.bottom - 4), 1585 BPoint(pos + 1, rect.bottom), lightColor); 1586 1587 pos += factor; 1588 } 1589 } else { 1590 float pos = startPos; 1591 for (int32 i = 0; i < hashMarkCount; i++) { 1592 view->AddLine(BPoint(rect.right - 4, pos), 1593 BPoint(rect.right, pos), darkColor); 1594 view->AddLine(BPoint(rect.right - 4, pos + 1), 1595 BPoint(rect.right, pos + 1), lightColor); 1596 1597 pos += factor; 1598 } 1599 } 1600 1601 view->EndLineArray(); 1602 } 1603 } 1604 1605 1606 void 1607 HaikuControlLook::DrawTabFrame(BView* view, BRect& rect, 1608 const BRect& updateRect, const rgb_color& base, uint32 flags, 1609 uint32 borders, border_style borderStyle, uint32 side) 1610 { 1611 if (!ShouldDraw(view, rect, updateRect)) 1612 return; 1613 1614 if (side == BTabView::kTopSide || side == BTabView::kBottomSide) { 1615 // draw an inactive tab frame behind all tabs 1616 borders = B_TOP_BORDER | B_BOTTOM_BORDER; 1617 if (borderStyle != B_NO_BORDER) 1618 borders |= B_LEFT_BORDER | B_RIGHT_BORDER; 1619 1620 // DrawInactiveTab draws 2px border 1621 // draw tab frame wider to align B_PLAIN_BORDER with it 1622 if (borderStyle == B_PLAIN_BORDER) 1623 rect.InsetBy(-1, 0); 1624 } else if (side == BTabView::kLeftSide || side == BTabView::kRightSide) { 1625 // draw an inactive tab frame behind all tabs 1626 borders = B_LEFT_BORDER | B_RIGHT_BORDER; 1627 if (borderStyle != B_NO_BORDER) 1628 borders |= B_TOP_BORDER | B_BOTTOM_BORDER; 1629 1630 // DrawInactiveTab draws 2px border 1631 // draw tab frame wider to align B_PLAIN_BORDER with it 1632 if (borderStyle == B_PLAIN_BORDER) 1633 rect.InsetBy(0, -1); 1634 } 1635 1636 DrawInactiveTab(view, rect, rect, base, 0, borders, side); 1637 } 1638 1639 1640 void 1641 HaikuControlLook::DrawActiveTab(BView* view, BRect& rect, 1642 const BRect& updateRect, const rgb_color& base, uint32 flags, 1643 uint32 borders, uint32 side, int32, int32, int32, int32) 1644 { 1645 if (!ShouldDraw(view, rect, updateRect)) 1646 return; 1647 1648 // Snap the rectangle to pixels to avoid rounding errors. 1649 rect.left = floorf(rect.left); 1650 rect.right = floorf(rect.right); 1651 rect.top = floorf(rect.top); 1652 rect.bottom = floorf(rect.bottom); 1653 1654 // save the clipping constraints of the view 1655 view->PushState(); 1656 1657 // set clipping constraints to rect 1658 view->ClipToRect(rect); 1659 1660 rgb_color edgeShadowColor; 1661 rgb_color edgeLightColor; 1662 rgb_color frameShadowColor; 1663 rgb_color frameLightColor; 1664 rgb_color bevelShadowColor; 1665 rgb_color bevelLightColor; 1666 BGradientLinear fillGradient; 1667 fillGradient.SetStart(rect.LeftTop() + BPoint(3, 3)); 1668 fillGradient.SetEnd(rect.LeftBottom() + BPoint(3, -3)); 1669 1670 if ((flags & B_DISABLED) != 0) { 1671 edgeLightColor = base; 1672 edgeShadowColor = base; 1673 frameLightColor = tint_color(base, 1.25); 1674 frameShadowColor = tint_color(base, 1.30); 1675 bevelLightColor = tint_color(base, 0.8); 1676 bevelShadowColor = tint_color(base, 1.07); 1677 fillGradient.AddColor(tint_color(base, 0.85), 0); 1678 fillGradient.AddColor(base, 255); 1679 } else { 1680 edgeLightColor = tint_color(base, 0.80); 1681 edgeShadowColor = tint_color(base, 1.03); 1682 frameLightColor = tint_color(base, 1.30); 1683 frameShadowColor = tint_color(base, 1.30); 1684 bevelLightColor = tint_color(base, 0.6); 1685 bevelShadowColor = tint_color(base, 1.07); 1686 fillGradient.AddColor(tint_color(base, 0.75), 0); 1687 fillGradient.AddColor(tint_color(base, 1.03), 255); 1688 } 1689 1690 static const float kRoundCornerRadius = 4.0f; 1691 1692 // left top corner dimensions 1693 BRect leftTopCorner(rect); 1694 leftTopCorner.right = floorf(leftTopCorner.left + kRoundCornerRadius); 1695 leftTopCorner.bottom = floorf(rect.top + kRoundCornerRadius); 1696 1697 // right top corner dimensions 1698 BRect rightTopCorner(rect); 1699 rightTopCorner.left = floorf(rightTopCorner.right - kRoundCornerRadius); 1700 rightTopCorner.bottom = floorf(rect.top + kRoundCornerRadius); 1701 1702 // left bottom corner dimensions 1703 BRect leftBottomCorner(rect); 1704 leftBottomCorner.right = floorf(leftBottomCorner.left + kRoundCornerRadius); 1705 leftBottomCorner.top = floorf(rect.bottom - kRoundCornerRadius); 1706 1707 // right bottom corner dimensions 1708 BRect rightBottomCorner(rect); 1709 rightBottomCorner.left = floorf(rightBottomCorner.right 1710 - kRoundCornerRadius); 1711 rightBottomCorner.top = floorf(rect.bottom - kRoundCornerRadius); 1712 1713 BRect roundCorner[2]; 1714 1715 switch (side) { 1716 case B_TOP_BORDER: 1717 roundCorner[0] = leftTopCorner; 1718 roundCorner[1] = rightTopCorner; 1719 1720 // draw the left top corner 1721 _DrawRoundCornerLeftTop(view, leftTopCorner, updateRect, base, 1722 edgeShadowColor, frameLightColor, bevelLightColor, 1723 fillGradient); 1724 // draw the right top corner 1725 _DrawRoundCornerRightTop(view, rightTopCorner, updateRect, base, 1726 edgeShadowColor, edgeLightColor, frameLightColor, 1727 frameShadowColor, bevelLightColor, bevelShadowColor, 1728 fillGradient); 1729 break; 1730 case B_BOTTOM_BORDER: 1731 roundCorner[0] = leftBottomCorner; 1732 roundCorner[1] = rightBottomCorner; 1733 1734 // draw the left bottom corner 1735 _DrawRoundCornerLeftBottom(view, leftBottomCorner, updateRect, base, 1736 edgeShadowColor, edgeLightColor, frameLightColor, 1737 frameShadowColor, bevelLightColor, bevelShadowColor, 1738 fillGradient); 1739 // draw the right bottom corner 1740 _DrawRoundCornerRightBottom(view, rightBottomCorner, updateRect, 1741 base, edgeLightColor, frameShadowColor, bevelShadowColor, 1742 fillGradient); 1743 break; 1744 case B_LEFT_BORDER: 1745 roundCorner[0] = leftTopCorner; 1746 roundCorner[1] = leftBottomCorner; 1747 1748 // draw the left top corner 1749 _DrawRoundCornerLeftTop(view, leftTopCorner, updateRect, base, 1750 edgeShadowColor, frameLightColor, bevelLightColor, 1751 fillGradient); 1752 // draw the left bottom corner 1753 _DrawRoundCornerLeftBottom(view, leftBottomCorner, updateRect, base, 1754 edgeShadowColor, edgeLightColor, frameLightColor, 1755 frameShadowColor, bevelLightColor, bevelShadowColor, 1756 fillGradient); 1757 break; 1758 case B_RIGHT_BORDER: 1759 roundCorner[0] = rightTopCorner; 1760 roundCorner[1] = rightBottomCorner; 1761 1762 // draw the right top corner 1763 _DrawRoundCornerRightTop(view, rightTopCorner, updateRect, base, 1764 edgeShadowColor, edgeLightColor, frameLightColor, 1765 frameShadowColor, bevelLightColor, bevelShadowColor, 1766 fillGradient); 1767 // draw the right bottom corner 1768 _DrawRoundCornerRightBottom(view, rightBottomCorner, updateRect, 1769 base, edgeLightColor, frameShadowColor, bevelShadowColor, 1770 fillGradient); 1771 break; 1772 } 1773 1774 // clip out the corners 1775 view->ClipToInverseRect(roundCorner[0]); 1776 view->ClipToInverseRect(roundCorner[1]); 1777 1778 uint32 bordersToDraw = 0; 1779 switch (side) { 1780 case B_TOP_BORDER: 1781 bordersToDraw = (B_LEFT_BORDER | B_TOP_BORDER | B_RIGHT_BORDER); 1782 break; 1783 case B_BOTTOM_BORDER: 1784 bordersToDraw = (B_LEFT_BORDER | B_BOTTOM_BORDER | B_RIGHT_BORDER); 1785 break; 1786 case B_LEFT_BORDER: 1787 bordersToDraw = (B_LEFT_BORDER | B_BOTTOM_BORDER | B_TOP_BORDER); 1788 break; 1789 case B_RIGHT_BORDER: 1790 bordersToDraw = (B_RIGHT_BORDER | B_BOTTOM_BORDER | B_TOP_BORDER); 1791 break; 1792 } 1793 1794 // draw the rest of frame and fill 1795 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, edgeLightColor, 1796 edgeLightColor, borders); 1797 if (side == B_TOP_BORDER || side == B_BOTTOM_BORDER) { 1798 if ((borders & B_LEFT_BORDER) == 0) 1799 rect.left++; 1800 if ((borders & B_RIGHT_BORDER) == 0) 1801 rect.right--; 1802 } else if (side == B_LEFT_BORDER || side == B_RIGHT_BORDER) { 1803 if ((borders & B_TOP_BORDER) == 0) 1804 rect.top++; 1805 if ((borders & B_BOTTOM_BORDER) == 0) 1806 rect.bottom--; 1807 } 1808 1809 _DrawFrame(view, rect, frameLightColor, frameLightColor, frameShadowColor, 1810 frameShadowColor, bordersToDraw); 1811 1812 _DrawFrame(view, rect, bevelLightColor, bevelLightColor, bevelShadowColor, 1813 bevelShadowColor); 1814 1815 view->FillRect(rect, fillGradient); 1816 1817 // restore the clipping constraints of the view 1818 view->PopState(); 1819 } 1820 1821 1822 void 1823 HaikuControlLook::DrawInactiveTab(BView* view, BRect& rect, 1824 const BRect& updateRect, const rgb_color& base, uint32 flags, 1825 uint32 borders, uint32 side, int32, int32, int32, int32) 1826 { 1827 if (!ShouldDraw(view, rect, updateRect)) 1828 return; 1829 1830 rgb_color edgeShadowColor; 1831 rgb_color edgeLightColor; 1832 rgb_color frameShadowColor; 1833 rgb_color frameLightColor; 1834 rgb_color bevelShadowColor; 1835 rgb_color bevelLightColor; 1836 BGradientLinear fillGradient; 1837 fillGradient.SetStart(rect.LeftTop() + BPoint(3, 3)); 1838 fillGradient.SetEnd(rect.LeftBottom() + BPoint(3, -3)); 1839 1840 if ((flags & B_DISABLED) != 0) { 1841 edgeLightColor = base; 1842 edgeShadowColor = base; 1843 frameLightColor = tint_color(base, 1.25); 1844 frameShadowColor = tint_color(base, 1.30); 1845 bevelLightColor = tint_color(base, 0.8); 1846 bevelShadowColor = tint_color(base, 1.07); 1847 fillGradient.AddColor(tint_color(base, 0.85), 0); 1848 fillGradient.AddColor(base, 255); 1849 } else { 1850 edgeLightColor = tint_color(base, 0.80); 1851 edgeShadowColor = tint_color(base, 1.03); 1852 frameLightColor = tint_color(base, 1.30); 1853 frameShadowColor = tint_color(base, 1.30); 1854 bevelLightColor = tint_color(base, 1.10); 1855 bevelShadowColor = tint_color(base, 1.17); 1856 fillGradient.AddColor(tint_color(base, 1.12), 0); 1857 fillGradient.AddColor(tint_color(base, 1.08), 255); 1858 } 1859 1860 BRect background = rect; 1861 bool isVertical; 1862 switch (side) { 1863 default: 1864 case BTabView::kTopSide: 1865 rect.top += 4; 1866 background.bottom = rect.top; 1867 isVertical = false; 1868 break; 1869 1870 case BTabView::kBottomSide: 1871 rect.bottom -= 4; 1872 background.top = rect.bottom; 1873 isVertical = false; 1874 break; 1875 1876 case BTabView::kLeftSide: 1877 rect.left += 4; 1878 background.right = rect.left; 1879 isVertical = true; 1880 break; 1881 1882 case BTabView::kRightSide: 1883 rect.right -= 4; 1884 background.left = rect.right; 1885 isVertical = true; 1886 break; 1887 } 1888 1889 // active tabs stand out at the top, but this is an inactive tab 1890 view->SetHighColor(base); 1891 view->FillRect(background); 1892 1893 // frame and fill 1894 // Note that _DrawFrame also insets the rect, so each of the calls here 1895 // operate on a smaller rect than the previous ones 1896 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, edgeLightColor, 1897 edgeLightColor, borders); 1898 1899 _DrawFrame(view, rect, frameLightColor, frameLightColor, frameShadowColor, 1900 frameShadowColor, borders); 1901 1902 if (rect.IsValid()) { 1903 if (isVertical) { 1904 _DrawFrame(view, rect, bevelShadowColor, bevelShadowColor, 1905 bevelLightColor, bevelLightColor, B_TOP_BORDER & ~borders); 1906 } else { 1907 _DrawFrame(view, rect, bevelShadowColor, bevelShadowColor, 1908 bevelLightColor, bevelLightColor, B_LEFT_BORDER & ~borders); 1909 } 1910 } else { 1911 if (isVertical) { 1912 if ((B_LEFT_BORDER & ~borders) != 0) 1913 rect.left++; 1914 } else { 1915 if ((B_TOP_BORDER & ~borders) != 0) 1916 rect.top++; 1917 } 1918 } 1919 1920 view->FillRect(rect, fillGradient); 1921 } 1922 1923 1924 void 1925 HaikuControlLook::DrawSplitter(BView* view, BRect& rect, const BRect& updateRect, 1926 const rgb_color& base, orientation orientation, uint32 flags, 1927 uint32 borders) 1928 { 1929 if (!ShouldDraw(view, rect, updateRect)) 1930 return; 1931 1932 rgb_color background; 1933 if ((flags & (B_CLICKED | B_ACTIVATED)) != 0) 1934 background = tint_color(base, B_DARKEN_1_TINT); 1935 else 1936 background = base; 1937 1938 rgb_color light = tint_color(background, 0.6); 1939 rgb_color shadow = tint_color(background, 1.21); 1940 1941 // frame 1942 if (borders != 0 && rect.Width() > 3 && rect.Height() > 3) 1943 DrawRaisedBorder(view, rect, updateRect, background, flags, borders); 1944 1945 // dots and rest of background 1946 if (orientation == B_HORIZONTAL) { 1947 if (rect.Width() > 2) { 1948 // background on left/right 1949 BRegion region(rect); 1950 rect.left = floorf((rect.left + rect.right) / 2.0 - 0.5); 1951 rect.right = rect.left + 1; 1952 region.Exclude(rect); 1953 view->SetHighColor(background); 1954 view->FillRegion(®ion); 1955 } 1956 1957 BPoint dot = rect.LeftTop(); 1958 BPoint stop = rect.LeftBottom(); 1959 int32 num = 1; 1960 while (dot.y <= stop.y) { 1961 rgb_color col1; 1962 rgb_color col2; 1963 switch (num) { 1964 case 1: 1965 col1 = background; 1966 col2 = background; 1967 break; 1968 case 2: 1969 col1 = shadow; 1970 col2 = background; 1971 break; 1972 case 3: 1973 default: 1974 col1 = background; 1975 col2 = light; 1976 num = 0; 1977 break; 1978 } 1979 view->SetHighColor(col1); 1980 view->StrokeLine(dot, dot, B_SOLID_HIGH); 1981 view->SetHighColor(col2); 1982 dot.x++; 1983 view->StrokeLine(dot, dot, B_SOLID_HIGH); 1984 dot.x -= 1.0; 1985 // next pixel 1986 num++; 1987 dot.y++; 1988 } 1989 } else { 1990 if (rect.Height() > 2) { 1991 // background on left/right 1992 BRegion region(rect); 1993 rect.top = floorf((rect.top + rect.bottom) / 2.0 - 0.5); 1994 rect.bottom = rect.top + 1; 1995 region.Exclude(rect); 1996 view->SetHighColor(background); 1997 view->FillRegion(®ion); 1998 } 1999 2000 BPoint dot = rect.LeftTop(); 2001 BPoint stop = rect.RightTop(); 2002 int32 num = 1; 2003 while (dot.x <= stop.x) { 2004 rgb_color col1; 2005 rgb_color col2; 2006 switch (num) { 2007 case 1: 2008 col1 = background; 2009 col2 = background; 2010 break; 2011 case 2: 2012 col1 = shadow; 2013 col2 = background; 2014 break; 2015 case 3: 2016 default: 2017 col1 = background; 2018 col2 = light; 2019 num = 0; 2020 break; 2021 } 2022 view->SetHighColor(col1); 2023 view->StrokeLine(dot, dot, B_SOLID_HIGH); 2024 view->SetHighColor(col2); 2025 dot.y++; 2026 view->StrokeLine(dot, dot, B_SOLID_HIGH); 2027 dot.y -= 1.0; 2028 // next pixel 2029 num++; 2030 dot.x++; 2031 } 2032 } 2033 } 2034 2035 2036 // #pragma mark - 2037 2038 2039 void 2040 HaikuControlLook::DrawBorder(BView* view, BRect& rect, const BRect& updateRect, 2041 const rgb_color& base, border_style borderStyle, uint32 flags, 2042 uint32 borders) 2043 { 2044 if (borderStyle == B_NO_BORDER) 2045 return; 2046 2047 rgb_color scrollbarFrameColor = tint_color(base, B_DARKEN_2_TINT); 2048 if (base.red + base.green + base.blue <= 128 * 3) { 2049 scrollbarFrameColor = tint_color(base, B_LIGHTEN_1_TINT); 2050 } 2051 2052 if ((flags & B_FOCUSED) != 0) 2053 scrollbarFrameColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 2054 2055 if (borderStyle == B_FANCY_BORDER) 2056 _DrawOuterResessedFrame(view, rect, base, 1.0, 1.0, flags, borders); 2057 2058 _DrawFrame(view, rect, scrollbarFrameColor, scrollbarFrameColor, 2059 scrollbarFrameColor, scrollbarFrameColor, borders); 2060 } 2061 2062 2063 void 2064 HaikuControlLook::DrawRaisedBorder(BView* view, BRect& rect, 2065 const BRect& updateRect, const rgb_color& base, uint32 flags, 2066 uint32 borders) 2067 { 2068 rgb_color lightColor; 2069 rgb_color shadowColor; 2070 2071 if ((flags & B_DISABLED) != 0) { 2072 lightColor = base; 2073 shadowColor = base; 2074 } else { 2075 lightColor = tint_color(base, 0.85); 2076 shadowColor = tint_color(base, 1.07); 2077 } 2078 2079 _DrawFrame(view, rect, lightColor, lightColor, shadowColor, shadowColor, 2080 borders); 2081 } 2082 2083 2084 void 2085 HaikuControlLook::DrawTextControlBorder(BView* view, BRect& rect, 2086 const BRect& updateRect, const rgb_color& base, uint32 flags, 2087 uint32 borders) 2088 { 2089 if (!ShouldDraw(view, rect, updateRect)) 2090 return; 2091 2092 rgb_color dark1BorderColor; 2093 rgb_color dark2BorderColor; 2094 rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 2095 rgb_color invalidColor = ui_color(B_FAILURE_COLOR); 2096 2097 if ((flags & B_DISABLED) != 0) { 2098 _DrawOuterResessedFrame(view, rect, base, 0.0, 1.0, flags, borders); 2099 2100 if ((flags & B_BLEND_FRAME) != 0) 2101 dark1BorderColor = (rgb_color){ 0, 0, 0, 40 }; 2102 else 2103 dark1BorderColor = tint_color(base, 1.15); 2104 dark2BorderColor = dark1BorderColor; 2105 } else if ((flags & B_CLICKED) != 0) { 2106 dark1BorderColor = tint_color(base, 1.50); 2107 dark2BorderColor = tint_color(base, 1.49); 2108 2109 // BCheckBox uses this to indicate the clicked state... 2110 _DrawFrame(view, rect, 2111 dark1BorderColor, dark1BorderColor, 2112 dark2BorderColor, dark2BorderColor); 2113 2114 dark2BorderColor = dark1BorderColor; 2115 } else { 2116 _DrawOuterResessedFrame(view, rect, base, 0.6, 1.0, flags, borders); 2117 2118 if ((flags & B_BLEND_FRAME) != 0) { 2119 dark1BorderColor = (rgb_color){ 0, 0, 0, 102 }; 2120 dark2BorderColor = (rgb_color){ 0, 0, 0, 97 }; 2121 } else { 2122 dark1BorderColor = tint_color(base, 1.40); 2123 dark2BorderColor = tint_color(base, 1.38); 2124 } 2125 } 2126 2127 if ((flags & B_DISABLED) == 0 && (flags & B_FOCUSED) != 0) { 2128 dark1BorderColor = navigationColor; 2129 dark2BorderColor = navigationColor; 2130 } 2131 2132 if ((flags & B_DISABLED) == 0 && (flags & B_INVALID) != 0) { 2133 dark1BorderColor = invalidColor; 2134 dark2BorderColor = invalidColor; 2135 } 2136 2137 if ((flags & B_BLEND_FRAME) != 0) { 2138 drawing_mode oldMode = view->DrawingMode(); 2139 view->SetDrawingMode(B_OP_ALPHA); 2140 2141 _DrawFrame(view, rect, 2142 dark1BorderColor, dark1BorderColor, 2143 dark2BorderColor, dark2BorderColor, borders); 2144 2145 view->SetDrawingMode(oldMode); 2146 } else { 2147 _DrawFrame(view, rect, 2148 dark1BorderColor, dark1BorderColor, 2149 dark2BorderColor, dark2BorderColor, borders); 2150 } 2151 } 2152 2153 2154 void 2155 HaikuControlLook::DrawGroupFrame(BView* view, BRect& rect, const BRect& updateRect, 2156 const rgb_color& base, uint32 borders) 2157 { 2158 rgb_color frameColor = tint_color(base, 1.30); 2159 rgb_color bevelLight = tint_color(base, 0.8); 2160 rgb_color bevelShadow = tint_color(base, 1.03); 2161 2162 _DrawFrame(view, rect, bevelShadow, bevelShadow, bevelLight, bevelLight, 2163 borders); 2164 2165 _DrawFrame(view, rect, frameColor, frameColor, frameColor, frameColor, 2166 borders); 2167 2168 _DrawFrame(view, rect, bevelLight, bevelLight, bevelShadow, bevelShadow, 2169 borders); 2170 } 2171 2172 2173 void 2174 HaikuControlLook::DrawLabel(BView* view, const char* label, BRect rect, 2175 const BRect& updateRect, const rgb_color& base, uint32 flags, 2176 const rgb_color* textColor) 2177 { 2178 DrawLabel(view, label, NULL, rect, updateRect, base, flags, 2179 DefaultLabelAlignment(), textColor); 2180 } 2181 2182 2183 void 2184 HaikuControlLook::DrawLabel(BView* view, const char* label, BRect rect, 2185 const BRect& updateRect, const rgb_color& base, uint32 flags, 2186 const BAlignment& alignment, const rgb_color* textColor) 2187 { 2188 DrawLabel(view, label, NULL, rect, updateRect, base, flags, alignment, 2189 textColor); 2190 } 2191 2192 2193 void 2194 HaikuControlLook::DrawLabel(BView* view, const char* label, const rgb_color& base, 2195 uint32 flags, const BPoint& where, const rgb_color* textColor) 2196 { 2197 // setup the text color 2198 2199 BWindow* window = view->Window(); 2200 bool isDesktop = window 2201 && window->Feel() == kDesktopWindowFeel 2202 && window->Look() == kDesktopWindowLook 2203 && view->Parent() 2204 && view->Parent()->Parent() == NULL 2205 && (flags & B_IGNORE_OUTLINE) == 0; 2206 2207 rgb_color low; 2208 rgb_color color; 2209 rgb_color glowColor; 2210 2211 if (textColor != NULL) 2212 glowColor = *textColor; 2213 else if ((flags & B_IS_CONTROL) != 0) 2214 glowColor = ui_color(B_CONTROL_TEXT_COLOR); 2215 else 2216 glowColor = ui_color(B_PANEL_TEXT_COLOR); 2217 2218 color = glowColor; 2219 2220 if (isDesktop) 2221 low = view->Parent()->ViewColor(); 2222 else 2223 low = base; 2224 2225 if ((flags & B_DISABLED) != 0) { 2226 color.red = (uint8)(((int32)low.red + color.red + 1) / 2); 2227 color.green = (uint8)(((int32)low.green + color.green + 1) / 2); 2228 color.blue = (uint8)(((int32)low.blue + color.blue + 1) / 2); 2229 } 2230 2231 drawing_mode oldMode = view->DrawingMode(); 2232 2233 if (isDesktop) { 2234 // enforce proper use of desktop label colors 2235 if (low.Brightness() < 100) { 2236 if (textColor == NULL) 2237 color = make_color(255, 255, 255); 2238 2239 glowColor = make_color(0, 0, 0); 2240 } else { 2241 if (textColor == NULL) 2242 color = make_color(0, 0, 0); 2243 2244 glowColor = make_color(255, 255, 255); 2245 } 2246 2247 // drawing occurs on the desktop 2248 if (fCachedWorkspace != current_workspace()) { 2249 int8 indice = 0; 2250 int32 mask; 2251 bool tmpOutline; 2252 while (fBackgroundInfo.FindInt32("be:bgndimginfoworkspaces", 2253 indice, &mask) == B_OK 2254 && fBackgroundInfo.FindBool("be:bgndimginfoerasetext", 2255 indice, &tmpOutline) == B_OK) { 2256 2257 if (((1 << current_workspace()) & mask) != 0) { 2258 fCachedOutline = tmpOutline; 2259 fCachedWorkspace = current_workspace(); 2260 break; 2261 } 2262 indice++; 2263 } 2264 } 2265 2266 if (fCachedOutline) { 2267 BFont font; 2268 view->GetFont(&font); 2269 2270 view->SetDrawingMode(B_OP_ALPHA); 2271 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY); 2272 // Draw glow or outline 2273 if (glowColor.Brightness() > 128) { 2274 font.SetFalseBoldWidth(2.0); 2275 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2276 2277 glowColor.alpha = 30; 2278 view->SetHighColor(glowColor); 2279 view->DrawString(label, where); 2280 2281 font.SetFalseBoldWidth(1.0); 2282 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2283 2284 glowColor.alpha = 65; 2285 view->SetHighColor(glowColor); 2286 view->DrawString(label, where); 2287 2288 font.SetFalseBoldWidth(0.0); 2289 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2290 } else { 2291 font.SetFalseBoldWidth(1.0); 2292 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2293 2294 glowColor.alpha = 30; 2295 view->SetHighColor(glowColor); 2296 view->DrawString(label, where); 2297 2298 font.SetFalseBoldWidth(0.0); 2299 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2300 2301 glowColor.alpha = 200; 2302 view->SetHighColor(glowColor); 2303 view->DrawString(label, BPoint(where.x + 1, where.y + 1)); 2304 } 2305 } 2306 } 2307 2308 view->SetHighColor(color); 2309 view->SetDrawingMode(B_OP_OVER); 2310 view->DrawString(label, where); 2311 view->SetDrawingMode(oldMode); 2312 } 2313 2314 2315 void 2316 HaikuControlLook::DrawLabel(BView* view, const char* label, const BBitmap* icon, 2317 BRect rect, const BRect& updateRect, const rgb_color& base, uint32 flags, 2318 const BAlignment& alignment, const rgb_color* textColor) 2319 { 2320 if (!ShouldDraw(view, rect, updateRect)) 2321 return; 2322 2323 if (label == NULL && icon == NULL) 2324 return; 2325 2326 if (label == NULL) { 2327 // icon only 2328 BRect alignedRect = BLayoutUtils::AlignInFrame(rect, 2329 icon->Bounds().Size(), alignment); 2330 drawing_mode oldMode = view->DrawingMode(); 2331 view->SetDrawingMode(B_OP_OVER); 2332 view->DrawBitmap(icon, alignedRect.LeftTop()); 2333 view->SetDrawingMode(oldMode); 2334 return; 2335 } 2336 2337 // label, possibly with icon 2338 float availableWidth = rect.Width() + 1; 2339 float width = 0; 2340 float textOffset = 0; 2341 float height = 0; 2342 2343 if (icon != NULL) { 2344 width = icon->Bounds().Width() + DefaultLabelSpacing() + 1; 2345 height = icon->Bounds().Height() + 1; 2346 textOffset = width; 2347 availableWidth -= textOffset; 2348 } 2349 2350 // truncate the label if necessary and get the width and height 2351 BString truncatedLabel(label); 2352 2353 BFont font; 2354 view->GetFont(&font); 2355 2356 font.TruncateString(&truncatedLabel, B_TRUNCATE_END, availableWidth); 2357 width += ceilf(font.StringWidth(truncatedLabel.String())); 2358 2359 font_height fontHeight; 2360 font.GetHeight(&fontHeight); 2361 float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); 2362 height = std::max(height, textHeight); 2363 2364 // handle alignment 2365 BRect alignedRect(BLayoutUtils::AlignOnRect(rect, 2366 BSize(width - 1, height - 1), alignment)); 2367 2368 if (icon != NULL) { 2369 BPoint location(alignedRect.LeftTop()); 2370 if (icon->Bounds().Height() + 1 < height) 2371 location.y += ceilf((height - icon->Bounds().Height() - 1) / 2); 2372 2373 drawing_mode oldMode = view->DrawingMode(); 2374 view->SetDrawingMode(B_OP_OVER); 2375 view->DrawBitmap(icon, location); 2376 view->SetDrawingMode(oldMode); 2377 } 2378 2379 BPoint location(alignedRect.left + textOffset, 2380 alignedRect.top + ceilf(fontHeight.ascent)); 2381 if (textHeight < height) 2382 location.y += ceilf((height - textHeight) / 2); 2383 2384 DrawLabel(view, truncatedLabel.String(), base, flags, location, textColor); 2385 } 2386 2387 2388 void 2389 HaikuControlLook::GetFrameInsets(frame_type frameType, uint32 flags, float& _left, 2390 float& _top, float& _right, float& _bottom) 2391 { 2392 // All frames have the same inset on each side. 2393 float inset = 0; 2394 2395 switch (frameType) { 2396 case B_BUTTON_FRAME: 2397 inset = (flags & B_DEFAULT_BUTTON) != 0 ? 5 : 2; 2398 break; 2399 case B_GROUP_FRAME: 2400 case B_MENU_FIELD_FRAME: 2401 inset = 3; 2402 break; 2403 case B_SCROLL_VIEW_FRAME: 2404 case B_TEXT_CONTROL_FRAME: 2405 inset = 2; 2406 break; 2407 } 2408 2409 inset = ceilf(inset * (be_plain_font->Size() / 12.0f)); 2410 2411 _left = inset; 2412 _top = inset; 2413 _right = inset; 2414 _bottom = inset; 2415 } 2416 2417 2418 void 2419 HaikuControlLook::GetBackgroundInsets(background_type backgroundType, 2420 uint32 flags, float& _left, float& _top, float& _right, float& _bottom) 2421 { 2422 // Most backgrounds have the same inset on each side. 2423 float inset = 0; 2424 2425 switch (backgroundType) { 2426 case B_BUTTON_BACKGROUND: 2427 case B_MENU_BACKGROUND: 2428 case B_MENU_BAR_BACKGROUND: 2429 case B_MENU_FIELD_BACKGROUND: 2430 case B_MENU_ITEM_BACKGROUND: 2431 inset = 1; 2432 break; 2433 case B_BUTTON_WITH_POP_UP_BACKGROUND: 2434 _left = 1; 2435 _top = 1; 2436 _right = 1 + ComposeSpacing(kButtonPopUpIndicatorWidth); 2437 _bottom = 1; 2438 return; 2439 case B_HORIZONTAL_SCROLL_BAR_BACKGROUND: 2440 _left = 2; 2441 _top = 0; 2442 _right = 1; 2443 _bottom = 0; 2444 return; 2445 case B_VERTICAL_SCROLL_BAR_BACKGROUND: 2446 _left = 0; 2447 _top = 2; 2448 _right = 0; 2449 _bottom = 1; 2450 return; 2451 } 2452 2453 _left = inset; 2454 _top = inset; 2455 _right = inset; 2456 _bottom = inset; 2457 } 2458 2459 2460 void 2461 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect, 2462 const BRect& updateRect, const rgb_color& base, uint32 flags, 2463 uint32 borders, orientation orientation) 2464 { 2465 _DrawButtonBackground(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f, 2466 base, true, flags, borders, orientation); 2467 } 2468 2469 2470 void 2471 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect, 2472 const BRect& updateRect, float radius, const rgb_color& base, uint32 flags, 2473 uint32 borders, orientation orientation) 2474 { 2475 _DrawButtonBackground(view, rect, updateRect, radius, radius, radius, 2476 radius, base, true, flags, borders, orientation); 2477 } 2478 2479 2480 void 2481 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect, 2482 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 2483 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 2484 uint32 flags, uint32 borders, orientation orientation) 2485 { 2486 _DrawButtonBackground(view, rect, updateRect, leftTopRadius, 2487 rightTopRadius, leftBottomRadius, rightBottomRadius, base, true, flags, 2488 borders, orientation); 2489 } 2490 2491 2492 // #pragma mark - 2493 2494 2495 void 2496 HaikuControlLook::_DrawButtonFrame(BView* view, BRect& rect, 2497 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 2498 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 2499 const rgb_color& background, float contrast, float brightness, 2500 uint32 flags, uint32 borders) 2501 { 2502 if (!rect.IsValid()) 2503 return; 2504 2505 // save the clipping constraints of the view 2506 view->PushState(); 2507 2508 // set clipping constraints to rect 2509 view->ClipToRect(rect); 2510 2511 // If the button is flat and neither activated nor otherwise highlighted 2512 // (mouse hovering or focussed), draw it flat. 2513 if ((flags & B_FLAT) != 0 2514 && (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0 2515 && ((flags & (B_HOVER | B_FOCUSED)) == 0 2516 || (flags & B_DISABLED) != 0)) { 2517 _DrawFrame(view, rect, background, background, background, 2518 background, borders); 2519 _DrawFrame(view, rect, background, background, background, 2520 background, borders); 2521 view->PopState(); 2522 return; 2523 } 2524 2525 // outer edge colors 2526 rgb_color edgeLightColor; 2527 rgb_color edgeShadowColor; 2528 2529 // default button frame color 2530 rgb_color defaultIndicatorColor = ui_color(B_CONTROL_BORDER_COLOR); 2531 rgb_color cornerBgColor; 2532 2533 if ((flags & B_DISABLED) != 0) { 2534 defaultIndicatorColor = disable_color(defaultIndicatorColor, 2535 background); 2536 } 2537 2538 drawing_mode oldMode = view->DrawingMode(); 2539 2540 if ((flags & B_DEFAULT_BUTTON) != 0) { 2541 cornerBgColor = defaultIndicatorColor; 2542 edgeLightColor = _EdgeLightColor(defaultIndicatorColor, 2543 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8), 2544 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags); 2545 edgeShadowColor = _EdgeShadowColor(defaultIndicatorColor, 2546 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8), 2547 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags); 2548 2549 // draw default button indicator 2550 // Allow a 1-pixel border of the background to come through. 2551 rect.InsetBy(1, 1); 2552 2553 view->SetHighColor(defaultIndicatorColor); 2554 view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius); 2555 rect.InsetBy(1, 1); 2556 2557 view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius); 2558 rect.InsetBy(1, 1); 2559 } else { 2560 cornerBgColor = background; 2561 if ((flags & B_BLEND_FRAME) != 0) { 2562 // set the background color to transparent for the case 2563 // that we are on the desktop 2564 cornerBgColor.alpha = 0; 2565 view->SetDrawingMode(B_OP_ALPHA); 2566 } 2567 2568 edgeLightColor = _EdgeLightColor(background, 2569 contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0), 2570 brightness * 1.0, flags); 2571 edgeShadowColor = _EdgeShadowColor(background, 2572 contrast * (flags & B_DISABLED) != 0 ? 0.0 : 1.0, 2573 brightness * 1.0, flags); 2574 } 2575 2576 // frame colors 2577 rgb_color frameLightColor = _FrameLightColor(base, flags); 2578 rgb_color frameShadowColor = _FrameShadowColor(base, flags); 2579 2580 // rounded corners 2581 2582 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0 2583 && leftTopRadius > 0) { 2584 // draw left top rounded corner 2585 BRect leftTopCorner(floorf(rect.left), floorf(rect.top), 2586 floorf(rect.left + leftTopRadius), 2587 floorf(rect.top + leftTopRadius)); 2588 BRect cornerRect(leftTopCorner); 2589 _DrawRoundCornerFrameLeftTop(view, leftTopCorner, updateRect, 2590 cornerBgColor, edgeShadowColor, frameLightColor); 2591 view->ClipToInverseRect(cornerRect); 2592 } 2593 2594 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0 2595 && rightTopRadius > 0) { 2596 // draw right top rounded corner 2597 BRect rightTopCorner(floorf(rect.right - rightTopRadius), 2598 floorf(rect.top), floorf(rect.right), 2599 floorf(rect.top + rightTopRadius)); 2600 BRect cornerRect(rightTopCorner); 2601 _DrawRoundCornerFrameRightTop(view, rightTopCorner, updateRect, 2602 cornerBgColor, edgeShadowColor, edgeLightColor, 2603 frameLightColor, frameShadowColor); 2604 view->ClipToInverseRect(cornerRect); 2605 } 2606 2607 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2608 && leftBottomRadius > 0) { 2609 // draw left bottom rounded corner 2610 BRect leftBottomCorner(floorf(rect.left), 2611 floorf(rect.bottom - leftBottomRadius), 2612 floorf(rect.left + leftBottomRadius), floorf(rect.bottom)); 2613 BRect cornerRect(leftBottomCorner); 2614 _DrawRoundCornerFrameLeftBottom(view, leftBottomCorner, updateRect, 2615 cornerBgColor, edgeShadowColor, edgeLightColor, 2616 frameLightColor, frameShadowColor); 2617 view->ClipToInverseRect(cornerRect); 2618 } 2619 2620 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2621 && rightBottomRadius > 0) { 2622 // draw right bottom rounded corner 2623 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius), 2624 floorf(rect.bottom - rightBottomRadius), floorf(rect.right), 2625 floorf(rect.bottom)); 2626 BRect cornerRect(rightBottomCorner); 2627 _DrawRoundCornerFrameRightBottom(view, rightBottomCorner, 2628 updateRect, cornerBgColor, edgeLightColor, frameShadowColor); 2629 view->ClipToInverseRect(cornerRect); 2630 } 2631 2632 // draw outer edge 2633 if ((flags & B_DEFAULT_BUTTON) != 0) { 2634 _DrawOuterResessedFrame(view, rect, defaultIndicatorColor, 2635 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8), 2636 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), 2637 flags, borders); 2638 } else { 2639 _DrawOuterResessedFrame(view, rect, background, 2640 contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0), 2641 brightness * 1.0, flags, borders); 2642 } 2643 2644 view->SetDrawingMode(oldMode); 2645 2646 // draw frame 2647 if ((flags & B_BLEND_FRAME) != 0) { 2648 drawing_mode oldDrawingMode = view->DrawingMode(); 2649 view->SetDrawingMode(B_OP_ALPHA); 2650 2651 _DrawFrame(view, rect, frameLightColor, frameLightColor, 2652 frameShadowColor, frameShadowColor, borders); 2653 2654 view->SetDrawingMode(oldDrawingMode); 2655 } else { 2656 _DrawFrame(view, rect, frameLightColor, frameLightColor, 2657 frameShadowColor, frameShadowColor, borders); 2658 } 2659 2660 // restore the clipping constraints of the view 2661 view->PopState(); 2662 } 2663 2664 2665 void 2666 HaikuControlLook::_DrawOuterResessedFrame(BView* view, BRect& rect, 2667 const rgb_color& base, float contrast, float brightness, uint32 flags, 2668 uint32 borders) 2669 { 2670 rgb_color edgeLightColor = _EdgeLightColor(base, contrast, 2671 brightness, flags); 2672 rgb_color edgeShadowColor = _EdgeShadowColor(base, contrast, 2673 brightness, flags); 2674 2675 if ((flags & B_BLEND_FRAME) != 0) { 2676 // assumes the background has already been painted 2677 drawing_mode oldDrawingMode = view->DrawingMode(); 2678 view->SetDrawingMode(B_OP_ALPHA); 2679 2680 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, 2681 edgeLightColor, edgeLightColor, borders); 2682 2683 view->SetDrawingMode(oldDrawingMode); 2684 } else { 2685 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, 2686 edgeLightColor, edgeLightColor, borders); 2687 } 2688 } 2689 2690 2691 void 2692 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left, 2693 const rgb_color& top, const rgb_color& right, const rgb_color& bottom, 2694 uint32 borders) 2695 { 2696 view->BeginLineArray(4); 2697 2698 if (borders & B_LEFT_BORDER) { 2699 view->AddLine( 2700 BPoint(rect.left, rect.bottom), 2701 BPoint(rect.left, rect.top), left); 2702 rect.left++; 2703 } 2704 if (borders & B_TOP_BORDER) { 2705 view->AddLine( 2706 BPoint(rect.left, rect.top), 2707 BPoint(rect.right, rect.top), top); 2708 rect.top++; 2709 } 2710 if (borders & B_RIGHT_BORDER) { 2711 view->AddLine( 2712 BPoint(rect.right, rect.top), 2713 BPoint(rect.right, rect.bottom), right); 2714 rect.right--; 2715 } 2716 if (borders & B_BOTTOM_BORDER) { 2717 view->AddLine( 2718 BPoint(rect.left, rect.bottom), 2719 BPoint(rect.right, rect.bottom), bottom); 2720 rect.bottom--; 2721 } 2722 2723 view->EndLineArray(); 2724 } 2725 2726 2727 void 2728 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left, 2729 const rgb_color& top, const rgb_color& right, const rgb_color& bottom, 2730 const rgb_color& rightTop, const rgb_color& leftBottom, uint32 borders) 2731 { 2732 view->BeginLineArray(6); 2733 2734 if (borders & B_TOP_BORDER) { 2735 if (borders & B_RIGHT_BORDER) { 2736 view->AddLine( 2737 BPoint(rect.left, rect.top), 2738 BPoint(rect.right - 1, rect.top), top); 2739 view->AddLine( 2740 BPoint(rect.right, rect.top), 2741 BPoint(rect.right, rect.top), rightTop); 2742 } else { 2743 view->AddLine( 2744 BPoint(rect.left, rect.top), 2745 BPoint(rect.right, rect.top), top); 2746 } 2747 rect.top++; 2748 } 2749 2750 if (borders & B_LEFT_BORDER) { 2751 view->AddLine( 2752 BPoint(rect.left, rect.top), 2753 BPoint(rect.left, rect.bottom - 1), left); 2754 view->AddLine( 2755 BPoint(rect.left, rect.bottom), 2756 BPoint(rect.left, rect.bottom), leftBottom); 2757 rect.left++; 2758 } 2759 2760 if (borders & B_BOTTOM_BORDER) { 2761 view->AddLine( 2762 BPoint(rect.left, rect.bottom), 2763 BPoint(rect.right, rect.bottom), bottom); 2764 rect.bottom--; 2765 } 2766 2767 if (borders & B_RIGHT_BORDER) { 2768 view->AddLine( 2769 BPoint(rect.right, rect.bottom), 2770 BPoint(rect.right, rect.top), right); 2771 rect.right--; 2772 } 2773 2774 view->EndLineArray(); 2775 } 2776 2777 2778 void 2779 HaikuControlLook::_DrawButtonBackground(BView* view, BRect& rect, 2780 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 2781 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 2782 bool popupIndicator, uint32 flags, uint32 borders, orientation orientation) 2783 { 2784 if (!rect.IsValid()) 2785 return; 2786 2787 // save the clipping constraints of the view 2788 view->PushState(); 2789 2790 // set clipping constraints to rect 2791 view->ClipToRect(rect); 2792 2793 // If the button is flat and neither activated nor otherwise highlighted 2794 // (mouse hovering or focussed), draw it flat. 2795 if ((flags & B_FLAT) != 0 2796 && (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0 2797 && ((flags & (B_HOVER | B_FOCUSED)) == 0 2798 || (flags & B_DISABLED) != 0)) { 2799 _DrawFlatButtonBackground(view, rect, updateRect, base, popupIndicator, 2800 flags, borders, orientation); 2801 } else { 2802 BRegion clipping(rect); 2803 _DrawNonFlatButtonBackground(view, rect, updateRect, clipping, 2804 leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, 2805 base, popupIndicator, flags, borders, orientation); 2806 } 2807 2808 // restore the clipping constraints of the view 2809 view->PopState(); 2810 } 2811 2812 2813 void 2814 HaikuControlLook::_DrawFlatButtonBackground(BView* view, BRect& rect, 2815 const BRect& updateRect, const rgb_color& base, bool popupIndicator, 2816 uint32 flags, uint32 borders, orientation orientation) 2817 { 2818 _DrawFrame(view, rect, base, base, base, base, borders); 2819 // Not an actual frame, but the method insets our rect as needed. 2820 2821 view->SetHighColor(base); 2822 view->FillRect(rect); 2823 2824 if (popupIndicator) { 2825 BRect indicatorRect(rect); 2826 rect.right -= ComposeSpacing(kButtonPopUpIndicatorWidth); 2827 indicatorRect.left = rect.right + 3; 2828 // 2 pixels for the separator 2829 2830 view->SetHighColor(base); 2831 view->FillRect(indicatorRect); 2832 2833 _DrawPopUpMarker(view, indicatorRect, base, flags); 2834 } 2835 } 2836 2837 2838 void 2839 HaikuControlLook::_DrawNonFlatButtonBackground(BView* view, BRect& rect, 2840 const BRect& updateRect, BRegion& clipping, float leftTopRadius, 2841 float rightTopRadius, float leftBottomRadius, float rightBottomRadius, 2842 const rgb_color& base, bool popupIndicator, uint32 flags, uint32 borders, 2843 orientation orientation) 2844 { 2845 // inner bevel colors 2846 rgb_color bevelLightColor = _BevelLightColor(base, flags); 2847 rgb_color bevelShadowColor = _BevelShadowColor(base, flags); 2848 2849 // button background color 2850 rgb_color buttonBgColor; 2851 if ((flags & B_DISABLED) != 0) 2852 buttonBgColor = tint_color(base, 0.7); 2853 else 2854 buttonBgColor = tint_color(base, B_LIGHTEN_1_TINT); 2855 2856 // surface top gradient 2857 BGradientLinear fillGradient; 2858 _MakeButtonGradient(fillGradient, rect, base, flags, orientation); 2859 2860 // rounded corners 2861 2862 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0 2863 && leftTopRadius > 0) { 2864 // draw left top rounded corner 2865 BRect leftTopCorner(floorf(rect.left), floorf(rect.top), 2866 floorf(rect.left + leftTopRadius - 2.0), 2867 floorf(rect.top + leftTopRadius - 2.0)); 2868 clipping.Exclude(leftTopCorner); 2869 BRect cornerRect(leftTopCorner); 2870 _DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect, 2871 bevelLightColor, fillGradient); 2872 view->ClipToInverseRect(cornerRect); 2873 } 2874 2875 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0 2876 && rightTopRadius > 0) { 2877 // draw right top rounded corner 2878 BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0), 2879 floorf(rect.top), floorf(rect.right), 2880 floorf(rect.top + rightTopRadius - 2.0)); 2881 clipping.Exclude(rightTopCorner); 2882 BRect cornerRect(rightTopCorner); 2883 _DrawRoundCornerBackgroundRightTop(view, rightTopCorner, 2884 updateRect, bevelLightColor, bevelShadowColor, fillGradient); 2885 view->ClipToInverseRect(cornerRect); 2886 } 2887 2888 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2889 && leftBottomRadius > 0) { 2890 // draw left bottom rounded corner 2891 BRect leftBottomCorner(floorf(rect.left), 2892 floorf(rect.bottom - leftBottomRadius + 2.0), 2893 floorf(rect.left + leftBottomRadius - 2.0), 2894 floorf(rect.bottom)); 2895 clipping.Exclude(leftBottomCorner); 2896 BRect cornerRect(leftBottomCorner); 2897 _DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner, 2898 updateRect, bevelLightColor, bevelShadowColor, fillGradient); 2899 view->ClipToInverseRect(cornerRect); 2900 } 2901 2902 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2903 && rightBottomRadius > 0) { 2904 // draw right bottom rounded corner 2905 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0), 2906 floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right), 2907 floorf(rect.bottom)); 2908 clipping.Exclude(rightBottomCorner); 2909 BRect cornerRect(rightBottomCorner); 2910 _DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner, 2911 updateRect, bevelShadowColor, fillGradient); 2912 view->ClipToInverseRect(cornerRect); 2913 } 2914 2915 // draw inner bevel 2916 2917 if ((flags & B_ACTIVATED) != 0) { 2918 view->BeginLineArray(4); 2919 2920 // shadow along left/top borders 2921 if (borders & B_LEFT_BORDER) { 2922 view->AddLine(BPoint(rect.left, rect.top), 2923 BPoint(rect.left, rect.bottom), bevelLightColor); 2924 rect.left++; 2925 } 2926 if (borders & B_TOP_BORDER) { 2927 view->AddLine(BPoint(rect.left, rect.top), 2928 BPoint(rect.right, rect.top), bevelLightColor); 2929 rect.top++; 2930 } 2931 2932 // softer shadow along left/top borders 2933 if (borders & B_LEFT_BORDER) { 2934 view->AddLine(BPoint(rect.left, rect.top), 2935 BPoint(rect.left, rect.bottom), bevelShadowColor); 2936 rect.left++; 2937 } 2938 if (borders & B_TOP_BORDER) { 2939 view->AddLine(BPoint(rect.left, rect.top), 2940 BPoint(rect.right, rect.top), bevelShadowColor); 2941 rect.top++; 2942 } 2943 2944 view->EndLineArray(); 2945 } else { 2946 _DrawFrame(view, rect, 2947 bevelLightColor, bevelLightColor, 2948 bevelShadowColor, bevelShadowColor, 2949 buttonBgColor, buttonBgColor, borders); 2950 } 2951 2952 if (popupIndicator) { 2953 BRect indicatorRect(rect); 2954 rect.right -= ComposeSpacing(kButtonPopUpIndicatorWidth); 2955 indicatorRect.left = rect.right + 3; 2956 // 2 pixels for the separator 2957 2958 // Even when depressed we want the pop-up indicator background and 2959 // separator to cover the area up to the top. 2960 if ((flags & B_ACTIVATED) != 0) 2961 indicatorRect.top--; 2962 2963 // draw the separator 2964 rgb_color separatorBaseColor = base; 2965 if ((flags & B_ACTIVATED) != 0) 2966 separatorBaseColor = tint_color(base, B_DARKEN_1_TINT); 2967 2968 rgb_color separatorLightColor = _EdgeLightColor(separatorBaseColor, 2969 (flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags); 2970 rgb_color separatorShadowColor = _EdgeShadowColor(separatorBaseColor, 2971 (flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags); 2972 2973 view->BeginLineArray(2); 2974 2975 view->AddLine(BPoint(indicatorRect.left - 2, indicatorRect.top), 2976 BPoint(indicatorRect.left - 2, indicatorRect.bottom), 2977 separatorShadowColor); 2978 view->AddLine(BPoint(indicatorRect.left - 1, indicatorRect.top), 2979 BPoint(indicatorRect.left - 1, indicatorRect.bottom), 2980 separatorLightColor); 2981 2982 view->EndLineArray(); 2983 2984 // draw background and pop-up marker 2985 _DrawMenuFieldBackgroundInside(view, indicatorRect, updateRect, 2986 0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags, 0); 2987 2988 if ((flags & B_ACTIVATED) != 0) 2989 indicatorRect.top++; 2990 2991 _DrawPopUpMarker(view, indicatorRect, base, flags); 2992 } 2993 2994 // fill in the background 2995 view->FillRect(rect, fillGradient); 2996 } 2997 2998 2999 void 3000 HaikuControlLook::_DrawPopUpMarker(BView* view, const BRect& rect, 3001 const rgb_color& base, uint32 flags) 3002 { 3003 BPoint center(roundf((rect.left + rect.right) / 2.0), 3004 roundf((rect.top + rect.bottom) / 2.0)); 3005 const float metric = roundf(rect.Width() * 3.125f) / 10.0f, 3006 offset = ceilf((metric * 0.2f) * 10.0f) / 10.0f; 3007 BPoint triangle[3]; 3008 triangle[0] = center + BPoint(-metric, -offset); 3009 triangle[1] = center + BPoint(metric, -offset); 3010 triangle[2] = center + BPoint(0.0, metric * 0.8f); 3011 3012 const uint32 viewFlags = view->Flags(); 3013 view->SetFlags(viewFlags | B_SUBPIXEL_PRECISE); 3014 3015 rgb_color markColor; 3016 if ((flags & B_DISABLED) != 0) 3017 markColor = tint_color(base, 1.35); 3018 else 3019 markColor = tint_color(base, 1.65); 3020 3021 view->SetHighColor(markColor); 3022 view->FillTriangle(triangle[0], triangle[1], triangle[2]); 3023 3024 view->SetFlags(viewFlags); 3025 } 3026 3027 3028 void 3029 HaikuControlLook::_DrawMenuFieldBackgroundOutside(BView* view, BRect& rect, 3030 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 3031 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 3032 bool popupIndicator, uint32 flags) 3033 { 3034 if (!ShouldDraw(view, rect, updateRect)) 3035 return; 3036 3037 if (popupIndicator) { 3038 const float indicatorWidth = ComposeSpacing(kButtonPopUpIndicatorWidth); 3039 const float spacing = (indicatorWidth <= 11.0f) ? 1.0f : roundf(indicatorWidth / 11.0f); 3040 3041 BRect leftRect(rect); 3042 leftRect.right -= indicatorWidth - spacing; 3043 3044 BRect rightRect(rect); 3045 rightRect.left = rightRect.right - (indicatorWidth - spacing * 2); 3046 3047 _DrawMenuFieldBackgroundInside(view, leftRect, updateRect, 3048 leftTopRadius, 0.0f, leftBottomRadius, 0.0f, base, flags, 3049 B_LEFT_BORDER | B_TOP_BORDER | B_BOTTOM_BORDER); 3050 3051 _DrawMenuFieldBackgroundInside(view, rightRect, updateRect, 3052 0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags, 3053 B_TOP_BORDER | B_RIGHT_BORDER | B_BOTTOM_BORDER); 3054 3055 _DrawPopUpMarker(view, rightRect, base, flags); 3056 3057 // draw a line on the left of the popup frame 3058 rgb_color bevelShadowColor = _BevelShadowColor(base, flags); 3059 view->SetHighColor(bevelShadowColor); 3060 BPoint leftTopCorner(floorf(rightRect.left - spacing), 3061 floorf(rightRect.top - spacing)); 3062 BPoint leftBottomCorner(floorf(rightRect.left - spacing), 3063 floorf(rightRect.bottom + spacing)); 3064 for (float i = 0; i < spacing; i++) { 3065 view->StrokeLine(leftTopCorner + BPoint(i, 0), 3066 leftBottomCorner + BPoint(i, 0)); 3067 } 3068 3069 rect = leftRect; 3070 } else { 3071 _DrawMenuFieldBackgroundInside(view, rect, updateRect, leftTopRadius, 3072 rightTopRadius, leftBottomRadius, rightBottomRadius, base, flags); 3073 } 3074 } 3075 3076 3077 void 3078 HaikuControlLook::_DrawMenuFieldBackgroundInside(BView* view, BRect& rect, 3079 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 3080 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 3081 uint32 flags, uint32 borders) 3082 { 3083 if (!ShouldDraw(view, rect, updateRect)) 3084 return; 3085 3086 // save the clipping constraints of the view 3087 view->PushState(); 3088 3089 // set clipping constraints to rect 3090 view->ClipToRect(rect); 3091 3092 // frame colors 3093 rgb_color frameLightColor = _FrameLightColor(base, flags); 3094 rgb_color frameShadowColor = _FrameShadowColor(base, flags); 3095 3096 // indicator background color 3097 rgb_color indicatorBase; 3098 if ((borders & B_LEFT_BORDER) != 0) 3099 indicatorBase = base; 3100 else { 3101 if ((flags & B_DISABLED) != 0) 3102 indicatorBase = tint_color(base, 1.05); 3103 else 3104 indicatorBase = tint_color(base, 1.12); 3105 } 3106 3107 // bevel colors 3108 rgb_color cornerColor = tint_color(indicatorBase, 0.85); 3109 rgb_color bevelColor1 = tint_color(indicatorBase, 0.3); 3110 rgb_color bevelColor2 = tint_color(indicatorBase, 0.5); 3111 rgb_color bevelColor3 = tint_color(indicatorBase, 1.03); 3112 3113 if ((flags & B_DISABLED) != 0) { 3114 cornerColor = tint_color(indicatorBase, 0.8); 3115 bevelColor1 = tint_color(indicatorBase, 0.7); 3116 bevelColor2 = tint_color(indicatorBase, 0.8); 3117 bevelColor3 = tint_color(indicatorBase, 1.01); 3118 } else { 3119 cornerColor = tint_color(indicatorBase, 0.85); 3120 bevelColor1 = tint_color(indicatorBase, 0.3); 3121 bevelColor2 = tint_color(indicatorBase, 0.5); 3122 bevelColor3 = tint_color(indicatorBase, 1.03); 3123 } 3124 3125 // surface top gradient 3126 BGradientLinear fillGradient; 3127 _MakeButtonGradient(fillGradient, rect, indicatorBase, flags); 3128 3129 // rounded corners 3130 3131 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0 3132 && leftTopRadius > 0) { 3133 // draw left top rounded corner 3134 BRect leftTopCorner(floorf(rect.left), floorf(rect.top), 3135 floorf(rect.left + leftTopRadius - 2.0), 3136 floorf(rect.top + leftTopRadius - 2.0)); 3137 BRect cornerRect(leftTopCorner); 3138 3139 view->PushState(); 3140 view->ClipToRect(cornerRect); 3141 3142 BRect ellipseRect(leftTopCorner); 3143 ellipseRect.InsetBy(-1.0, -1.0); 3144 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3145 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3146 3147 // draw the frame (again) 3148 view->SetHighColor(frameLightColor); 3149 view->FillEllipse(ellipseRect); 3150 3151 // draw the bevel and background 3152 _DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect, 3153 bevelColor1, fillGradient); 3154 3155 view->PopState(); 3156 view->ClipToInverseRect(cornerRect); 3157 } 3158 3159 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0 3160 && rightTopRadius > 0) { 3161 // draw right top rounded corner 3162 BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0), 3163 floorf(rect.top), floorf(rect.right), 3164 floorf(rect.top + rightTopRadius - 2.0)); 3165 BRect cornerRect(rightTopCorner); 3166 3167 view->PushState(); 3168 view->ClipToRect(cornerRect); 3169 3170 BRect ellipseRect(rightTopCorner); 3171 ellipseRect.InsetBy(-1.0, -1.0); 3172 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3173 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3174 3175 // draw the frame (again) 3176 if (frameLightColor == frameShadowColor) { 3177 view->SetHighColor(frameLightColor); 3178 view->FillEllipse(ellipseRect); 3179 } else { 3180 BGradientLinear gradient; 3181 gradient.AddColor(frameLightColor, 0); 3182 gradient.AddColor(frameShadowColor, 255); 3183 gradient.SetStart(rightTopCorner.LeftTop()); 3184 gradient.SetEnd(rightTopCorner.RightBottom()); 3185 view->FillEllipse(ellipseRect, gradient); 3186 } 3187 3188 // draw the bevel and background 3189 _DrawRoundCornerBackgroundRightTop(view, rightTopCorner, updateRect, 3190 bevelColor1, bevelColor3, fillGradient); 3191 3192 view->PopState(); 3193 view->ClipToInverseRect(cornerRect); 3194 } 3195 3196 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 3197 && leftBottomRadius > 0) { 3198 // draw left bottom rounded corner 3199 BRect leftBottomCorner(floorf(rect.left), 3200 floorf(rect.bottom - leftBottomRadius + 2.0), 3201 floorf(rect.left + leftBottomRadius - 2.0), 3202 floorf(rect.bottom)); 3203 BRect cornerRect(leftBottomCorner); 3204 3205 view->PushState(); 3206 view->ClipToRect(cornerRect); 3207 3208 BRect ellipseRect(leftBottomCorner); 3209 ellipseRect.InsetBy(-1.0, -1.0); 3210 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3211 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3212 3213 // draw the frame (again) 3214 if (frameLightColor == frameShadowColor) { 3215 view->SetHighColor(frameLightColor); 3216 view->FillEllipse(ellipseRect); 3217 } else { 3218 BGradientLinear gradient; 3219 gradient.AddColor(frameLightColor, 0); 3220 gradient.AddColor(frameShadowColor, 255); 3221 gradient.SetStart(leftBottomCorner.LeftTop()); 3222 gradient.SetEnd(leftBottomCorner.RightBottom()); 3223 view->FillEllipse(ellipseRect, gradient); 3224 } 3225 3226 // draw the bevel and background 3227 _DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner, 3228 updateRect, bevelColor2, bevelColor3, fillGradient); 3229 3230 view->PopState(); 3231 view->ClipToInverseRect(cornerRect); 3232 } 3233 3234 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 3235 && rightBottomRadius > 0) { 3236 // draw right bottom rounded corner 3237 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0), 3238 floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right), 3239 floorf(rect.bottom)); 3240 BRect cornerRect(rightBottomCorner); 3241 3242 view->PushState(); 3243 view->ClipToRect(cornerRect); 3244 3245 BRect ellipseRect(rightBottomCorner); 3246 ellipseRect.InsetBy(-1.0, -1.0); 3247 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3248 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3249 3250 // draw the frame (again) 3251 view->SetHighColor(frameShadowColor); 3252 view->FillEllipse(ellipseRect); 3253 3254 // draw the bevel and background 3255 _DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner, 3256 updateRect, bevelColor3, fillGradient); 3257 3258 view->PopState(); 3259 view->ClipToInverseRect(cornerRect); 3260 } 3261 3262 // draw the bevel 3263 _DrawFrame(view, rect, 3264 bevelColor2, bevelColor1, 3265 bevelColor3, bevelColor3, 3266 cornerColor, cornerColor, 3267 borders); 3268 3269 // fill in the background 3270 view->FillRect(rect, fillGradient); 3271 3272 // restore the clipping constraints of the view 3273 view->PopState(); 3274 } 3275 3276 3277 void 3278 HaikuControlLook::_DrawRoundCornerLeftTop(BView* view, BRect& cornerRect, 3279 const BRect& updateRect, const rgb_color& background, 3280 const rgb_color& edgeColor, const rgb_color& frameColor, 3281 const rgb_color& bevelColor, const BGradientLinear& fillGradient) 3282 { 3283 _DrawRoundCornerFrameLeftTop(view, cornerRect, updateRect, 3284 background, edgeColor, frameColor); 3285 _DrawRoundCornerBackgroundLeftTop(view, cornerRect, updateRect, 3286 bevelColor, fillGradient); 3287 } 3288 3289 3290 void 3291 HaikuControlLook::_DrawRoundCornerFrameLeftTop(BView* view, BRect& cornerRect, 3292 const BRect& updateRect, const rgb_color& background, 3293 const rgb_color& edgeColor, const rgb_color& frameColor) 3294 { 3295 view->PushState(); 3296 3297 // constrain clipping region to corner 3298 view->ClipToRect(cornerRect); 3299 3300 // background 3301 view->SetHighColor(background); 3302 view->FillRect(cornerRect); 3303 3304 // outer edge 3305 BRect ellipseRect(cornerRect); 3306 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3307 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3308 3309 view->SetHighColor(edgeColor); 3310 view->FillEllipse(ellipseRect); 3311 3312 // frame 3313 ellipseRect.InsetBy(1, 1); 3314 cornerRect.left++; 3315 cornerRect.top++; 3316 view->SetHighColor(frameColor); 3317 view->FillEllipse(ellipseRect); 3318 3319 // prepare for bevel 3320 cornerRect.left++; 3321 cornerRect.top++; 3322 3323 view->PopState(); 3324 } 3325 3326 3327 void 3328 HaikuControlLook::_DrawRoundCornerBackgroundLeftTop(BView* view, BRect& cornerRect, 3329 const BRect& updateRect, const rgb_color& bevelColor, 3330 const BGradientLinear& fillGradient) 3331 { 3332 view->PushState(); 3333 3334 // constrain clipping region to corner 3335 view->ClipToRect(cornerRect); 3336 3337 BRect ellipseRect(cornerRect); 3338 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3339 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3340 3341 // bevel 3342 view->SetHighColor(bevelColor); 3343 view->FillEllipse(ellipseRect); 3344 3345 // gradient 3346 ellipseRect.InsetBy(1, 1); 3347 view->FillEllipse(ellipseRect, fillGradient); 3348 3349 view->PopState(); 3350 } 3351 3352 3353 void 3354 HaikuControlLook::_DrawRoundCornerRightTop(BView* view, BRect& cornerRect, 3355 const BRect& updateRect, const rgb_color& background, 3356 const rgb_color& edgeTopColor, const rgb_color& edgeRightColor, 3357 const rgb_color& frameTopColor, const rgb_color& frameRightColor, 3358 const rgb_color& bevelTopColor, const rgb_color& bevelRightColor, 3359 const BGradientLinear& fillGradient) 3360 { 3361 _DrawRoundCornerFrameRightTop(view, cornerRect, updateRect, 3362 background, edgeTopColor, edgeRightColor, frameTopColor, 3363 frameRightColor); 3364 _DrawRoundCornerBackgroundRightTop(view, cornerRect, updateRect, 3365 bevelTopColor, bevelRightColor, fillGradient); 3366 } 3367 3368 3369 void 3370 HaikuControlLook::_DrawRoundCornerFrameRightTop(BView* view, BRect& cornerRect, 3371 const BRect& updateRect, const rgb_color& background, 3372 const rgb_color& edgeTopColor, const rgb_color& edgeRightColor, 3373 const rgb_color& frameTopColor, const rgb_color& frameRightColor) 3374 { 3375 view->PushState(); 3376 3377 // constrain clipping region to corner 3378 view->ClipToRect(cornerRect); 3379 3380 // background 3381 view->SetHighColor(background); 3382 view->FillRect(cornerRect); 3383 3384 // outer edge 3385 BRect ellipseRect(cornerRect); 3386 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3387 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3388 3389 BGradientLinear gradient; 3390 gradient.AddColor(edgeTopColor, 0); 3391 gradient.AddColor(edgeRightColor, 255); 3392 gradient.SetStart(cornerRect.LeftTop()); 3393 gradient.SetEnd(cornerRect.RightBottom()); 3394 view->FillEllipse(ellipseRect, gradient); 3395 3396 // frame 3397 ellipseRect.InsetBy(1, 1); 3398 cornerRect.right--; 3399 cornerRect.top++; 3400 if (frameTopColor == frameRightColor) { 3401 view->SetHighColor(frameTopColor); 3402 view->FillEllipse(ellipseRect); 3403 } else { 3404 gradient.SetColor(0, frameTopColor); 3405 gradient.SetColor(1, frameRightColor); 3406 gradient.SetStart(cornerRect.LeftTop()); 3407 gradient.SetEnd(cornerRect.RightBottom()); 3408 view->FillEllipse(ellipseRect, gradient); 3409 } 3410 3411 // prepare for bevel 3412 cornerRect.right--; 3413 cornerRect.top++; 3414 3415 view->PopState(); 3416 } 3417 3418 3419 void 3420 HaikuControlLook::_DrawRoundCornerBackgroundRightTop(BView* view, BRect& cornerRect, 3421 const BRect& updateRect, const rgb_color& bevelTopColor, 3422 const rgb_color& bevelRightColor, const BGradientLinear& fillGradient) 3423 { 3424 view->PushState(); 3425 3426 // constrain clipping region to corner 3427 view->ClipToRect(cornerRect); 3428 3429 BRect ellipseRect(cornerRect); 3430 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3431 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3432 3433 // bevel 3434 BGradientLinear gradient; 3435 gradient.AddColor(bevelTopColor, 0); 3436 gradient.AddColor(bevelRightColor, 255); 3437 gradient.SetStart(cornerRect.LeftTop()); 3438 gradient.SetEnd(cornerRect.RightBottom()); 3439 view->FillEllipse(ellipseRect, gradient); 3440 3441 // gradient 3442 ellipseRect.InsetBy(1, 1); 3443 view->FillEllipse(ellipseRect, fillGradient); 3444 3445 view->PopState(); 3446 } 3447 3448 3449 void 3450 HaikuControlLook::_DrawRoundCornerLeftBottom(BView* view, BRect& cornerRect, 3451 const BRect& updateRect, const rgb_color& background, 3452 const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor, 3453 const rgb_color& frameLeftColor, const rgb_color& frameBottomColor, 3454 const rgb_color& bevelLeftColor, const rgb_color& bevelBottomColor, 3455 const BGradientLinear& fillGradient) 3456 { 3457 _DrawRoundCornerFrameLeftBottom(view, cornerRect, updateRect, 3458 background, edgeLeftColor, edgeBottomColor, frameLeftColor, 3459 frameBottomColor); 3460 _DrawRoundCornerBackgroundLeftBottom(view, cornerRect, updateRect, 3461 bevelLeftColor, bevelBottomColor, fillGradient); 3462 } 3463 3464 3465 void 3466 HaikuControlLook::_DrawRoundCornerFrameLeftBottom(BView* view, BRect& cornerRect, 3467 const BRect& updateRect, const rgb_color& background, 3468 const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor, 3469 const rgb_color& frameLeftColor, const rgb_color& frameBottomColor) 3470 { 3471 view->PushState(); 3472 3473 // constrain clipping region to corner 3474 view->ClipToRect(cornerRect); 3475 3476 // background 3477 view->SetHighColor(background); 3478 view->FillRect(cornerRect); 3479 3480 // outer edge 3481 BRect ellipseRect(cornerRect); 3482 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3483 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3484 3485 BGradientLinear gradient; 3486 gradient.AddColor(edgeLeftColor, 0); 3487 gradient.AddColor(edgeBottomColor, 255); 3488 gradient.SetStart(cornerRect.LeftTop()); 3489 gradient.SetEnd(cornerRect.RightBottom()); 3490 view->FillEllipse(ellipseRect, gradient); 3491 3492 // frame 3493 ellipseRect.InsetBy(1, 1); 3494 cornerRect.left++; 3495 cornerRect.bottom--; 3496 if (frameLeftColor == frameBottomColor) { 3497 view->SetHighColor(frameLeftColor); 3498 view->FillEllipse(ellipseRect); 3499 } else { 3500 gradient.SetColor(0, frameLeftColor); 3501 gradient.SetColor(1, frameBottomColor); 3502 gradient.SetStart(cornerRect.LeftTop()); 3503 gradient.SetEnd(cornerRect.RightBottom()); 3504 view->FillEllipse(ellipseRect, gradient); 3505 } 3506 3507 // prepare for bevel 3508 cornerRect.left++; 3509 cornerRect.bottom--; 3510 3511 view->PopState(); 3512 } 3513 3514 3515 void 3516 HaikuControlLook::_DrawRoundCornerBackgroundLeftBottom(BView* view, BRect& cornerRect, 3517 const BRect& updateRect, const rgb_color& bevelLeftColor, 3518 const rgb_color& bevelBottomColor, const BGradientLinear& fillGradient) 3519 { 3520 view->PushState(); 3521 3522 // constrain clipping region to corner 3523 view->ClipToRect(cornerRect); 3524 3525 BRect ellipseRect(cornerRect); 3526 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3527 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3528 3529 // bevel 3530 BGradientLinear gradient; 3531 gradient.AddColor(bevelLeftColor, 0); 3532 gradient.AddColor(bevelBottomColor, 255); 3533 gradient.SetStart(cornerRect.LeftTop()); 3534 gradient.SetEnd(cornerRect.RightBottom()); 3535 view->FillEllipse(ellipseRect, gradient); 3536 3537 // gradient 3538 ellipseRect.InsetBy(1, 1); 3539 view->FillEllipse(ellipseRect, fillGradient); 3540 3541 view->PopState(); 3542 } 3543 3544 3545 void 3546 HaikuControlLook::_DrawRoundCornerRightBottom(BView* view, BRect& cornerRect, 3547 const BRect& updateRect, const rgb_color& background, 3548 const rgb_color& edgeColor, const rgb_color& frameColor, 3549 const rgb_color& bevelColor, const BGradientLinear& fillGradient) 3550 { 3551 _DrawRoundCornerFrameRightBottom(view, cornerRect, updateRect, 3552 background, edgeColor, frameColor); 3553 _DrawRoundCornerBackgroundRightBottom(view, cornerRect, updateRect, 3554 bevelColor, fillGradient); 3555 } 3556 3557 3558 void 3559 HaikuControlLook::_DrawRoundCornerFrameRightBottom(BView* view, BRect& cornerRect, 3560 const BRect& updateRect, const rgb_color& background, 3561 const rgb_color& edgeColor, const rgb_color& frameColor) 3562 { 3563 view->PushState(); 3564 3565 // constrain clipping region to corner 3566 view->ClipToRect(cornerRect); 3567 3568 // background 3569 view->SetHighColor(background); 3570 view->FillRect(cornerRect); 3571 3572 // outer edge 3573 BRect ellipseRect(cornerRect); 3574 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3575 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3576 3577 view->SetHighColor(edgeColor); 3578 view->FillEllipse(ellipseRect); 3579 3580 // frame 3581 ellipseRect.InsetBy(1, 1); 3582 cornerRect.right--; 3583 cornerRect.bottom--; 3584 view->SetHighColor(frameColor); 3585 view->FillEllipse(ellipseRect); 3586 3587 // prepare for bevel 3588 cornerRect.right--; 3589 cornerRect.bottom--; 3590 3591 view->PopState(); 3592 } 3593 3594 3595 void 3596 HaikuControlLook::_DrawRoundCornerBackgroundRightBottom(BView* view, 3597 BRect& cornerRect, const BRect& updateRect, const rgb_color& bevelColor, 3598 const BGradientLinear& fillGradient) 3599 { 3600 view->PushState(); 3601 3602 // constrain clipping region to corner 3603 view->ClipToRect(cornerRect); 3604 3605 BRect ellipseRect(cornerRect); 3606 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3607 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3608 3609 // bevel 3610 view->SetHighColor(bevelColor); 3611 view->FillEllipse(ellipseRect); 3612 3613 // gradient 3614 ellipseRect.InsetBy(1, 1); 3615 view->FillEllipse(ellipseRect, fillGradient); 3616 3617 view->PopState(); 3618 } 3619 3620 3621 void 3622 HaikuControlLook::_DrawRoundBarCorner(BView* view, BRect& rect, 3623 const BRect& updateRect, 3624 const rgb_color& edgeLightColor, const rgb_color& edgeShadowColor, 3625 const rgb_color& frameLightColor, const rgb_color& frameShadowColor, 3626 const rgb_color& fillLightColor, const rgb_color& fillShadowColor, 3627 float leftInset, float topInset, float rightInset, float bottomInset, 3628 orientation orientation) 3629 { 3630 if (!ShouldDraw(view, rect, updateRect)) 3631 return; 3632 3633 BGradientLinear gradient; 3634 gradient.AddColor(edgeShadowColor, 0); 3635 gradient.AddColor(edgeLightColor, 255); 3636 gradient.SetStart(rect.LeftTop()); 3637 if (orientation == B_HORIZONTAL) 3638 gradient.SetEnd(rect.LeftBottom()); 3639 else 3640 gradient.SetEnd(rect.RightTop()); 3641 3642 view->FillEllipse(rect, gradient); 3643 3644 rect.left += leftInset; 3645 rect.top += topInset; 3646 rect.right += rightInset; 3647 rect.bottom += bottomInset; 3648 3649 gradient.MakeEmpty(); 3650 gradient.AddColor(frameShadowColor, 0); 3651 gradient.AddColor(frameLightColor, 255); 3652 gradient.SetStart(rect.LeftTop()); 3653 if (orientation == B_HORIZONTAL) 3654 gradient.SetEnd(rect.LeftBottom()); 3655 else 3656 gradient.SetEnd(rect.RightTop()); 3657 3658 view->FillEllipse(rect, gradient); 3659 3660 rect.left += leftInset; 3661 rect.top += topInset; 3662 rect.right += rightInset; 3663 rect.bottom += bottomInset; 3664 3665 gradient.MakeEmpty(); 3666 gradient.AddColor(fillShadowColor, 0); 3667 gradient.AddColor(fillLightColor, 255); 3668 gradient.SetStart(rect.LeftTop()); 3669 if (orientation == B_HORIZONTAL) 3670 gradient.SetEnd(rect.LeftBottom()); 3671 else 3672 gradient.SetEnd(rect.RightTop()); 3673 3674 view->FillEllipse(rect, gradient); 3675 } 3676 3677 3678 rgb_color 3679 HaikuControlLook::_EdgeLightColor(const rgb_color& base, float contrast, 3680 float brightness, uint32 flags) 3681 { 3682 rgb_color edgeLightColor; 3683 3684 if ((flags & B_BLEND_FRAME) != 0) { 3685 uint8 alpha = uint8(20 * contrast); 3686 uint8 white = uint8(255 * brightness); 3687 3688 edgeLightColor = (rgb_color){ white, white, white, alpha }; 3689 } else { 3690 // colors 3691 float tintLight = kEdgeBevelLightTint; 3692 3693 if (contrast == 0.0) 3694 tintLight = B_NO_TINT; 3695 else if (contrast != 1.0) 3696 tintLight = B_NO_TINT + (tintLight - B_NO_TINT) * contrast; 3697 3698 edgeLightColor = tint_color(base, tintLight); 3699 3700 if (brightness < 1.0) { 3701 edgeLightColor.red = uint8(edgeLightColor.red * brightness); 3702 edgeLightColor.green = uint8(edgeLightColor.green * brightness); 3703 edgeLightColor.blue = uint8(edgeLightColor.blue * brightness); 3704 } 3705 } 3706 3707 return edgeLightColor; 3708 } 3709 3710 3711 rgb_color 3712 HaikuControlLook::_EdgeShadowColor(const rgb_color& base, float contrast, 3713 float brightness, uint32 flags) 3714 { 3715 rgb_color edgeShadowColor; 3716 3717 if ((flags & B_BLEND_FRAME) != 0) { 3718 uint8 alpha = uint8(20 * contrast); 3719 edgeShadowColor = (rgb_color){ 0, 0, 0, alpha }; 3720 } else { 3721 float tintShadow = kEdgeBevelShadowTint; 3722 3723 if (contrast == 0.0) 3724 tintShadow = B_NO_TINT; 3725 else if (contrast != 1.0) 3726 tintShadow = B_NO_TINT + (tintShadow - B_NO_TINT) * contrast; 3727 3728 edgeShadowColor = tint_color(base, tintShadow); 3729 3730 if (brightness < 1.0) { 3731 edgeShadowColor.red = uint8(edgeShadowColor.red * brightness); 3732 edgeShadowColor.green = uint8(edgeShadowColor.green * brightness); 3733 edgeShadowColor.blue = uint8(edgeShadowColor.blue * brightness); 3734 } 3735 } 3736 3737 return edgeShadowColor; 3738 } 3739 3740 3741 rgb_color 3742 HaikuControlLook::_FrameLightColor(const rgb_color& base, uint32 flags) 3743 { 3744 if ((flags & B_FOCUSED) != 0) 3745 return ui_color(B_KEYBOARD_NAVIGATION_COLOR); 3746 3747 if ((flags & B_ACTIVATED) != 0) 3748 return _FrameShadowColor(base, flags & ~B_ACTIVATED); 3749 3750 rgb_color frameLightColor; 3751 3752 if ((flags & B_DISABLED) != 0) { 3753 // TODO: B_BLEND_FRAME 3754 frameLightColor = tint_color(base, 1.145); 3755 3756 if ((flags & B_DEFAULT_BUTTON) != 0) 3757 frameLightColor = tint_color(frameLightColor, 1.14); 3758 } else { 3759 if ((flags & B_BLEND_FRAME) != 0) 3760 frameLightColor = (rgb_color){ 0, 0, 0, 75 }; 3761 else 3762 frameLightColor = tint_color(base, 1.33); 3763 3764 if ((flags & B_DEFAULT_BUTTON) != 0) 3765 frameLightColor = tint_color(frameLightColor, 1.35); 3766 } 3767 3768 return frameLightColor; 3769 } 3770 3771 3772 rgb_color 3773 HaikuControlLook::_FrameShadowColor(const rgb_color& base, uint32 flags) 3774 { 3775 if ((flags & B_FOCUSED) != 0) 3776 return ui_color(B_KEYBOARD_NAVIGATION_COLOR); 3777 3778 if ((flags & B_ACTIVATED) != 0) 3779 return _FrameLightColor(base, flags & ~B_ACTIVATED); 3780 3781 rgb_color frameShadowColor; 3782 3783 if ((flags & B_DISABLED) != 0) { 3784 // TODO: B_BLEND_FRAME 3785 frameShadowColor = tint_color(base, 1.24); 3786 3787 if ((flags & B_DEFAULT_BUTTON) != 0) { 3788 frameShadowColor = tint_color(base, 1.145); 3789 frameShadowColor = tint_color(frameShadowColor, 1.12); 3790 } 3791 } else { 3792 if ((flags & B_DEFAULT_BUTTON) != 0) { 3793 if ((flags & B_BLEND_FRAME) != 0) 3794 frameShadowColor = (rgb_color){ 0, 0, 0, 75 }; 3795 else 3796 frameShadowColor = tint_color(base, 1.33); 3797 3798 frameShadowColor = tint_color(frameShadowColor, 1.5); 3799 } else { 3800 if ((flags & B_BLEND_FRAME) != 0) 3801 frameShadowColor = (rgb_color){ 0, 0, 0, 95 }; 3802 else 3803 frameShadowColor = tint_color(base, 1.47); 3804 } 3805 } 3806 3807 return frameShadowColor; 3808 } 3809 3810 3811 rgb_color 3812 HaikuControlLook::_BevelLightColor(const rgb_color& base, uint32 flags) 3813 { 3814 rgb_color bevelLightColor = tint_color(base, 0.2); 3815 3816 if ((flags & B_DISABLED) != 0) 3817 bevelLightColor = tint_color(base, B_LIGHTEN_1_TINT); 3818 3819 if ((flags & B_ACTIVATED) != 0) 3820 bevelLightColor = tint_color(base, B_DARKEN_1_TINT); 3821 3822 return bevelLightColor; 3823 } 3824 3825 3826 rgb_color 3827 HaikuControlLook::_BevelShadowColor(const rgb_color& base, uint32 flags) 3828 { 3829 rgb_color bevelShadowColor = tint_color(base, 1.08); 3830 3831 if ((flags & B_DISABLED) != 0) 3832 bevelShadowColor = base; 3833 3834 if ((flags & B_ACTIVATED) != 0) 3835 bevelShadowColor = tint_color(base, B_DARKEN_1_TINT); 3836 3837 return bevelShadowColor; 3838 } 3839 3840 3841 void 3842 HaikuControlLook::_FillGradient(BView* view, const BRect& rect, 3843 const rgb_color& base, float topTint, float bottomTint, 3844 orientation orientation) 3845 { 3846 BGradientLinear gradient; 3847 _MakeGradient(gradient, rect, base, topTint, bottomTint, orientation); 3848 view->FillRect(rect, gradient); 3849 } 3850 3851 3852 void 3853 HaikuControlLook::_FillGlossyGradient(BView* view, const BRect& rect, 3854 const rgb_color& base, float topTint, float middle1Tint, 3855 float middle2Tint, float bottomTint, orientation orientation) 3856 { 3857 BGradientLinear gradient; 3858 _MakeGlossyGradient(gradient, rect, base, topTint, middle1Tint, 3859 middle2Tint, bottomTint, orientation); 3860 view->FillRect(rect, gradient); 3861 } 3862 3863 3864 void 3865 HaikuControlLook::_MakeGradient(BGradientLinear& gradient, const BRect& rect, 3866 const rgb_color& base, float topTint, float bottomTint, 3867 orientation orientation) const 3868 { 3869 gradient.AddColor(tint_color(base, topTint), 0); 3870 gradient.AddColor(tint_color(base, bottomTint), 255); 3871 gradient.SetStart(rect.LeftTop()); 3872 if (orientation == B_HORIZONTAL) 3873 gradient.SetEnd(rect.LeftBottom()); 3874 else 3875 gradient.SetEnd(rect.RightTop()); 3876 } 3877 3878 3879 void 3880 HaikuControlLook::_MakeGlossyGradient(BGradientLinear& gradient, const BRect& rect, 3881 const rgb_color& base, float topTint, float middle1Tint, 3882 float middle2Tint, float bottomTint, 3883 orientation orientation) const 3884 { 3885 gradient.AddColor(tint_color(base, topTint), 0); 3886 gradient.AddColor(tint_color(base, middle1Tint), 132); 3887 gradient.AddColor(tint_color(base, middle2Tint), 136); 3888 gradient.AddColor(tint_color(base, bottomTint), 255); 3889 gradient.SetStart(rect.LeftTop()); 3890 if (orientation == B_HORIZONTAL) 3891 gradient.SetEnd(rect.LeftBottom()); 3892 else 3893 gradient.SetEnd(rect.RightTop()); 3894 } 3895 3896 3897 void 3898 HaikuControlLook::_MakeButtonGradient(BGradientLinear& gradient, BRect& rect, 3899 const rgb_color& base, uint32 flags, orientation orientation) const 3900 { 3901 float topTint = 0.49; 3902 float middleTint1 = 0.62; 3903 float middleTint2 = 0.76; 3904 float bottomTint = 0.90; 3905 3906 if ((flags & B_ACTIVATED) != 0) { 3907 topTint = 1.11; 3908 bottomTint = 1.08; 3909 } 3910 3911 if ((flags & B_DISABLED) != 0) { 3912 topTint = (topTint + B_NO_TINT) / 2; 3913 middleTint1 = (middleTint1 + B_NO_TINT) / 2; 3914 middleTint2 = (middleTint2 + B_NO_TINT) / 2; 3915 bottomTint = (bottomTint + B_NO_TINT) / 2; 3916 } else if ((flags & B_HOVER) != 0) { 3917 topTint *= kHoverTintFactor; 3918 middleTint1 *= kHoverTintFactor; 3919 middleTint2 *= kHoverTintFactor; 3920 bottomTint *= kHoverTintFactor; 3921 } 3922 3923 if ((flags & B_ACTIVATED) != 0) { 3924 _MakeGradient(gradient, rect, base, topTint, bottomTint, orientation); 3925 } else { 3926 _MakeGlossyGradient(gradient, rect, base, topTint, middleTint1, 3927 middleTint2, bottomTint, orientation); 3928 } 3929 } 3930 3931 3932 bool 3933 HaikuControlLook::_RadioButtonAndCheckBoxMarkColor(const rgb_color& base, 3934 rgb_color& color, uint32 flags) const 3935 { 3936 if ((flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED | B_CLICKED)) == 0) { 3937 // no mark to be drawn at all 3938 return false; 3939 } 3940 3941 color = ui_color(B_CONTROL_MARK_COLOR); 3942 3943 float mix = 1.0; 3944 3945 if ((flags & B_DISABLED) != 0) { 3946 // activated, but disabled 3947 mix = 0.4; 3948 } else if ((flags & B_CLICKED) != 0) { 3949 if ((flags & B_ACTIVATED) != 0) { 3950 // losing activation 3951 mix = 0.7; 3952 } else { 3953 // becoming activated (or losing partial activation) 3954 mix = 0.3; 3955 } 3956 } else if ((flags & B_PARTIALLY_ACTIVATED) != 0) { 3957 // partially activated 3958 mix = 0.5; 3959 } else { 3960 // simply activated 3961 } 3962 3963 color.red = uint8(color.red * mix + base.red * (1.0 - mix)); 3964 color.green = uint8(color.green * mix + base.green * (1.0 - mix)); 3965 color.blue = uint8(color.blue * mix + base.blue * (1.0 - mix)); 3966 3967 return true; 3968 } 3969 3970 } // namespace BPrivate 3971