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