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 != NULL && window->Feel() == kDesktopWindowFeel 2201 && window->Look() == kDesktopWindowLook && view->Parent() != NULL 2202 && view->Parent()->Parent() == NULL && (flags & B_IGNORE_OUTLINE) == 0; 2203 2204 rgb_color low; 2205 rgb_color color; 2206 rgb_color glowColor; 2207 2208 if (textColor != NULL) 2209 glowColor = *textColor; 2210 else if (view->Parent() != NULL) 2211 glowColor = view->Parent()->HighColor(); 2212 else if ((flags & B_IS_CONTROL) != 0) 2213 glowColor = ui_color(B_CONTROL_TEXT_COLOR); 2214 else 2215 glowColor = ui_color(B_PANEL_TEXT_COLOR); 2216 2217 color = glowColor; 2218 2219 if (isDesktop) 2220 low = view->Parent()->ViewColor(); 2221 else 2222 low = base; 2223 2224 if ((flags & B_DISABLED) != 0) { 2225 color.red = (uint8)(((int32)low.red + color.red + 1) / 2); 2226 color.green = (uint8)(((int32)low.green + color.green + 1) / 2); 2227 color.blue = (uint8)(((int32)low.blue + color.blue + 1) / 2); 2228 } 2229 2230 drawing_mode oldMode = view->DrawingMode(); 2231 2232 if (isDesktop) { 2233 // enforce proper use of desktop label colors 2234 if (low.IsDark()) { 2235 if (textColor == NULL) 2236 color = make_color(255, 255, 255); 2237 2238 glowColor = make_color(0, 0, 0); 2239 } else { 2240 if (textColor == NULL) 2241 color = make_color(0, 0, 0); 2242 2243 glowColor = make_color(255, 255, 255); 2244 } 2245 2246 // drawing occurs on the desktop 2247 if (fCachedWorkspace != current_workspace()) { 2248 int8 indice = 0; 2249 int32 mask; 2250 bool tmpOutline; 2251 while (fBackgroundInfo.FindInt32("be:bgndimginfoworkspaces", 2252 indice, &mask) == B_OK 2253 && fBackgroundInfo.FindBool("be:bgndimginfoerasetext", 2254 indice, &tmpOutline) == B_OK) { 2255 2256 if (((1 << current_workspace()) & mask) != 0) { 2257 fCachedOutline = tmpOutline; 2258 fCachedWorkspace = current_workspace(); 2259 break; 2260 } 2261 indice++; 2262 } 2263 } 2264 2265 if (fCachedOutline) { 2266 BFont font; 2267 view->GetFont(&font); 2268 2269 view->SetDrawingMode(B_OP_ALPHA); 2270 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY); 2271 // Draw glow or outline 2272 if (glowColor.IsLight()) { 2273 font.SetFalseBoldWidth(2.0); 2274 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2275 2276 glowColor.alpha = 30; 2277 view->SetHighColor(glowColor); 2278 view->DrawString(label, where); 2279 2280 font.SetFalseBoldWidth(1.0); 2281 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2282 2283 glowColor.alpha = 65; 2284 view->SetHighColor(glowColor); 2285 view->DrawString(label, where); 2286 2287 font.SetFalseBoldWidth(0.0); 2288 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2289 } else { 2290 font.SetFalseBoldWidth(1.0); 2291 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2292 2293 glowColor.alpha = 30; 2294 view->SetHighColor(glowColor); 2295 view->DrawString(label, where); 2296 2297 font.SetFalseBoldWidth(0.0); 2298 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2299 2300 glowColor.alpha = 200; 2301 view->SetHighColor(glowColor); 2302 view->DrawString(label, BPoint(where.x + 1, where.y + 1)); 2303 } 2304 } 2305 } 2306 2307 view->SetHighColor(color); 2308 view->SetDrawingMode(B_OP_OVER); 2309 view->DrawString(label, where); 2310 view->SetDrawingMode(oldMode); 2311 } 2312 2313 2314 void 2315 HaikuControlLook::DrawLabel(BView* view, const char* label, const BBitmap* icon, 2316 BRect rect, const BRect& updateRect, const rgb_color& base, uint32 flags, 2317 const BAlignment& alignment, const rgb_color* textColor) 2318 { 2319 if (!ShouldDraw(view, rect, updateRect)) 2320 return; 2321 2322 if (label == NULL && icon == NULL) 2323 return; 2324 2325 if (label == NULL) { 2326 // icon only 2327 BRect alignedRect = BLayoutUtils::AlignInFrame(rect, 2328 icon->Bounds().Size(), alignment); 2329 drawing_mode oldMode = view->DrawingMode(); 2330 view->SetDrawingMode(B_OP_OVER); 2331 view->DrawBitmap(icon, alignedRect.LeftTop()); 2332 view->SetDrawingMode(oldMode); 2333 return; 2334 } 2335 2336 // label, possibly with icon 2337 float availableWidth = rect.Width() + 1; 2338 float width = 0; 2339 float textOffset = 0; 2340 float height = 0; 2341 2342 if (icon != NULL) { 2343 width = icon->Bounds().Width() + DefaultLabelSpacing() + 1; 2344 height = icon->Bounds().Height() + 1; 2345 textOffset = width; 2346 availableWidth -= textOffset; 2347 } 2348 2349 // truncate the label if necessary and get the width and height 2350 BString truncatedLabel(label); 2351 2352 BFont font; 2353 view->GetFont(&font); 2354 2355 font.TruncateString(&truncatedLabel, B_TRUNCATE_END, availableWidth); 2356 width += ceilf(font.StringWidth(truncatedLabel.String())); 2357 2358 font_height fontHeight; 2359 font.GetHeight(&fontHeight); 2360 float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); 2361 height = std::max(height, textHeight); 2362 2363 // handle alignment 2364 BRect alignedRect(BLayoutUtils::AlignOnRect(rect, 2365 BSize(width - 1, height - 1), alignment)); 2366 2367 if (icon != NULL) { 2368 BPoint location(alignedRect.LeftTop()); 2369 if (icon->Bounds().Height() + 1 < height) 2370 location.y += ceilf((height - icon->Bounds().Height() - 1) / 2); 2371 2372 drawing_mode oldMode = view->DrawingMode(); 2373 view->SetDrawingMode(B_OP_OVER); 2374 view->DrawBitmap(icon, location); 2375 view->SetDrawingMode(oldMode); 2376 } 2377 2378 BPoint location(alignedRect.left + textOffset, 2379 alignedRect.top + ceilf(fontHeight.ascent)); 2380 if (textHeight < height) 2381 location.y += ceilf((height - textHeight) / 2); 2382 2383 DrawLabel(view, truncatedLabel.String(), base, flags, location, textColor); 2384 } 2385 2386 2387 void 2388 HaikuControlLook::GetFrameInsets(frame_type frameType, uint32 flags, float& _left, 2389 float& _top, float& _right, float& _bottom) 2390 { 2391 // All frames have the same inset on each side. 2392 float inset = 0; 2393 2394 switch (frameType) { 2395 case B_BUTTON_FRAME: 2396 inset = (flags & B_DEFAULT_BUTTON) != 0 ? 5 : 2; 2397 break; 2398 case B_GROUP_FRAME: 2399 case B_MENU_FIELD_FRAME: 2400 inset = 3; 2401 break; 2402 case B_SCROLL_VIEW_FRAME: 2403 case B_TEXT_CONTROL_FRAME: 2404 inset = 2; 2405 break; 2406 } 2407 2408 inset = ceilf(inset * (be_plain_font->Size() / 12.0f)); 2409 2410 _left = inset; 2411 _top = inset; 2412 _right = inset; 2413 _bottom = inset; 2414 } 2415 2416 2417 void 2418 HaikuControlLook::GetBackgroundInsets(background_type backgroundType, 2419 uint32 flags, float& _left, float& _top, float& _right, float& _bottom) 2420 { 2421 // Most backgrounds have the same inset on each side. 2422 float inset = 0; 2423 2424 switch (backgroundType) { 2425 case B_BUTTON_BACKGROUND: 2426 case B_MENU_BACKGROUND: 2427 case B_MENU_BAR_BACKGROUND: 2428 case B_MENU_FIELD_BACKGROUND: 2429 case B_MENU_ITEM_BACKGROUND: 2430 inset = 1; 2431 break; 2432 case B_BUTTON_WITH_POP_UP_BACKGROUND: 2433 _left = 1; 2434 _top = 1; 2435 _right = 1 + ComposeSpacing(kButtonPopUpIndicatorWidth); 2436 _bottom = 1; 2437 return; 2438 case B_HORIZONTAL_SCROLL_BAR_BACKGROUND: 2439 _left = 2; 2440 _top = 0; 2441 _right = 1; 2442 _bottom = 0; 2443 return; 2444 case B_VERTICAL_SCROLL_BAR_BACKGROUND: 2445 _left = 0; 2446 _top = 2; 2447 _right = 0; 2448 _bottom = 1; 2449 return; 2450 } 2451 2452 _left = inset; 2453 _top = inset; 2454 _right = inset; 2455 _bottom = inset; 2456 } 2457 2458 2459 void 2460 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect, 2461 const BRect& updateRect, const rgb_color& base, uint32 flags, 2462 uint32 borders, orientation orientation) 2463 { 2464 _DrawButtonBackground(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f, 2465 base, true, flags, borders, orientation); 2466 } 2467 2468 2469 void 2470 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect, 2471 const BRect& updateRect, float radius, const rgb_color& base, uint32 flags, 2472 uint32 borders, orientation orientation) 2473 { 2474 _DrawButtonBackground(view, rect, updateRect, radius, radius, radius, 2475 radius, base, true, flags, borders, orientation); 2476 } 2477 2478 2479 void 2480 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect, 2481 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 2482 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 2483 uint32 flags, uint32 borders, orientation orientation) 2484 { 2485 _DrawButtonBackground(view, rect, updateRect, leftTopRadius, 2486 rightTopRadius, leftBottomRadius, rightBottomRadius, base, true, flags, 2487 borders, orientation); 2488 } 2489 2490 2491 // #pragma mark - 2492 2493 2494 void 2495 HaikuControlLook::_DrawButtonFrame(BView* view, BRect& rect, 2496 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 2497 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 2498 const rgb_color& background, float contrast, float brightness, 2499 uint32 flags, uint32 borders) 2500 { 2501 if (!rect.IsValid()) 2502 return; 2503 2504 // save the clipping constraints of the view 2505 view->PushState(); 2506 2507 // set clipping constraints to rect 2508 view->ClipToRect(rect); 2509 2510 // If the button is flat and neither activated nor otherwise highlighted 2511 // (mouse hovering or focussed), draw it flat. 2512 if ((flags & B_FLAT) != 0 2513 && (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0 2514 && ((flags & (B_HOVER | B_FOCUSED)) == 0 2515 || (flags & B_DISABLED) != 0)) { 2516 _DrawFrame(view, rect, background, background, background, 2517 background, borders); 2518 _DrawFrame(view, rect, background, background, background, 2519 background, borders); 2520 view->PopState(); 2521 return; 2522 } 2523 2524 // outer edge colors 2525 rgb_color edgeLightColor; 2526 rgb_color edgeShadowColor; 2527 2528 // default button frame color 2529 rgb_color defaultIndicatorColor = ui_color(B_CONTROL_BORDER_COLOR); 2530 rgb_color cornerBgColor; 2531 2532 if ((flags & B_DISABLED) != 0) { 2533 defaultIndicatorColor = disable_color(defaultIndicatorColor, 2534 background); 2535 } 2536 2537 drawing_mode oldMode = view->DrawingMode(); 2538 2539 if ((flags & B_DEFAULT_BUTTON) != 0) { 2540 cornerBgColor = defaultIndicatorColor; 2541 edgeLightColor = _EdgeLightColor(defaultIndicatorColor, 2542 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8), 2543 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags); 2544 edgeShadowColor = _EdgeShadowColor(defaultIndicatorColor, 2545 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8), 2546 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags); 2547 2548 // draw default button indicator 2549 // Allow a 1-pixel border of the background to come through. 2550 rect.InsetBy(1, 1); 2551 2552 view->SetHighColor(defaultIndicatorColor); 2553 view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius); 2554 rect.InsetBy(1, 1); 2555 2556 view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius); 2557 rect.InsetBy(1, 1); 2558 } else { 2559 cornerBgColor = background; 2560 if ((flags & B_BLEND_FRAME) != 0) { 2561 // set the background color to transparent for the case 2562 // that we are on the desktop 2563 cornerBgColor.alpha = 0; 2564 view->SetDrawingMode(B_OP_ALPHA); 2565 } 2566 2567 edgeLightColor = _EdgeLightColor(background, 2568 contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0), 2569 brightness * 1.0, flags); 2570 edgeShadowColor = _EdgeShadowColor(background, 2571 contrast * (flags & B_DISABLED) != 0 ? 0.0 : 1.0, 2572 brightness * 1.0, flags); 2573 } 2574 2575 // frame colors 2576 rgb_color frameLightColor = _FrameLightColor(base, flags); 2577 rgb_color frameShadowColor = _FrameShadowColor(base, flags); 2578 2579 // rounded corners 2580 2581 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0 2582 && leftTopRadius > 0) { 2583 // draw left top rounded corner 2584 BRect leftTopCorner(floorf(rect.left), floorf(rect.top), 2585 floorf(rect.left + leftTopRadius), 2586 floorf(rect.top + leftTopRadius)); 2587 BRect cornerRect(leftTopCorner); 2588 _DrawRoundCornerFrameLeftTop(view, leftTopCorner, updateRect, 2589 cornerBgColor, edgeShadowColor, frameLightColor); 2590 view->ClipToInverseRect(cornerRect); 2591 } 2592 2593 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0 2594 && rightTopRadius > 0) { 2595 // draw right top rounded corner 2596 BRect rightTopCorner(floorf(rect.right - rightTopRadius), 2597 floorf(rect.top), floorf(rect.right), 2598 floorf(rect.top + rightTopRadius)); 2599 BRect cornerRect(rightTopCorner); 2600 _DrawRoundCornerFrameRightTop(view, rightTopCorner, updateRect, 2601 cornerBgColor, edgeShadowColor, edgeLightColor, 2602 frameLightColor, frameShadowColor); 2603 view->ClipToInverseRect(cornerRect); 2604 } 2605 2606 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2607 && leftBottomRadius > 0) { 2608 // draw left bottom rounded corner 2609 BRect leftBottomCorner(floorf(rect.left), 2610 floorf(rect.bottom - leftBottomRadius), 2611 floorf(rect.left + leftBottomRadius), floorf(rect.bottom)); 2612 BRect cornerRect(leftBottomCorner); 2613 _DrawRoundCornerFrameLeftBottom(view, leftBottomCorner, updateRect, 2614 cornerBgColor, edgeShadowColor, edgeLightColor, 2615 frameLightColor, frameShadowColor); 2616 view->ClipToInverseRect(cornerRect); 2617 } 2618 2619 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2620 && rightBottomRadius > 0) { 2621 // draw right bottom rounded corner 2622 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius), 2623 floorf(rect.bottom - rightBottomRadius), floorf(rect.right), 2624 floorf(rect.bottom)); 2625 BRect cornerRect(rightBottomCorner); 2626 _DrawRoundCornerFrameRightBottom(view, rightBottomCorner, 2627 updateRect, cornerBgColor, edgeLightColor, frameShadowColor); 2628 view->ClipToInverseRect(cornerRect); 2629 } 2630 2631 // draw outer edge 2632 if ((flags & B_DEFAULT_BUTTON) != 0) { 2633 _DrawOuterResessedFrame(view, rect, defaultIndicatorColor, 2634 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8), 2635 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), 2636 flags, borders); 2637 } else { 2638 _DrawOuterResessedFrame(view, rect, background, 2639 contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0), 2640 brightness * 1.0, flags, borders); 2641 } 2642 2643 view->SetDrawingMode(oldMode); 2644 2645 // draw frame 2646 if ((flags & B_BLEND_FRAME) != 0) { 2647 drawing_mode oldDrawingMode = view->DrawingMode(); 2648 view->SetDrawingMode(B_OP_ALPHA); 2649 2650 _DrawFrame(view, rect, frameLightColor, frameLightColor, 2651 frameShadowColor, frameShadowColor, borders); 2652 2653 view->SetDrawingMode(oldDrawingMode); 2654 } else { 2655 _DrawFrame(view, rect, frameLightColor, frameLightColor, 2656 frameShadowColor, frameShadowColor, borders); 2657 } 2658 2659 // restore the clipping constraints of the view 2660 view->PopState(); 2661 } 2662 2663 2664 void 2665 HaikuControlLook::_DrawOuterResessedFrame(BView* view, BRect& rect, 2666 const rgb_color& base, float contrast, float brightness, uint32 flags, 2667 uint32 borders) 2668 { 2669 rgb_color edgeLightColor = _EdgeLightColor(base, contrast, 2670 brightness, flags); 2671 rgb_color edgeShadowColor = _EdgeShadowColor(base, contrast, 2672 brightness, flags); 2673 2674 if ((flags & B_BLEND_FRAME) != 0) { 2675 // assumes the background has already been painted 2676 drawing_mode oldDrawingMode = view->DrawingMode(); 2677 view->SetDrawingMode(B_OP_ALPHA); 2678 2679 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, 2680 edgeLightColor, edgeLightColor, borders); 2681 2682 view->SetDrawingMode(oldDrawingMode); 2683 } else { 2684 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, 2685 edgeLightColor, edgeLightColor, borders); 2686 } 2687 } 2688 2689 2690 void 2691 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left, 2692 const rgb_color& top, const rgb_color& right, const rgb_color& bottom, 2693 uint32 borders) 2694 { 2695 view->BeginLineArray(4); 2696 2697 if (borders & B_LEFT_BORDER) { 2698 view->AddLine( 2699 BPoint(rect.left, rect.bottom), 2700 BPoint(rect.left, rect.top), left); 2701 rect.left++; 2702 } 2703 if (borders & B_TOP_BORDER) { 2704 view->AddLine( 2705 BPoint(rect.left, rect.top), 2706 BPoint(rect.right, rect.top), top); 2707 rect.top++; 2708 } 2709 if (borders & B_RIGHT_BORDER) { 2710 view->AddLine( 2711 BPoint(rect.right, rect.top), 2712 BPoint(rect.right, rect.bottom), right); 2713 rect.right--; 2714 } 2715 if (borders & B_BOTTOM_BORDER) { 2716 view->AddLine( 2717 BPoint(rect.left, rect.bottom), 2718 BPoint(rect.right, rect.bottom), bottom); 2719 rect.bottom--; 2720 } 2721 2722 view->EndLineArray(); 2723 } 2724 2725 2726 void 2727 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left, 2728 const rgb_color& top, const rgb_color& right, const rgb_color& bottom, 2729 const rgb_color& rightTop, const rgb_color& leftBottom, uint32 borders) 2730 { 2731 view->BeginLineArray(6); 2732 2733 if (borders & B_TOP_BORDER) { 2734 if (borders & B_RIGHT_BORDER) { 2735 view->AddLine( 2736 BPoint(rect.left, rect.top), 2737 BPoint(rect.right - 1, rect.top), top); 2738 view->AddLine( 2739 BPoint(rect.right, rect.top), 2740 BPoint(rect.right, rect.top), rightTop); 2741 } else { 2742 view->AddLine( 2743 BPoint(rect.left, rect.top), 2744 BPoint(rect.right, rect.top), top); 2745 } 2746 rect.top++; 2747 } 2748 2749 if (borders & B_LEFT_BORDER) { 2750 view->AddLine( 2751 BPoint(rect.left, rect.top), 2752 BPoint(rect.left, rect.bottom - 1), left); 2753 view->AddLine( 2754 BPoint(rect.left, rect.bottom), 2755 BPoint(rect.left, rect.bottom), leftBottom); 2756 rect.left++; 2757 } 2758 2759 if (borders & B_BOTTOM_BORDER) { 2760 view->AddLine( 2761 BPoint(rect.left, rect.bottom), 2762 BPoint(rect.right, rect.bottom), bottom); 2763 rect.bottom--; 2764 } 2765 2766 if (borders & B_RIGHT_BORDER) { 2767 view->AddLine( 2768 BPoint(rect.right, rect.bottom), 2769 BPoint(rect.right, rect.top), right); 2770 rect.right--; 2771 } 2772 2773 view->EndLineArray(); 2774 } 2775 2776 2777 void 2778 HaikuControlLook::_DrawButtonBackground(BView* view, BRect& rect, 2779 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 2780 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 2781 bool popupIndicator, uint32 flags, uint32 borders, orientation orientation) 2782 { 2783 if (!rect.IsValid()) 2784 return; 2785 2786 // save the clipping constraints of the view 2787 view->PushState(); 2788 2789 // set clipping constraints to rect 2790 view->ClipToRect(rect); 2791 2792 // If the button is flat and neither activated nor otherwise highlighted 2793 // (mouse hovering or focussed), draw it flat. 2794 if ((flags & B_FLAT) != 0 2795 && (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0 2796 && ((flags & (B_HOVER | B_FOCUSED)) == 0 2797 || (flags & B_DISABLED) != 0)) { 2798 _DrawFlatButtonBackground(view, rect, updateRect, base, popupIndicator, 2799 flags, borders, orientation); 2800 } else { 2801 BRegion clipping(rect); 2802 _DrawNonFlatButtonBackground(view, rect, updateRect, clipping, 2803 leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, 2804 base, popupIndicator, flags, borders, orientation); 2805 } 2806 2807 // restore the clipping constraints of the view 2808 view->PopState(); 2809 } 2810 2811 2812 void 2813 HaikuControlLook::_DrawFlatButtonBackground(BView* view, BRect& rect, 2814 const BRect& updateRect, const rgb_color& base, bool popupIndicator, 2815 uint32 flags, uint32 borders, orientation orientation) 2816 { 2817 _DrawFrame(view, rect, base, base, base, base, borders); 2818 // Not an actual frame, but the method insets our rect as needed. 2819 2820 view->SetHighColor(base); 2821 view->FillRect(rect); 2822 2823 if (popupIndicator) { 2824 BRect indicatorRect(rect); 2825 rect.right -= ComposeSpacing(kButtonPopUpIndicatorWidth); 2826 indicatorRect.left = rect.right + 3; 2827 // 2 pixels for the separator 2828 2829 view->SetHighColor(base); 2830 view->FillRect(indicatorRect); 2831 2832 _DrawPopUpMarker(view, indicatorRect, base, flags); 2833 } 2834 } 2835 2836 2837 void 2838 HaikuControlLook::_DrawNonFlatButtonBackground(BView* view, BRect& rect, 2839 const BRect& updateRect, BRegion& clipping, float leftTopRadius, 2840 float rightTopRadius, float leftBottomRadius, float rightBottomRadius, 2841 const rgb_color& base, bool popupIndicator, uint32 flags, uint32 borders, 2842 orientation orientation) 2843 { 2844 // inner bevel colors 2845 rgb_color bevelLightColor = _BevelLightColor(base, flags); 2846 rgb_color bevelShadowColor = _BevelShadowColor(base, flags); 2847 2848 // button background color 2849 rgb_color buttonBgColor; 2850 if ((flags & B_DISABLED) != 0) 2851 buttonBgColor = tint_color(base, 0.7); 2852 else 2853 buttonBgColor = tint_color(base, B_LIGHTEN_1_TINT); 2854 2855 // surface top gradient 2856 BGradientLinear fillGradient; 2857 _MakeButtonGradient(fillGradient, rect, base, flags, orientation); 2858 2859 // rounded corners 2860 2861 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0 2862 && leftTopRadius > 0) { 2863 // draw left top rounded corner 2864 BRect leftTopCorner(floorf(rect.left), floorf(rect.top), 2865 floorf(rect.left + leftTopRadius - 2.0), 2866 floorf(rect.top + leftTopRadius - 2.0)); 2867 clipping.Exclude(leftTopCorner); 2868 BRect cornerRect(leftTopCorner); 2869 _DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect, 2870 bevelLightColor, fillGradient); 2871 view->ClipToInverseRect(cornerRect); 2872 } 2873 2874 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0 2875 && rightTopRadius > 0) { 2876 // draw right top rounded corner 2877 BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0), 2878 floorf(rect.top), floorf(rect.right), 2879 floorf(rect.top + rightTopRadius - 2.0)); 2880 clipping.Exclude(rightTopCorner); 2881 BRect cornerRect(rightTopCorner); 2882 _DrawRoundCornerBackgroundRightTop(view, rightTopCorner, 2883 updateRect, bevelLightColor, bevelShadowColor, fillGradient); 2884 view->ClipToInverseRect(cornerRect); 2885 } 2886 2887 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2888 && leftBottomRadius > 0) { 2889 // draw left bottom rounded corner 2890 BRect leftBottomCorner(floorf(rect.left), 2891 floorf(rect.bottom - leftBottomRadius + 2.0), 2892 floorf(rect.left + leftBottomRadius - 2.0), 2893 floorf(rect.bottom)); 2894 clipping.Exclude(leftBottomCorner); 2895 BRect cornerRect(leftBottomCorner); 2896 _DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner, 2897 updateRect, bevelLightColor, bevelShadowColor, fillGradient); 2898 view->ClipToInverseRect(cornerRect); 2899 } 2900 2901 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2902 && rightBottomRadius > 0) { 2903 // draw right bottom rounded corner 2904 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0), 2905 floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right), 2906 floorf(rect.bottom)); 2907 clipping.Exclude(rightBottomCorner); 2908 BRect cornerRect(rightBottomCorner); 2909 _DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner, 2910 updateRect, bevelShadowColor, fillGradient); 2911 view->ClipToInverseRect(cornerRect); 2912 } 2913 2914 // draw inner bevel 2915 2916 if ((flags & B_ACTIVATED) != 0) { 2917 view->BeginLineArray(4); 2918 2919 // shadow along left/top borders 2920 if (borders & B_LEFT_BORDER) { 2921 view->AddLine(BPoint(rect.left, rect.top), 2922 BPoint(rect.left, rect.bottom), bevelLightColor); 2923 rect.left++; 2924 } 2925 if (borders & B_TOP_BORDER) { 2926 view->AddLine(BPoint(rect.left, rect.top), 2927 BPoint(rect.right, rect.top), bevelLightColor); 2928 rect.top++; 2929 } 2930 2931 // softer shadow along left/top borders 2932 if (borders & B_LEFT_BORDER) { 2933 view->AddLine(BPoint(rect.left, rect.top), 2934 BPoint(rect.left, rect.bottom), bevelShadowColor); 2935 rect.left++; 2936 } 2937 if (borders & B_TOP_BORDER) { 2938 view->AddLine(BPoint(rect.left, rect.top), 2939 BPoint(rect.right, rect.top), bevelShadowColor); 2940 rect.top++; 2941 } 2942 2943 view->EndLineArray(); 2944 } else { 2945 _DrawFrame(view, rect, 2946 bevelLightColor, bevelLightColor, 2947 bevelShadowColor, bevelShadowColor, 2948 buttonBgColor, buttonBgColor, borders); 2949 } 2950 2951 if (popupIndicator) { 2952 BRect indicatorRect(rect); 2953 rect.right -= ComposeSpacing(kButtonPopUpIndicatorWidth); 2954 indicatorRect.left = rect.right + 3; 2955 // 2 pixels for the separator 2956 2957 // Even when depressed we want the pop-up indicator background and 2958 // separator to cover the area up to the top. 2959 if ((flags & B_ACTIVATED) != 0) 2960 indicatorRect.top--; 2961 2962 // draw the separator 2963 rgb_color separatorBaseColor = base; 2964 if ((flags & B_ACTIVATED) != 0) 2965 separatorBaseColor = tint_color(base, B_DARKEN_1_TINT); 2966 2967 rgb_color separatorLightColor = _EdgeLightColor(separatorBaseColor, 2968 (flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags); 2969 rgb_color separatorShadowColor = _EdgeShadowColor(separatorBaseColor, 2970 (flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags); 2971 2972 view->BeginLineArray(2); 2973 2974 view->AddLine(BPoint(indicatorRect.left - 2, indicatorRect.top), 2975 BPoint(indicatorRect.left - 2, indicatorRect.bottom), 2976 separatorShadowColor); 2977 view->AddLine(BPoint(indicatorRect.left - 1, indicatorRect.top), 2978 BPoint(indicatorRect.left - 1, indicatorRect.bottom), 2979 separatorLightColor); 2980 2981 view->EndLineArray(); 2982 2983 // draw background and pop-up marker 2984 _DrawMenuFieldBackgroundInside(view, indicatorRect, updateRect, 2985 0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags, 0); 2986 2987 if ((flags & B_ACTIVATED) != 0) 2988 indicatorRect.top++; 2989 2990 _DrawPopUpMarker(view, indicatorRect, base, flags); 2991 } 2992 2993 // fill in the background 2994 view->FillRect(rect, fillGradient); 2995 } 2996 2997 2998 void 2999 HaikuControlLook::_DrawPopUpMarker(BView* view, const BRect& rect, 3000 const rgb_color& base, uint32 flags) 3001 { 3002 BPoint center(roundf((rect.left + rect.right) / 2.0), 3003 roundf((rect.top + rect.bottom) / 2.0)); 3004 const float metric = roundf(rect.Width() * 3.125f) / 10.0f, 3005 offset = ceilf((metric * 0.2f) * 10.0f) / 10.0f; 3006 BPoint triangle[3]; 3007 triangle[0] = center + BPoint(-metric, -offset); 3008 triangle[1] = center + BPoint(metric, -offset); 3009 triangle[2] = center + BPoint(0.0, metric * 0.8f); 3010 3011 const uint32 viewFlags = view->Flags(); 3012 view->SetFlags(viewFlags | B_SUBPIXEL_PRECISE); 3013 3014 rgb_color markColor; 3015 if ((flags & B_DISABLED) != 0) 3016 markColor = tint_color(base, 1.35); 3017 else 3018 markColor = tint_color(base, 1.65); 3019 3020 view->SetHighColor(markColor); 3021 view->FillTriangle(triangle[0], triangle[1], triangle[2]); 3022 3023 view->SetFlags(viewFlags); 3024 } 3025 3026 3027 void 3028 HaikuControlLook::_DrawMenuFieldBackgroundOutside(BView* view, BRect& rect, 3029 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 3030 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 3031 bool popupIndicator, uint32 flags) 3032 { 3033 if (!ShouldDraw(view, rect, updateRect)) 3034 return; 3035 3036 if (popupIndicator) { 3037 const float indicatorWidth = ComposeSpacing(kButtonPopUpIndicatorWidth); 3038 const float spacing = (indicatorWidth <= 11.0f) ? 1.0f : roundf(indicatorWidth / 11.0f); 3039 3040 BRect leftRect(rect); 3041 leftRect.right -= indicatorWidth - spacing; 3042 3043 BRect rightRect(rect); 3044 rightRect.left = rightRect.right - (indicatorWidth - spacing * 2); 3045 3046 _DrawMenuFieldBackgroundInside(view, leftRect, updateRect, 3047 leftTopRadius, 0.0f, leftBottomRadius, 0.0f, base, flags, 3048 B_LEFT_BORDER | B_TOP_BORDER | B_BOTTOM_BORDER); 3049 3050 _DrawMenuFieldBackgroundInside(view, rightRect, updateRect, 3051 0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags, 3052 B_TOP_BORDER | B_RIGHT_BORDER | B_BOTTOM_BORDER); 3053 3054 _DrawPopUpMarker(view, rightRect, base, flags); 3055 3056 // draw a line on the left of the popup frame 3057 rgb_color bevelShadowColor = _BevelShadowColor(base, flags); 3058 view->SetHighColor(bevelShadowColor); 3059 BPoint leftTopCorner(floorf(rightRect.left - spacing), 3060 floorf(rightRect.top - spacing)); 3061 BPoint leftBottomCorner(floorf(rightRect.left - spacing), 3062 floorf(rightRect.bottom + spacing)); 3063 for (float i = 0; i < spacing; i++) { 3064 view->StrokeLine(leftTopCorner + BPoint(i, 0), 3065 leftBottomCorner + BPoint(i, 0)); 3066 } 3067 3068 rect = leftRect; 3069 } else { 3070 _DrawMenuFieldBackgroundInside(view, rect, updateRect, leftTopRadius, 3071 rightTopRadius, leftBottomRadius, rightBottomRadius, base, flags); 3072 } 3073 } 3074 3075 3076 void 3077 HaikuControlLook::_DrawMenuFieldBackgroundInside(BView* view, BRect& rect, 3078 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 3079 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 3080 uint32 flags, uint32 borders) 3081 { 3082 if (!ShouldDraw(view, rect, updateRect)) 3083 return; 3084 3085 // save the clipping constraints of the view 3086 view->PushState(); 3087 3088 // set clipping constraints to rect 3089 view->ClipToRect(rect); 3090 3091 // frame colors 3092 rgb_color frameLightColor = _FrameLightColor(base, flags); 3093 rgb_color frameShadowColor = _FrameShadowColor(base, flags); 3094 3095 // indicator background color 3096 rgb_color indicatorBase; 3097 if ((borders & B_LEFT_BORDER) != 0) 3098 indicatorBase = base; 3099 else { 3100 if ((flags & B_DISABLED) != 0) 3101 indicatorBase = tint_color(base, 1.05); 3102 else 3103 indicatorBase = tint_color(base, 1.12); 3104 } 3105 3106 // bevel colors 3107 rgb_color cornerColor = tint_color(indicatorBase, 0.85); 3108 rgb_color bevelColor1 = tint_color(indicatorBase, 0.3); 3109 rgb_color bevelColor2 = tint_color(indicatorBase, 0.5); 3110 rgb_color bevelColor3 = tint_color(indicatorBase, 1.03); 3111 3112 if ((flags & B_DISABLED) != 0) { 3113 cornerColor = tint_color(indicatorBase, 0.8); 3114 bevelColor1 = tint_color(indicatorBase, 0.7); 3115 bevelColor2 = tint_color(indicatorBase, 0.8); 3116 bevelColor3 = tint_color(indicatorBase, 1.01); 3117 } else { 3118 cornerColor = tint_color(indicatorBase, 0.85); 3119 bevelColor1 = tint_color(indicatorBase, 0.3); 3120 bevelColor2 = tint_color(indicatorBase, 0.5); 3121 bevelColor3 = tint_color(indicatorBase, 1.03); 3122 } 3123 3124 // surface top gradient 3125 BGradientLinear fillGradient; 3126 _MakeButtonGradient(fillGradient, rect, indicatorBase, flags); 3127 3128 // rounded corners 3129 3130 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0 3131 && leftTopRadius > 0) { 3132 // draw left top rounded corner 3133 BRect leftTopCorner(floorf(rect.left), floorf(rect.top), 3134 floorf(rect.left + leftTopRadius - 2.0), 3135 floorf(rect.top + leftTopRadius - 2.0)); 3136 BRect cornerRect(leftTopCorner); 3137 3138 view->PushState(); 3139 view->ClipToRect(cornerRect); 3140 3141 BRect ellipseRect(leftTopCorner); 3142 ellipseRect.InsetBy(-1.0, -1.0); 3143 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3144 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3145 3146 // draw the frame (again) 3147 view->SetHighColor(frameLightColor); 3148 view->FillEllipse(ellipseRect); 3149 3150 // draw the bevel and background 3151 _DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect, 3152 bevelColor1, fillGradient); 3153 3154 view->PopState(); 3155 view->ClipToInverseRect(cornerRect); 3156 } 3157 3158 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0 3159 && rightTopRadius > 0) { 3160 // draw right top rounded corner 3161 BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0), 3162 floorf(rect.top), floorf(rect.right), 3163 floorf(rect.top + rightTopRadius - 2.0)); 3164 BRect cornerRect(rightTopCorner); 3165 3166 view->PushState(); 3167 view->ClipToRect(cornerRect); 3168 3169 BRect ellipseRect(rightTopCorner); 3170 ellipseRect.InsetBy(-1.0, -1.0); 3171 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3172 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3173 3174 // draw the frame (again) 3175 if (frameLightColor == frameShadowColor) { 3176 view->SetHighColor(frameLightColor); 3177 view->FillEllipse(ellipseRect); 3178 } else { 3179 BGradientLinear gradient; 3180 gradient.AddColor(frameLightColor, 0); 3181 gradient.AddColor(frameShadowColor, 255); 3182 gradient.SetStart(rightTopCorner.LeftTop()); 3183 gradient.SetEnd(rightTopCorner.RightBottom()); 3184 view->FillEllipse(ellipseRect, gradient); 3185 } 3186 3187 // draw the bevel and background 3188 _DrawRoundCornerBackgroundRightTop(view, rightTopCorner, updateRect, 3189 bevelColor1, bevelColor3, fillGradient); 3190 3191 view->PopState(); 3192 view->ClipToInverseRect(cornerRect); 3193 } 3194 3195 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 3196 && leftBottomRadius > 0) { 3197 // draw left bottom rounded corner 3198 BRect leftBottomCorner(floorf(rect.left), 3199 floorf(rect.bottom - leftBottomRadius + 2.0), 3200 floorf(rect.left + leftBottomRadius - 2.0), 3201 floorf(rect.bottom)); 3202 BRect cornerRect(leftBottomCorner); 3203 3204 view->PushState(); 3205 view->ClipToRect(cornerRect); 3206 3207 BRect ellipseRect(leftBottomCorner); 3208 ellipseRect.InsetBy(-1.0, -1.0); 3209 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3210 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3211 3212 // draw the frame (again) 3213 if (frameLightColor == frameShadowColor) { 3214 view->SetHighColor(frameLightColor); 3215 view->FillEllipse(ellipseRect); 3216 } else { 3217 BGradientLinear gradient; 3218 gradient.AddColor(frameLightColor, 0); 3219 gradient.AddColor(frameShadowColor, 255); 3220 gradient.SetStart(leftBottomCorner.LeftTop()); 3221 gradient.SetEnd(leftBottomCorner.RightBottom()); 3222 view->FillEllipse(ellipseRect, gradient); 3223 } 3224 3225 // draw the bevel and background 3226 _DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner, 3227 updateRect, bevelColor2, bevelColor3, fillGradient); 3228 3229 view->PopState(); 3230 view->ClipToInverseRect(cornerRect); 3231 } 3232 3233 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 3234 && rightBottomRadius > 0) { 3235 // draw right bottom rounded corner 3236 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0), 3237 floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right), 3238 floorf(rect.bottom)); 3239 BRect cornerRect(rightBottomCorner); 3240 3241 view->PushState(); 3242 view->ClipToRect(cornerRect); 3243 3244 BRect ellipseRect(rightBottomCorner); 3245 ellipseRect.InsetBy(-1.0, -1.0); 3246 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3247 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3248 3249 // draw the frame (again) 3250 view->SetHighColor(frameShadowColor); 3251 view->FillEllipse(ellipseRect); 3252 3253 // draw the bevel and background 3254 _DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner, 3255 updateRect, bevelColor3, fillGradient); 3256 3257 view->PopState(); 3258 view->ClipToInverseRect(cornerRect); 3259 } 3260 3261 // draw the bevel 3262 _DrawFrame(view, rect, 3263 bevelColor2, bevelColor1, 3264 bevelColor3, bevelColor3, 3265 cornerColor, cornerColor, 3266 borders); 3267 3268 // fill in the background 3269 view->FillRect(rect, fillGradient); 3270 3271 // restore the clipping constraints of the view 3272 view->PopState(); 3273 } 3274 3275 3276 void 3277 HaikuControlLook::_DrawRoundCornerLeftTop(BView* view, BRect& cornerRect, 3278 const BRect& updateRect, const rgb_color& background, 3279 const rgb_color& edgeColor, const rgb_color& frameColor, 3280 const rgb_color& bevelColor, const BGradientLinear& fillGradient) 3281 { 3282 _DrawRoundCornerFrameLeftTop(view, cornerRect, updateRect, 3283 background, edgeColor, frameColor); 3284 _DrawRoundCornerBackgroundLeftTop(view, cornerRect, updateRect, 3285 bevelColor, fillGradient); 3286 } 3287 3288 3289 void 3290 HaikuControlLook::_DrawRoundCornerFrameLeftTop(BView* view, BRect& cornerRect, 3291 const BRect& updateRect, const rgb_color& background, 3292 const rgb_color& edgeColor, const rgb_color& frameColor) 3293 { 3294 view->PushState(); 3295 3296 // constrain clipping region to corner 3297 view->ClipToRect(cornerRect); 3298 3299 // background 3300 view->SetHighColor(background); 3301 view->FillRect(cornerRect); 3302 3303 // outer edge 3304 BRect ellipseRect(cornerRect); 3305 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3306 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3307 3308 view->SetHighColor(edgeColor); 3309 view->FillEllipse(ellipseRect); 3310 3311 // frame 3312 ellipseRect.InsetBy(1, 1); 3313 cornerRect.left++; 3314 cornerRect.top++; 3315 view->SetHighColor(frameColor); 3316 view->FillEllipse(ellipseRect); 3317 3318 // prepare for bevel 3319 cornerRect.left++; 3320 cornerRect.top++; 3321 3322 view->PopState(); 3323 } 3324 3325 3326 void 3327 HaikuControlLook::_DrawRoundCornerBackgroundLeftTop(BView* view, BRect& cornerRect, 3328 const BRect& updateRect, const rgb_color& bevelColor, 3329 const BGradientLinear& fillGradient) 3330 { 3331 view->PushState(); 3332 3333 // constrain clipping region to corner 3334 view->ClipToRect(cornerRect); 3335 3336 BRect ellipseRect(cornerRect); 3337 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3338 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3339 3340 // bevel 3341 view->SetHighColor(bevelColor); 3342 view->FillEllipse(ellipseRect); 3343 3344 // gradient 3345 ellipseRect.InsetBy(1, 1); 3346 view->FillEllipse(ellipseRect, fillGradient); 3347 3348 view->PopState(); 3349 } 3350 3351 3352 void 3353 HaikuControlLook::_DrawRoundCornerRightTop(BView* view, BRect& cornerRect, 3354 const BRect& updateRect, const rgb_color& background, 3355 const rgb_color& edgeTopColor, const rgb_color& edgeRightColor, 3356 const rgb_color& frameTopColor, const rgb_color& frameRightColor, 3357 const rgb_color& bevelTopColor, const rgb_color& bevelRightColor, 3358 const BGradientLinear& fillGradient) 3359 { 3360 _DrawRoundCornerFrameRightTop(view, cornerRect, updateRect, 3361 background, edgeTopColor, edgeRightColor, frameTopColor, 3362 frameRightColor); 3363 _DrawRoundCornerBackgroundRightTop(view, cornerRect, updateRect, 3364 bevelTopColor, bevelRightColor, fillGradient); 3365 } 3366 3367 3368 void 3369 HaikuControlLook::_DrawRoundCornerFrameRightTop(BView* view, BRect& cornerRect, 3370 const BRect& updateRect, const rgb_color& background, 3371 const rgb_color& edgeTopColor, const rgb_color& edgeRightColor, 3372 const rgb_color& frameTopColor, const rgb_color& frameRightColor) 3373 { 3374 view->PushState(); 3375 3376 // constrain clipping region to corner 3377 view->ClipToRect(cornerRect); 3378 3379 // background 3380 view->SetHighColor(background); 3381 view->FillRect(cornerRect); 3382 3383 // outer edge 3384 BRect ellipseRect(cornerRect); 3385 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3386 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3387 3388 BGradientLinear gradient; 3389 gradient.AddColor(edgeTopColor, 0); 3390 gradient.AddColor(edgeRightColor, 255); 3391 gradient.SetStart(cornerRect.LeftTop()); 3392 gradient.SetEnd(cornerRect.RightBottom()); 3393 view->FillEllipse(ellipseRect, gradient); 3394 3395 // frame 3396 ellipseRect.InsetBy(1, 1); 3397 cornerRect.right--; 3398 cornerRect.top++; 3399 if (frameTopColor == frameRightColor) { 3400 view->SetHighColor(frameTopColor); 3401 view->FillEllipse(ellipseRect); 3402 } else { 3403 gradient.SetColor(0, frameTopColor); 3404 gradient.SetColor(1, frameRightColor); 3405 gradient.SetStart(cornerRect.LeftTop()); 3406 gradient.SetEnd(cornerRect.RightBottom()); 3407 view->FillEllipse(ellipseRect, gradient); 3408 } 3409 3410 // prepare for bevel 3411 cornerRect.right--; 3412 cornerRect.top++; 3413 3414 view->PopState(); 3415 } 3416 3417 3418 void 3419 HaikuControlLook::_DrawRoundCornerBackgroundRightTop(BView* view, BRect& cornerRect, 3420 const BRect& updateRect, const rgb_color& bevelTopColor, 3421 const rgb_color& bevelRightColor, const BGradientLinear& fillGradient) 3422 { 3423 view->PushState(); 3424 3425 // constrain clipping region to corner 3426 view->ClipToRect(cornerRect); 3427 3428 BRect ellipseRect(cornerRect); 3429 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3430 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3431 3432 // bevel 3433 BGradientLinear gradient; 3434 gradient.AddColor(bevelTopColor, 0); 3435 gradient.AddColor(bevelRightColor, 255); 3436 gradient.SetStart(cornerRect.LeftTop()); 3437 gradient.SetEnd(cornerRect.RightBottom()); 3438 view->FillEllipse(ellipseRect, gradient); 3439 3440 // gradient 3441 ellipseRect.InsetBy(1, 1); 3442 view->FillEllipse(ellipseRect, fillGradient); 3443 3444 view->PopState(); 3445 } 3446 3447 3448 void 3449 HaikuControlLook::_DrawRoundCornerLeftBottom(BView* view, BRect& cornerRect, 3450 const BRect& updateRect, const rgb_color& background, 3451 const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor, 3452 const rgb_color& frameLeftColor, const rgb_color& frameBottomColor, 3453 const rgb_color& bevelLeftColor, const rgb_color& bevelBottomColor, 3454 const BGradientLinear& fillGradient) 3455 { 3456 _DrawRoundCornerFrameLeftBottom(view, cornerRect, updateRect, 3457 background, edgeLeftColor, edgeBottomColor, frameLeftColor, 3458 frameBottomColor); 3459 _DrawRoundCornerBackgroundLeftBottom(view, cornerRect, updateRect, 3460 bevelLeftColor, bevelBottomColor, fillGradient); 3461 } 3462 3463 3464 void 3465 HaikuControlLook::_DrawRoundCornerFrameLeftBottom(BView* view, BRect& cornerRect, 3466 const BRect& updateRect, const rgb_color& background, 3467 const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor, 3468 const rgb_color& frameLeftColor, const rgb_color& frameBottomColor) 3469 { 3470 view->PushState(); 3471 3472 // constrain clipping region to corner 3473 view->ClipToRect(cornerRect); 3474 3475 // background 3476 view->SetHighColor(background); 3477 view->FillRect(cornerRect); 3478 3479 // outer edge 3480 BRect ellipseRect(cornerRect); 3481 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3482 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3483 3484 BGradientLinear gradient; 3485 gradient.AddColor(edgeLeftColor, 0); 3486 gradient.AddColor(edgeBottomColor, 255); 3487 gradient.SetStart(cornerRect.LeftTop()); 3488 gradient.SetEnd(cornerRect.RightBottom()); 3489 view->FillEllipse(ellipseRect, gradient); 3490 3491 // frame 3492 ellipseRect.InsetBy(1, 1); 3493 cornerRect.left++; 3494 cornerRect.bottom--; 3495 if (frameLeftColor == frameBottomColor) { 3496 view->SetHighColor(frameLeftColor); 3497 view->FillEllipse(ellipseRect); 3498 } else { 3499 gradient.SetColor(0, frameLeftColor); 3500 gradient.SetColor(1, frameBottomColor); 3501 gradient.SetStart(cornerRect.LeftTop()); 3502 gradient.SetEnd(cornerRect.RightBottom()); 3503 view->FillEllipse(ellipseRect, gradient); 3504 } 3505 3506 // prepare for bevel 3507 cornerRect.left++; 3508 cornerRect.bottom--; 3509 3510 view->PopState(); 3511 } 3512 3513 3514 void 3515 HaikuControlLook::_DrawRoundCornerBackgroundLeftBottom(BView* view, BRect& cornerRect, 3516 const BRect& updateRect, const rgb_color& bevelLeftColor, 3517 const rgb_color& bevelBottomColor, const BGradientLinear& fillGradient) 3518 { 3519 view->PushState(); 3520 3521 // constrain clipping region to corner 3522 view->ClipToRect(cornerRect); 3523 3524 BRect ellipseRect(cornerRect); 3525 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3526 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3527 3528 // bevel 3529 BGradientLinear gradient; 3530 gradient.AddColor(bevelLeftColor, 0); 3531 gradient.AddColor(bevelBottomColor, 255); 3532 gradient.SetStart(cornerRect.LeftTop()); 3533 gradient.SetEnd(cornerRect.RightBottom()); 3534 view->FillEllipse(ellipseRect, gradient); 3535 3536 // gradient 3537 ellipseRect.InsetBy(1, 1); 3538 view->FillEllipse(ellipseRect, fillGradient); 3539 3540 view->PopState(); 3541 } 3542 3543 3544 void 3545 HaikuControlLook::_DrawRoundCornerRightBottom(BView* view, BRect& cornerRect, 3546 const BRect& updateRect, const rgb_color& background, 3547 const rgb_color& edgeColor, const rgb_color& frameColor, 3548 const rgb_color& bevelColor, const BGradientLinear& fillGradient) 3549 { 3550 _DrawRoundCornerFrameRightBottom(view, cornerRect, updateRect, 3551 background, edgeColor, frameColor); 3552 _DrawRoundCornerBackgroundRightBottom(view, cornerRect, updateRect, 3553 bevelColor, fillGradient); 3554 } 3555 3556 3557 void 3558 HaikuControlLook::_DrawRoundCornerFrameRightBottom(BView* view, BRect& cornerRect, 3559 const BRect& updateRect, const rgb_color& background, 3560 const rgb_color& edgeColor, const rgb_color& frameColor) 3561 { 3562 view->PushState(); 3563 3564 // constrain clipping region to corner 3565 view->ClipToRect(cornerRect); 3566 3567 // background 3568 view->SetHighColor(background); 3569 view->FillRect(cornerRect); 3570 3571 // outer edge 3572 BRect ellipseRect(cornerRect); 3573 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3574 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3575 3576 view->SetHighColor(edgeColor); 3577 view->FillEllipse(ellipseRect); 3578 3579 // frame 3580 ellipseRect.InsetBy(1, 1); 3581 cornerRect.right--; 3582 cornerRect.bottom--; 3583 view->SetHighColor(frameColor); 3584 view->FillEllipse(ellipseRect); 3585 3586 // prepare for bevel 3587 cornerRect.right--; 3588 cornerRect.bottom--; 3589 3590 view->PopState(); 3591 } 3592 3593 3594 void 3595 HaikuControlLook::_DrawRoundCornerBackgroundRightBottom(BView* view, 3596 BRect& cornerRect, const BRect& updateRect, const rgb_color& bevelColor, 3597 const BGradientLinear& fillGradient) 3598 { 3599 view->PushState(); 3600 3601 // constrain clipping region to corner 3602 view->ClipToRect(cornerRect); 3603 3604 BRect ellipseRect(cornerRect); 3605 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3606 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3607 3608 // bevel 3609 view->SetHighColor(bevelColor); 3610 view->FillEllipse(ellipseRect); 3611 3612 // gradient 3613 ellipseRect.InsetBy(1, 1); 3614 view->FillEllipse(ellipseRect, fillGradient); 3615 3616 view->PopState(); 3617 } 3618 3619 3620 void 3621 HaikuControlLook::_DrawRoundBarCorner(BView* view, BRect& rect, 3622 const BRect& updateRect, 3623 const rgb_color& edgeLightColor, const rgb_color& edgeShadowColor, 3624 const rgb_color& frameLightColor, const rgb_color& frameShadowColor, 3625 const rgb_color& fillLightColor, const rgb_color& fillShadowColor, 3626 float leftInset, float topInset, float rightInset, float bottomInset, 3627 orientation orientation) 3628 { 3629 if (!ShouldDraw(view, rect, updateRect)) 3630 return; 3631 3632 BGradientLinear gradient; 3633 gradient.AddColor(edgeShadowColor, 0); 3634 gradient.AddColor(edgeLightColor, 255); 3635 gradient.SetStart(rect.LeftTop()); 3636 if (orientation == B_HORIZONTAL) 3637 gradient.SetEnd(rect.LeftBottom()); 3638 else 3639 gradient.SetEnd(rect.RightTop()); 3640 3641 view->FillEllipse(rect, gradient); 3642 3643 rect.left += leftInset; 3644 rect.top += topInset; 3645 rect.right += rightInset; 3646 rect.bottom += bottomInset; 3647 3648 gradient.MakeEmpty(); 3649 gradient.AddColor(frameShadowColor, 0); 3650 gradient.AddColor(frameLightColor, 255); 3651 gradient.SetStart(rect.LeftTop()); 3652 if (orientation == B_HORIZONTAL) 3653 gradient.SetEnd(rect.LeftBottom()); 3654 else 3655 gradient.SetEnd(rect.RightTop()); 3656 3657 view->FillEllipse(rect, gradient); 3658 3659 rect.left += leftInset; 3660 rect.top += topInset; 3661 rect.right += rightInset; 3662 rect.bottom += bottomInset; 3663 3664 gradient.MakeEmpty(); 3665 gradient.AddColor(fillShadowColor, 0); 3666 gradient.AddColor(fillLightColor, 255); 3667 gradient.SetStart(rect.LeftTop()); 3668 if (orientation == B_HORIZONTAL) 3669 gradient.SetEnd(rect.LeftBottom()); 3670 else 3671 gradient.SetEnd(rect.RightTop()); 3672 3673 view->FillEllipse(rect, gradient); 3674 } 3675 3676 3677 rgb_color 3678 HaikuControlLook::_EdgeLightColor(const rgb_color& base, float contrast, 3679 float brightness, uint32 flags) 3680 { 3681 rgb_color edgeLightColor; 3682 3683 if ((flags & B_BLEND_FRAME) != 0) { 3684 uint8 alpha = uint8(20 * contrast); 3685 uint8 white = uint8(255 * brightness); 3686 3687 edgeLightColor = (rgb_color){ white, white, white, alpha }; 3688 } else { 3689 // colors 3690 float tintLight = kEdgeBevelLightTint; 3691 3692 if (contrast == 0.0) 3693 tintLight = B_NO_TINT; 3694 else if (contrast != 1.0) 3695 tintLight = B_NO_TINT + (tintLight - B_NO_TINT) * contrast; 3696 3697 edgeLightColor = tint_color(base, tintLight); 3698 3699 if (brightness < 1.0) { 3700 edgeLightColor.red = uint8(edgeLightColor.red * brightness); 3701 edgeLightColor.green = uint8(edgeLightColor.green * brightness); 3702 edgeLightColor.blue = uint8(edgeLightColor.blue * brightness); 3703 } 3704 } 3705 3706 return edgeLightColor; 3707 } 3708 3709 3710 rgb_color 3711 HaikuControlLook::_EdgeShadowColor(const rgb_color& base, float contrast, 3712 float brightness, uint32 flags) 3713 { 3714 rgb_color edgeShadowColor; 3715 3716 if ((flags & B_BLEND_FRAME) != 0) { 3717 uint8 alpha = uint8(20 * contrast); 3718 edgeShadowColor = (rgb_color){ 0, 0, 0, alpha }; 3719 } else { 3720 float tintShadow = kEdgeBevelShadowTint; 3721 3722 if (contrast == 0.0) 3723 tintShadow = B_NO_TINT; 3724 else if (contrast != 1.0) 3725 tintShadow = B_NO_TINT + (tintShadow - B_NO_TINT) * contrast; 3726 3727 edgeShadowColor = tint_color(base, tintShadow); 3728 3729 if (brightness < 1.0) { 3730 edgeShadowColor.red = uint8(edgeShadowColor.red * brightness); 3731 edgeShadowColor.green = uint8(edgeShadowColor.green * brightness); 3732 edgeShadowColor.blue = uint8(edgeShadowColor.blue * brightness); 3733 } 3734 } 3735 3736 return edgeShadowColor; 3737 } 3738 3739 3740 rgb_color 3741 HaikuControlLook::_FrameLightColor(const rgb_color& base, uint32 flags) 3742 { 3743 if ((flags & B_FOCUSED) != 0) 3744 return ui_color(B_KEYBOARD_NAVIGATION_COLOR); 3745 3746 if ((flags & B_ACTIVATED) != 0) 3747 return _FrameShadowColor(base, flags & ~B_ACTIVATED); 3748 3749 rgb_color frameLightColor; 3750 3751 if ((flags & B_DISABLED) != 0) { 3752 // TODO: B_BLEND_FRAME 3753 frameLightColor = tint_color(base, 1.145); 3754 3755 if ((flags & B_DEFAULT_BUTTON) != 0) 3756 frameLightColor = tint_color(frameLightColor, 1.14); 3757 } else { 3758 if ((flags & B_BLEND_FRAME) != 0) 3759 frameLightColor = (rgb_color){ 0, 0, 0, 75 }; 3760 else 3761 frameLightColor = tint_color(base, 1.33); 3762 3763 if ((flags & B_DEFAULT_BUTTON) != 0) 3764 frameLightColor = tint_color(frameLightColor, 1.35); 3765 } 3766 3767 return frameLightColor; 3768 } 3769 3770 3771 rgb_color 3772 HaikuControlLook::_FrameShadowColor(const rgb_color& base, uint32 flags) 3773 { 3774 if ((flags & B_FOCUSED) != 0) 3775 return ui_color(B_KEYBOARD_NAVIGATION_COLOR); 3776 3777 if ((flags & B_ACTIVATED) != 0) 3778 return _FrameLightColor(base, flags & ~B_ACTIVATED); 3779 3780 rgb_color frameShadowColor; 3781 3782 if ((flags & B_DISABLED) != 0) { 3783 // TODO: B_BLEND_FRAME 3784 frameShadowColor = tint_color(base, 1.24); 3785 3786 if ((flags & B_DEFAULT_BUTTON) != 0) { 3787 frameShadowColor = tint_color(base, 1.145); 3788 frameShadowColor = tint_color(frameShadowColor, 1.12); 3789 } 3790 } else { 3791 if ((flags & B_DEFAULT_BUTTON) != 0) { 3792 if ((flags & B_BLEND_FRAME) != 0) 3793 frameShadowColor = (rgb_color){ 0, 0, 0, 75 }; 3794 else 3795 frameShadowColor = tint_color(base, 1.33); 3796 3797 frameShadowColor = tint_color(frameShadowColor, 1.5); 3798 } else { 3799 if ((flags & B_BLEND_FRAME) != 0) 3800 frameShadowColor = (rgb_color){ 0, 0, 0, 95 }; 3801 else 3802 frameShadowColor = tint_color(base, 1.47); 3803 } 3804 } 3805 3806 return frameShadowColor; 3807 } 3808 3809 3810 rgb_color 3811 HaikuControlLook::_BevelLightColor(const rgb_color& base, uint32 flags) 3812 { 3813 rgb_color bevelLightColor = tint_color(base, 0.2); 3814 3815 if ((flags & B_DISABLED) != 0) 3816 bevelLightColor = tint_color(base, B_LIGHTEN_1_TINT); 3817 3818 if ((flags & B_ACTIVATED) != 0) 3819 bevelLightColor = tint_color(base, B_DARKEN_1_TINT); 3820 3821 return bevelLightColor; 3822 } 3823 3824 3825 rgb_color 3826 HaikuControlLook::_BevelShadowColor(const rgb_color& base, uint32 flags) 3827 { 3828 rgb_color bevelShadowColor = tint_color(base, 1.08); 3829 3830 if ((flags & B_DISABLED) != 0) 3831 bevelShadowColor = base; 3832 3833 if ((flags & B_ACTIVATED) != 0) 3834 bevelShadowColor = tint_color(base, B_DARKEN_1_TINT); 3835 3836 return bevelShadowColor; 3837 } 3838 3839 3840 void 3841 HaikuControlLook::_FillGradient(BView* view, const BRect& rect, 3842 const rgb_color& base, float topTint, float bottomTint, 3843 orientation orientation) 3844 { 3845 BGradientLinear gradient; 3846 _MakeGradient(gradient, rect, base, topTint, bottomTint, orientation); 3847 view->FillRect(rect, gradient); 3848 } 3849 3850 3851 void 3852 HaikuControlLook::_FillGlossyGradient(BView* view, const BRect& rect, 3853 const rgb_color& base, float topTint, float middle1Tint, 3854 float middle2Tint, float bottomTint, orientation orientation) 3855 { 3856 BGradientLinear gradient; 3857 _MakeGlossyGradient(gradient, rect, base, topTint, middle1Tint, 3858 middle2Tint, bottomTint, orientation); 3859 view->FillRect(rect, gradient); 3860 } 3861 3862 3863 void 3864 HaikuControlLook::_MakeGradient(BGradientLinear& gradient, const BRect& rect, 3865 const rgb_color& base, float topTint, float bottomTint, 3866 orientation orientation) const 3867 { 3868 gradient.AddColor(tint_color(base, topTint), 0); 3869 gradient.AddColor(tint_color(base, bottomTint), 255); 3870 gradient.SetStart(rect.LeftTop()); 3871 if (orientation == B_HORIZONTAL) 3872 gradient.SetEnd(rect.LeftBottom()); 3873 else 3874 gradient.SetEnd(rect.RightTop()); 3875 } 3876 3877 3878 void 3879 HaikuControlLook::_MakeGlossyGradient(BGradientLinear& gradient, const BRect& rect, 3880 const rgb_color& base, float topTint, float middle1Tint, 3881 float middle2Tint, float bottomTint, 3882 orientation orientation) const 3883 { 3884 gradient.AddColor(tint_color(base, topTint), 0); 3885 gradient.AddColor(tint_color(base, middle1Tint), 132); 3886 gradient.AddColor(tint_color(base, middle2Tint), 136); 3887 gradient.AddColor(tint_color(base, bottomTint), 255); 3888 gradient.SetStart(rect.LeftTop()); 3889 if (orientation == B_HORIZONTAL) 3890 gradient.SetEnd(rect.LeftBottom()); 3891 else 3892 gradient.SetEnd(rect.RightTop()); 3893 } 3894 3895 3896 void 3897 HaikuControlLook::_MakeButtonGradient(BGradientLinear& gradient, BRect& rect, 3898 const rgb_color& base, uint32 flags, orientation orientation) const 3899 { 3900 float topTint = 0.49; 3901 float middleTint1 = 0.62; 3902 float middleTint2 = 0.76; 3903 float bottomTint = 0.90; 3904 3905 if ((flags & B_ACTIVATED) != 0) { 3906 topTint = 1.11; 3907 bottomTint = 1.08; 3908 } 3909 3910 if ((flags & B_DISABLED) != 0) { 3911 topTint = (topTint + B_NO_TINT) / 2; 3912 middleTint1 = (middleTint1 + B_NO_TINT) / 2; 3913 middleTint2 = (middleTint2 + B_NO_TINT) / 2; 3914 bottomTint = (bottomTint + B_NO_TINT) / 2; 3915 } else if ((flags & B_HOVER) != 0) { 3916 topTint *= kHoverTintFactor; 3917 middleTint1 *= kHoverTintFactor; 3918 middleTint2 *= kHoverTintFactor; 3919 bottomTint *= kHoverTintFactor; 3920 } 3921 3922 if ((flags & B_ACTIVATED) != 0) { 3923 _MakeGradient(gradient, rect, base, topTint, bottomTint, orientation); 3924 } else { 3925 _MakeGlossyGradient(gradient, rect, base, topTint, middleTint1, 3926 middleTint2, bottomTint, orientation); 3927 } 3928 } 3929 3930 3931 bool 3932 HaikuControlLook::_RadioButtonAndCheckBoxMarkColor(const rgb_color& base, 3933 rgb_color& color, uint32 flags) const 3934 { 3935 if ((flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED | B_CLICKED)) == 0) { 3936 // no mark to be drawn at all 3937 return false; 3938 } 3939 3940 color = ui_color(B_CONTROL_MARK_COLOR); 3941 3942 float mix = 1.0; 3943 3944 if ((flags & B_DISABLED) != 0) { 3945 // activated, but disabled 3946 mix = 0.4; 3947 } else if ((flags & B_CLICKED) != 0) { 3948 if ((flags & B_ACTIVATED) != 0) { 3949 // losing activation 3950 mix = 0.7; 3951 } else { 3952 // becoming activated (or losing partial activation) 3953 mix = 0.3; 3954 } 3955 } else if ((flags & B_PARTIALLY_ACTIVATED) != 0) { 3956 // partially activated 3957 mix = 0.5; 3958 } else { 3959 // simply activated 3960 } 3961 3962 color.red = uint8(color.red * mix + base.red * (1.0 - mix)); 3963 color.green = uint8(color.green * mix + base.green * (1.0 - mix)); 3964 color.blue = uint8(color.blue * mix + base.blue * (1.0 - mix)); 3965 3966 return true; 3967 } 3968 3969 } // namespace BPrivate 3970