1 /* 2 * Copyright 2009, Stephan Aßmus <superstippi@gmx.de> 3 * Copyright 2012-2020 Haiku, Inc. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 * 6 * Authors: 7 * Stephan Aßmus, superstippi@gmx.de 8 * John Scipione, jscipione@gmail.com 9 */ 10 11 12 #include <HaikuControlLook.h> 13 14 #include <algorithm> 15 16 #include <Bitmap.h> 17 #include <Control.h> 18 #include <GradientLinear.h> 19 #include <LayoutUtils.h> 20 #include <Region.h> 21 #include <Shape.h> 22 #include <String.h> 23 #include <TabView.h> 24 #include <View.h> 25 #include <Window.h> 26 #include <WindowPrivate.h> 27 28 29 namespace BPrivate { 30 31 static const float kEdgeBevelLightTint = 0.59; 32 static const float kEdgeBevelShadowTint = 1.0735; 33 static const float kHoverTintFactor = 0.85; 34 35 static const int32 kButtonPopUpIndicatorWidth = B_USE_ITEM_SPACING; 36 37 38 HaikuControlLook::HaikuControlLook() 39 : 40 fCachedOutline(false) 41 { 42 } 43 44 45 HaikuControlLook::~HaikuControlLook() 46 { 47 } 48 49 50 BAlignment 51 HaikuControlLook::DefaultLabelAlignment() const 52 { 53 return BAlignment(B_ALIGN_LEFT, B_ALIGN_VERTICAL_CENTER); 54 } 55 56 57 float 58 HaikuControlLook::DefaultLabelSpacing() const 59 { 60 return ceilf(be_plain_font->Size() / 2.0); 61 } 62 63 64 float 65 HaikuControlLook::DefaultItemSpacing() const 66 { 67 return ceilf(be_plain_font->Size() * 0.85); 68 } 69 70 71 uint32 72 HaikuControlLook::Flags(BControl* control) const 73 { 74 uint32 flags = B_IS_CONTROL; 75 76 if (!control->IsEnabled()) 77 flags |= B_DISABLED; 78 79 if (control->IsFocus() && control->Window() != NULL 80 && control->Window()->IsActive()) { 81 flags |= B_FOCUSED; 82 } 83 84 switch (control->Value()) { 85 case B_CONTROL_ON: 86 flags |= B_ACTIVATED; 87 break; 88 case B_CONTROL_PARTIALLY_ON: 89 flags |= B_PARTIALLY_ACTIVATED; 90 break; 91 } 92 93 if (control->Parent() != NULL 94 && (control->Parent()->Flags() & B_DRAW_ON_CHILDREN) != 0) { 95 // In this constellation, assume we want to render the control 96 // against the already existing view contents of the parent view. 97 flags |= B_BLEND_FRAME; 98 } 99 100 return flags; 101 } 102 103 104 // #pragma mark - 105 106 107 void 108 HaikuControlLook::DrawButtonFrame(BView* view, BRect& rect, const BRect& updateRect, 109 const rgb_color& base, const rgb_color& background, uint32 flags, 110 uint32 borders) 111 { 112 _DrawButtonFrame(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f, base, 113 background, 1.0, 1.0, flags, borders); 114 } 115 116 117 void 118 HaikuControlLook::DrawButtonFrame(BView* view, BRect& rect, const BRect& updateRect, 119 float radius, const rgb_color& base, const rgb_color& background, uint32 flags, 120 uint32 borders) 121 { 122 _DrawButtonFrame(view, rect, updateRect, radius, radius, radius, radius, 123 base, background, 1.0, 1.0, flags, borders); 124 } 125 126 127 void 128 HaikuControlLook::DrawButtonFrame(BView* view, BRect& rect, 129 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 130 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 131 const rgb_color& background, uint32 flags, 132 uint32 borders) 133 { 134 _DrawButtonFrame(view, rect, updateRect, leftTopRadius, rightTopRadius, 135 leftBottomRadius, rightBottomRadius, base, background, 136 1.0, 1.0, flags, borders); 137 } 138 139 140 void 141 HaikuControlLook::DrawButtonBackground(BView* view, BRect& rect, 142 const BRect& updateRect, const rgb_color& base, uint32 flags, 143 uint32 borders, orientation orientation) 144 { 145 _DrawButtonBackground(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f, 146 base, false, flags, borders, orientation); 147 } 148 149 150 void 151 HaikuControlLook::DrawButtonBackground(BView* view, BRect& rect, 152 const BRect& updateRect, float radius, const rgb_color& base, uint32 flags, 153 uint32 borders, orientation orientation) 154 { 155 _DrawButtonBackground(view, rect, updateRect, radius, radius, radius, 156 radius, base, false, flags, borders, orientation); 157 } 158 159 160 void 161 HaikuControlLook::DrawButtonBackground(BView* view, BRect& rect, 162 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 163 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 164 uint32 flags, uint32 borders, orientation orientation) 165 { 166 _DrawButtonBackground(view, rect, updateRect, leftTopRadius, 167 rightTopRadius, leftBottomRadius, rightBottomRadius, base, false, flags, 168 borders, orientation); 169 } 170 171 172 void 173 HaikuControlLook::DrawMenuBarBackground(BView* view, BRect& rect, 174 const BRect& updateRect, const rgb_color& base, uint32 flags, 175 uint32 borders) 176 { 177 if (!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 bool isVertical; 1878 switch (side) { 1879 default: 1880 case BTabView::kTopSide: 1881 rect.top += 4; 1882 background.bottom = rect.top; 1883 isVertical = false; 1884 break; 1885 1886 case BTabView::kBottomSide: 1887 rect.bottom -= 4; 1888 background.top = rect.bottom; 1889 isVertical = false; 1890 break; 1891 1892 case BTabView::kLeftSide: 1893 rect.left += 4; 1894 background.right = rect.left; 1895 isVertical = true; 1896 break; 1897 1898 case BTabView::kRightSide: 1899 rect.right -= 4; 1900 background.left = rect.right; 1901 isVertical = true; 1902 break; 1903 } 1904 1905 // active tabs stand out at the top, but this is an inactive tab 1906 view->SetHighColor(base); 1907 view->FillRect(background); 1908 1909 // frame and fill 1910 // Note that _DrawFrame also insets the rect, so each of the calls here 1911 // operate on a smaller rect than the previous ones 1912 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, edgeLightColor, 1913 edgeLightColor, borders); 1914 1915 _DrawFrame(view, rect, frameLightColor, frameLightColor, frameShadowColor, 1916 frameShadowColor, borders); 1917 1918 if (rect.IsValid()) { 1919 if (isVertical) { 1920 _DrawFrame(view, rect, bevelShadowColor, bevelShadowColor, 1921 bevelLightColor, bevelLightColor, B_TOP_BORDER & ~borders); 1922 } else { 1923 _DrawFrame(view, rect, bevelShadowColor, bevelShadowColor, 1924 bevelLightColor, bevelLightColor, B_LEFT_BORDER & ~borders); 1925 } 1926 } else { 1927 if (isVertical) { 1928 if ((B_LEFT_BORDER & ~borders) != 0) 1929 rect.left++; 1930 } else { 1931 if ((B_TOP_BORDER & ~borders) != 0) 1932 rect.top++; 1933 } 1934 } 1935 1936 view->FillRect(rect, fillGradient); 1937 } 1938 1939 1940 void 1941 HaikuControlLook::DrawSplitter(BView* view, BRect& rect, const BRect& updateRect, 1942 const rgb_color& base, orientation orientation, uint32 flags, 1943 uint32 borders) 1944 { 1945 if (!rect.IsValid() || !rect.Intersects(updateRect)) 1946 return; 1947 1948 rgb_color background; 1949 if ((flags & (B_CLICKED | B_ACTIVATED)) != 0) 1950 background = tint_color(base, B_DARKEN_1_TINT); 1951 else 1952 background = base; 1953 1954 rgb_color light = tint_color(background, 0.6); 1955 rgb_color shadow = tint_color(background, 1.21); 1956 1957 // frame 1958 if (borders != 0 && rect.Width() > 3 && rect.Height() > 3) 1959 DrawRaisedBorder(view, rect, updateRect, background, flags, borders); 1960 1961 // dots and rest of background 1962 if (orientation == B_HORIZONTAL) { 1963 if (rect.Width() > 2) { 1964 // background on left/right 1965 BRegion region(rect); 1966 rect.left = floorf((rect.left + rect.right) / 2.0 - 0.5); 1967 rect.right = rect.left + 1; 1968 region.Exclude(rect); 1969 view->SetHighColor(background); 1970 view->FillRegion(®ion); 1971 } 1972 1973 BPoint dot = rect.LeftTop(); 1974 BPoint stop = rect.LeftBottom(); 1975 int32 num = 1; 1976 while (dot.y <= stop.y) { 1977 rgb_color col1; 1978 rgb_color col2; 1979 switch (num) { 1980 case 1: 1981 col1 = background; 1982 col2 = background; 1983 break; 1984 case 2: 1985 col1 = shadow; 1986 col2 = background; 1987 break; 1988 case 3: 1989 default: 1990 col1 = background; 1991 col2 = light; 1992 num = 0; 1993 break; 1994 } 1995 view->SetHighColor(col1); 1996 view->StrokeLine(dot, dot, B_SOLID_HIGH); 1997 view->SetHighColor(col2); 1998 dot.x++; 1999 view->StrokeLine(dot, dot, B_SOLID_HIGH); 2000 dot.x -= 1.0; 2001 // next pixel 2002 num++; 2003 dot.y++; 2004 } 2005 } else { 2006 if (rect.Height() > 2) { 2007 // background on left/right 2008 BRegion region(rect); 2009 rect.top = floorf((rect.top + rect.bottom) / 2.0 - 0.5); 2010 rect.bottom = rect.top + 1; 2011 region.Exclude(rect); 2012 view->SetHighColor(background); 2013 view->FillRegion(®ion); 2014 } 2015 2016 BPoint dot = rect.LeftTop(); 2017 BPoint stop = rect.RightTop(); 2018 int32 num = 1; 2019 while (dot.x <= stop.x) { 2020 rgb_color col1; 2021 rgb_color col2; 2022 switch (num) { 2023 case 1: 2024 col1 = background; 2025 col2 = background; 2026 break; 2027 case 2: 2028 col1 = shadow; 2029 col2 = background; 2030 break; 2031 case 3: 2032 default: 2033 col1 = background; 2034 col2 = light; 2035 num = 0; 2036 break; 2037 } 2038 view->SetHighColor(col1); 2039 view->StrokeLine(dot, dot, B_SOLID_HIGH); 2040 view->SetHighColor(col2); 2041 dot.y++; 2042 view->StrokeLine(dot, dot, B_SOLID_HIGH); 2043 dot.y -= 1.0; 2044 // next pixel 2045 num++; 2046 dot.x++; 2047 } 2048 } 2049 } 2050 2051 2052 // #pragma mark - 2053 2054 2055 void 2056 HaikuControlLook::DrawBorder(BView* view, BRect& rect, const BRect& updateRect, 2057 const rgb_color& base, border_style borderStyle, uint32 flags, 2058 uint32 borders) 2059 { 2060 if (borderStyle == B_NO_BORDER) 2061 return; 2062 2063 rgb_color scrollbarFrameColor = tint_color(base, B_DARKEN_2_TINT); 2064 if (base.red + base.green + base.blue <= 128 * 3) { 2065 scrollbarFrameColor = tint_color(base, B_LIGHTEN_1_TINT); 2066 } 2067 2068 if ((flags & B_FOCUSED) != 0) 2069 scrollbarFrameColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 2070 2071 if (borderStyle == B_FANCY_BORDER) 2072 _DrawOuterResessedFrame(view, rect, base, 1.0, 1.0, flags, borders); 2073 2074 _DrawFrame(view, rect, scrollbarFrameColor, scrollbarFrameColor, 2075 scrollbarFrameColor, scrollbarFrameColor, borders); 2076 } 2077 2078 2079 void 2080 HaikuControlLook::DrawRaisedBorder(BView* view, BRect& rect, 2081 const BRect& updateRect, const rgb_color& base, uint32 flags, 2082 uint32 borders) 2083 { 2084 rgb_color lightColor; 2085 rgb_color shadowColor; 2086 2087 if ((flags & B_DISABLED) != 0) { 2088 lightColor = base; 2089 shadowColor = base; 2090 } else { 2091 lightColor = tint_color(base, 0.85); 2092 shadowColor = tint_color(base, 1.07); 2093 } 2094 2095 _DrawFrame(view, rect, lightColor, lightColor, shadowColor, shadowColor, 2096 borders); 2097 } 2098 2099 2100 void 2101 HaikuControlLook::DrawTextControlBorder(BView* view, BRect& rect, 2102 const BRect& updateRect, const rgb_color& base, uint32 flags, 2103 uint32 borders) 2104 { 2105 if (!rect.Intersects(updateRect)) 2106 return; 2107 2108 rgb_color dark1BorderColor; 2109 rgb_color dark2BorderColor; 2110 rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 2111 rgb_color invalidColor = ui_color(B_FAILURE_COLOR); 2112 2113 if ((flags & B_DISABLED) != 0) { 2114 _DrawOuterResessedFrame(view, rect, base, 0.0, 1.0, flags, borders); 2115 2116 if ((flags & B_BLEND_FRAME) != 0) 2117 dark1BorderColor = (rgb_color){ 0, 0, 0, 40 }; 2118 else 2119 dark1BorderColor = tint_color(base, 1.15); 2120 dark2BorderColor = dark1BorderColor; 2121 } else if ((flags & B_CLICKED) != 0) { 2122 dark1BorderColor = tint_color(base, 1.50); 2123 dark2BorderColor = tint_color(base, 1.49); 2124 2125 // BCheckBox uses this to indicate the clicked state... 2126 _DrawFrame(view, rect, 2127 dark1BorderColor, dark1BorderColor, 2128 dark2BorderColor, dark2BorderColor); 2129 2130 dark2BorderColor = dark1BorderColor; 2131 } else { 2132 _DrawOuterResessedFrame(view, rect, base, 0.6, 1.0, flags, borders); 2133 2134 if ((flags & B_BLEND_FRAME) != 0) { 2135 dark1BorderColor = (rgb_color){ 0, 0, 0, 102 }; 2136 dark2BorderColor = (rgb_color){ 0, 0, 0, 97 }; 2137 } else { 2138 dark1BorderColor = tint_color(base, 1.40); 2139 dark2BorderColor = tint_color(base, 1.38); 2140 } 2141 } 2142 2143 if ((flags & B_DISABLED) == 0 && (flags & B_FOCUSED) != 0) { 2144 dark1BorderColor = navigationColor; 2145 dark2BorderColor = navigationColor; 2146 } 2147 2148 if ((flags & B_DISABLED) == 0 && (flags & B_INVALID) != 0) { 2149 dark1BorderColor = invalidColor; 2150 dark2BorderColor = invalidColor; 2151 } 2152 2153 if ((flags & B_BLEND_FRAME) != 0) { 2154 drawing_mode oldMode = view->DrawingMode(); 2155 view->SetDrawingMode(B_OP_ALPHA); 2156 2157 _DrawFrame(view, rect, 2158 dark1BorderColor, dark1BorderColor, 2159 dark2BorderColor, dark2BorderColor, borders); 2160 2161 view->SetDrawingMode(oldMode); 2162 } else { 2163 _DrawFrame(view, rect, 2164 dark1BorderColor, dark1BorderColor, 2165 dark2BorderColor, dark2BorderColor, borders); 2166 } 2167 } 2168 2169 2170 void 2171 HaikuControlLook::DrawGroupFrame(BView* view, BRect& rect, const BRect& updateRect, 2172 const rgb_color& base, uint32 borders) 2173 { 2174 rgb_color frameColor = tint_color(base, 1.30); 2175 rgb_color bevelLight = tint_color(base, 0.8); 2176 rgb_color bevelShadow = tint_color(base, 1.03); 2177 2178 _DrawFrame(view, rect, bevelShadow, bevelShadow, bevelLight, bevelLight, 2179 borders); 2180 2181 _DrawFrame(view, rect, frameColor, frameColor, frameColor, frameColor, 2182 borders); 2183 2184 _DrawFrame(view, rect, bevelLight, bevelLight, bevelShadow, bevelShadow, 2185 borders); 2186 } 2187 2188 2189 void 2190 HaikuControlLook::DrawLabel(BView* view, const char* label, BRect rect, 2191 const BRect& updateRect, const rgb_color& base, uint32 flags, 2192 const rgb_color* textColor) 2193 { 2194 DrawLabel(view, label, NULL, rect, updateRect, base, flags, 2195 DefaultLabelAlignment(), textColor); 2196 } 2197 2198 2199 void 2200 HaikuControlLook::DrawLabel(BView* view, const char* label, BRect rect, 2201 const BRect& updateRect, const rgb_color& base, uint32 flags, 2202 const BAlignment& alignment, const rgb_color* textColor) 2203 { 2204 DrawLabel(view, label, NULL, rect, updateRect, base, flags, alignment, 2205 textColor); 2206 } 2207 2208 2209 void 2210 HaikuControlLook::DrawLabel(BView* view, const char* label, const rgb_color& base, 2211 uint32 flags, const BPoint& where, const rgb_color* textColor) 2212 { 2213 // setup the text color 2214 2215 BWindow* window = view->Window(); 2216 bool isDesktop = window 2217 && window->Feel() == kDesktopWindowFeel 2218 && window->Look() == kDesktopWindowLook 2219 && view->Parent() 2220 && view->Parent()->Parent() == NULL 2221 && (flags & B_IGNORE_OUTLINE) == 0; 2222 2223 rgb_color low; 2224 rgb_color color; 2225 rgb_color glowColor; 2226 2227 if (textColor != NULL) 2228 glowColor = *textColor; 2229 else if ((flags & B_IS_CONTROL) != 0) 2230 glowColor = ui_color(B_CONTROL_TEXT_COLOR); 2231 else 2232 glowColor = ui_color(B_PANEL_TEXT_COLOR); 2233 2234 color = glowColor; 2235 2236 if (isDesktop) 2237 low = view->Parent()->ViewColor(); 2238 else 2239 low = base; 2240 2241 if ((flags & B_DISABLED) != 0) { 2242 color.red = (uint8)(((int32)low.red + color.red + 1) / 2); 2243 color.green = (uint8)(((int32)low.green + color.green + 1) / 2); 2244 color.blue = (uint8)(((int32)low.blue + color.blue + 1) / 2); 2245 } 2246 2247 drawing_mode oldMode = view->DrawingMode(); 2248 2249 if (isDesktop) { 2250 // enforce proper use of desktop label colors 2251 if (low.Brightness() < 100) { 2252 if (textColor == NULL) 2253 color = make_color(255, 255, 255); 2254 2255 glowColor = make_color(0, 0, 0); 2256 } else { 2257 if (textColor == NULL) 2258 color = make_color(0, 0, 0); 2259 2260 glowColor = make_color(255, 255, 255); 2261 } 2262 2263 // drawing occurs on the desktop 2264 if (fCachedWorkspace != current_workspace()) { 2265 int8 indice = 0; 2266 int32 mask; 2267 bool tmpOutline; 2268 while (fBackgroundInfo.FindInt32("be:bgndimginfoworkspaces", 2269 indice, &mask) == B_OK 2270 && fBackgroundInfo.FindBool("be:bgndimginfoerasetext", 2271 indice, &tmpOutline) == B_OK) { 2272 2273 if (((1 << current_workspace()) & mask) != 0) { 2274 fCachedOutline = tmpOutline; 2275 fCachedWorkspace = current_workspace(); 2276 break; 2277 } 2278 indice++; 2279 } 2280 } 2281 2282 if (fCachedOutline) { 2283 BFont font; 2284 view->GetFont(&font); 2285 2286 view->SetDrawingMode(B_OP_ALPHA); 2287 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY); 2288 // Draw glow or outline 2289 if (glowColor.Brightness() > 128) { 2290 font.SetFalseBoldWidth(2.0); 2291 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2292 2293 glowColor.alpha = 30; 2294 view->SetHighColor(glowColor); 2295 view->DrawString(label, where); 2296 2297 font.SetFalseBoldWidth(1.0); 2298 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2299 2300 glowColor.alpha = 65; 2301 view->SetHighColor(glowColor); 2302 view->DrawString(label, where); 2303 2304 font.SetFalseBoldWidth(0.0); 2305 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2306 } else { 2307 font.SetFalseBoldWidth(1.0); 2308 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2309 2310 glowColor.alpha = 30; 2311 view->SetHighColor(glowColor); 2312 view->DrawString(label, where); 2313 2314 font.SetFalseBoldWidth(0.0); 2315 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 2316 2317 glowColor.alpha = 200; 2318 view->SetHighColor(glowColor); 2319 view->DrawString(label, BPoint(where.x + 1, where.y + 1)); 2320 } 2321 } 2322 } 2323 2324 view->SetHighColor(color); 2325 view->SetDrawingMode(B_OP_OVER); 2326 view->DrawString(label, where); 2327 view->SetDrawingMode(oldMode); 2328 } 2329 2330 2331 void 2332 HaikuControlLook::DrawLabel(BView* view, const char* label, const BBitmap* icon, 2333 BRect rect, const BRect& updateRect, const rgb_color& base, uint32 flags, 2334 const BAlignment& alignment, const rgb_color* textColor) 2335 { 2336 if (!rect.Intersects(updateRect)) 2337 return; 2338 2339 if (label == NULL && icon == NULL) 2340 return; 2341 2342 if (label == NULL) { 2343 // icon only 2344 BRect alignedRect = BLayoutUtils::AlignInFrame(rect, 2345 icon->Bounds().Size(), alignment); 2346 drawing_mode oldMode = view->DrawingMode(); 2347 view->SetDrawingMode(B_OP_OVER); 2348 view->DrawBitmap(icon, alignedRect.LeftTop()); 2349 view->SetDrawingMode(oldMode); 2350 return; 2351 } 2352 2353 // label, possibly with icon 2354 float availableWidth = rect.Width() + 1; 2355 float width = 0; 2356 float textOffset = 0; 2357 float height = 0; 2358 2359 if (icon != NULL) { 2360 width = icon->Bounds().Width() + DefaultLabelSpacing() + 1; 2361 height = icon->Bounds().Height() + 1; 2362 textOffset = width; 2363 availableWidth -= textOffset; 2364 } 2365 2366 // truncate the label if necessary and get the width and height 2367 BString truncatedLabel(label); 2368 2369 BFont font; 2370 view->GetFont(&font); 2371 2372 font.TruncateString(&truncatedLabel, B_TRUNCATE_END, availableWidth); 2373 width += ceilf(font.StringWidth(truncatedLabel.String())); 2374 2375 font_height fontHeight; 2376 font.GetHeight(&fontHeight); 2377 float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); 2378 height = std::max(height, textHeight); 2379 2380 // handle alignment 2381 BRect alignedRect(BLayoutUtils::AlignOnRect(rect, 2382 BSize(width - 1, height - 1), alignment)); 2383 2384 if (icon != NULL) { 2385 BPoint location(alignedRect.LeftTop()); 2386 if (icon->Bounds().Height() + 1 < height) 2387 location.y += ceilf((height - icon->Bounds().Height() - 1) / 2); 2388 2389 drawing_mode oldMode = view->DrawingMode(); 2390 view->SetDrawingMode(B_OP_OVER); 2391 view->DrawBitmap(icon, location); 2392 view->SetDrawingMode(oldMode); 2393 } 2394 2395 BPoint location(alignedRect.left + textOffset, 2396 alignedRect.top + ceilf(fontHeight.ascent)); 2397 if (textHeight < height) 2398 location.y += ceilf((height - textHeight) / 2); 2399 2400 DrawLabel(view, truncatedLabel.String(), base, flags, location, textColor); 2401 } 2402 2403 2404 void 2405 HaikuControlLook::GetFrameInsets(frame_type frameType, uint32 flags, float& _left, 2406 float& _top, float& _right, float& _bottom) 2407 { 2408 // All frames have the same inset on each side. 2409 float inset = 0; 2410 2411 switch (frameType) { 2412 case B_BUTTON_FRAME: 2413 inset = (flags & B_DEFAULT_BUTTON) != 0 ? 5 : 2; 2414 break; 2415 case B_GROUP_FRAME: 2416 case B_MENU_FIELD_FRAME: 2417 inset = 3; 2418 break; 2419 case B_SCROLL_VIEW_FRAME: 2420 case B_TEXT_CONTROL_FRAME: 2421 inset = 2; 2422 break; 2423 } 2424 2425 inset = ceilf(inset * (be_plain_font->Size() / 12.0f)); 2426 2427 _left = inset; 2428 _top = inset; 2429 _right = inset; 2430 _bottom = inset; 2431 } 2432 2433 2434 void 2435 HaikuControlLook::GetBackgroundInsets(background_type backgroundType, 2436 uint32 flags, float& _left, float& _top, float& _right, float& _bottom) 2437 { 2438 // Most backgrounds have the same inset on each side. 2439 float inset = 0; 2440 2441 switch (backgroundType) { 2442 case B_BUTTON_BACKGROUND: 2443 case B_MENU_BACKGROUND: 2444 case B_MENU_BAR_BACKGROUND: 2445 case B_MENU_FIELD_BACKGROUND: 2446 case B_MENU_ITEM_BACKGROUND: 2447 inset = 1; 2448 break; 2449 case B_BUTTON_WITH_POP_UP_BACKGROUND: 2450 _left = 1; 2451 _top = 1; 2452 _right = 1 + ComposeSpacing(kButtonPopUpIndicatorWidth); 2453 _bottom = 1; 2454 return; 2455 case B_HORIZONTAL_SCROLL_BAR_BACKGROUND: 2456 _left = 2; 2457 _top = 0; 2458 _right = 1; 2459 _bottom = 0; 2460 return; 2461 case B_VERTICAL_SCROLL_BAR_BACKGROUND: 2462 _left = 0; 2463 _top = 2; 2464 _right = 0; 2465 _bottom = 1; 2466 return; 2467 } 2468 2469 _left = inset; 2470 _top = inset; 2471 _right = inset; 2472 _bottom = inset; 2473 } 2474 2475 2476 void 2477 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect, 2478 const BRect& updateRect, const rgb_color& base, uint32 flags, 2479 uint32 borders, orientation orientation) 2480 { 2481 _DrawButtonBackground(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f, 2482 base, true, flags, borders, orientation); 2483 } 2484 2485 2486 void 2487 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect, 2488 const BRect& updateRect, float radius, const rgb_color& base, uint32 flags, 2489 uint32 borders, orientation orientation) 2490 { 2491 _DrawButtonBackground(view, rect, updateRect, radius, radius, radius, 2492 radius, base, true, flags, borders, orientation); 2493 } 2494 2495 2496 void 2497 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect, 2498 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 2499 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 2500 uint32 flags, uint32 borders, orientation orientation) 2501 { 2502 _DrawButtonBackground(view, rect, updateRect, leftTopRadius, 2503 rightTopRadius, leftBottomRadius, rightBottomRadius, base, true, flags, 2504 borders, orientation); 2505 } 2506 2507 2508 // #pragma mark - 2509 2510 2511 void 2512 HaikuControlLook::_DrawButtonFrame(BView* view, BRect& rect, 2513 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 2514 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 2515 const rgb_color& background, float contrast, float brightness, 2516 uint32 flags, uint32 borders) 2517 { 2518 if (!rect.IsValid()) 2519 return; 2520 2521 // save the clipping constraints of the view 2522 view->PushState(); 2523 2524 // set clipping constraints to updateRect 2525 BRegion clipping(updateRect); 2526 view->ConstrainClippingRegion(&clipping); 2527 2528 // If the button is flat and neither activated nor otherwise highlighted 2529 // (mouse hovering or focussed), draw it flat. 2530 if ((flags & B_FLAT) != 0 2531 && (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0 2532 && ((flags & (B_HOVER | B_FOCUSED)) == 0 2533 || (flags & B_DISABLED) != 0)) { 2534 _DrawFrame(view, rect, background, background, background, 2535 background, borders); 2536 _DrawFrame(view, rect, background, background, background, 2537 background, borders); 2538 view->PopState(); 2539 return; 2540 } 2541 2542 // outer edge colors 2543 rgb_color edgeLightColor; 2544 rgb_color edgeShadowColor; 2545 2546 // default button frame color 2547 rgb_color defaultIndicatorColor = ui_color(B_CONTROL_BORDER_COLOR); 2548 rgb_color cornerBgColor; 2549 2550 if ((flags & B_DISABLED) != 0) { 2551 defaultIndicatorColor = disable_color(defaultIndicatorColor, 2552 background); 2553 } 2554 2555 drawing_mode oldMode = view->DrawingMode(); 2556 2557 if ((flags & B_DEFAULT_BUTTON) != 0) { 2558 cornerBgColor = defaultIndicatorColor; 2559 edgeLightColor = _EdgeLightColor(defaultIndicatorColor, 2560 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8), 2561 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags); 2562 edgeShadowColor = _EdgeShadowColor(defaultIndicatorColor, 2563 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8), 2564 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags); 2565 2566 // draw default button indicator 2567 // Allow a 1-pixel border of the background to come through. 2568 rect.InsetBy(1, 1); 2569 2570 view->SetHighColor(defaultIndicatorColor); 2571 view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius); 2572 rect.InsetBy(1, 1); 2573 2574 view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius); 2575 rect.InsetBy(1, 1); 2576 } else { 2577 cornerBgColor = background; 2578 if ((flags & B_BLEND_FRAME) != 0) { 2579 // set the background color to transparent for the case 2580 // that we are on the desktop 2581 cornerBgColor.alpha = 0; 2582 view->SetDrawingMode(B_OP_ALPHA); 2583 } 2584 2585 edgeLightColor = _EdgeLightColor(background, 2586 contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0), 2587 brightness * 1.0, flags); 2588 edgeShadowColor = _EdgeShadowColor(background, 2589 contrast * (flags & B_DISABLED) != 0 ? 0.0 : 1.0, 2590 brightness * 1.0, flags); 2591 } 2592 2593 // frame colors 2594 rgb_color frameLightColor = _FrameLightColor(base, flags); 2595 rgb_color frameShadowColor = _FrameShadowColor(base, flags); 2596 2597 // rounded corners 2598 2599 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0 2600 && leftTopRadius > 0) { 2601 // draw left top rounded corner 2602 BRect leftTopCorner(floorf(rect.left), floorf(rect.top), 2603 floorf(rect.left + leftTopRadius), 2604 floorf(rect.top + leftTopRadius)); 2605 clipping.Exclude(leftTopCorner); 2606 _DrawRoundCornerFrameLeftTop(view, leftTopCorner, updateRect, 2607 cornerBgColor, edgeShadowColor, frameLightColor); 2608 } 2609 2610 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0 2611 && rightTopRadius > 0) { 2612 // draw right top rounded corner 2613 BRect rightTopCorner(floorf(rect.right - rightTopRadius), 2614 floorf(rect.top), floorf(rect.right), 2615 floorf(rect.top + rightTopRadius)); 2616 clipping.Exclude(rightTopCorner); 2617 _DrawRoundCornerFrameRightTop(view, rightTopCorner, updateRect, 2618 cornerBgColor, edgeShadowColor, edgeLightColor, 2619 frameLightColor, frameShadowColor); 2620 } 2621 2622 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2623 && leftBottomRadius > 0) { 2624 // draw left bottom rounded corner 2625 BRect leftBottomCorner(floorf(rect.left), 2626 floorf(rect.bottom - leftBottomRadius), 2627 floorf(rect.left + leftBottomRadius), floorf(rect.bottom)); 2628 clipping.Exclude(leftBottomCorner); 2629 _DrawRoundCornerFrameLeftBottom(view, leftBottomCorner, updateRect, 2630 cornerBgColor, edgeShadowColor, edgeLightColor, 2631 frameLightColor, frameShadowColor); 2632 } 2633 2634 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2635 && rightBottomRadius > 0) { 2636 // draw right bottom rounded corner 2637 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius), 2638 floorf(rect.bottom - rightBottomRadius), floorf(rect.right), 2639 floorf(rect.bottom)); 2640 clipping.Exclude(rightBottomCorner); 2641 _DrawRoundCornerFrameRightBottom(view, rightBottomCorner, 2642 updateRect, cornerBgColor, edgeLightColor, frameShadowColor); 2643 } 2644 2645 // clip out the corners 2646 view->ConstrainClippingRegion(&clipping); 2647 2648 // draw outer edge 2649 if ((flags & B_DEFAULT_BUTTON) != 0) { 2650 _DrawOuterResessedFrame(view, rect, defaultIndicatorColor, 2651 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8), 2652 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), 2653 flags, borders); 2654 } else { 2655 _DrawOuterResessedFrame(view, rect, background, 2656 contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0), 2657 brightness * 1.0, flags, borders); 2658 } 2659 2660 view->SetDrawingMode(oldMode); 2661 2662 // draw frame 2663 if ((flags & B_BLEND_FRAME) != 0) { 2664 drawing_mode oldDrawingMode = view->DrawingMode(); 2665 view->SetDrawingMode(B_OP_ALPHA); 2666 2667 _DrawFrame(view, rect, frameLightColor, frameLightColor, 2668 frameShadowColor, frameShadowColor, borders); 2669 2670 view->SetDrawingMode(oldDrawingMode); 2671 } else { 2672 _DrawFrame(view, rect, frameLightColor, frameLightColor, 2673 frameShadowColor, frameShadowColor, borders); 2674 } 2675 2676 // restore the clipping constraints of the view 2677 view->PopState(); 2678 } 2679 2680 2681 void 2682 HaikuControlLook::_DrawOuterResessedFrame(BView* view, BRect& rect, 2683 const rgb_color& base, float contrast, float brightness, uint32 flags, 2684 uint32 borders) 2685 { 2686 rgb_color edgeLightColor = _EdgeLightColor(base, contrast, 2687 brightness, flags); 2688 rgb_color edgeShadowColor = _EdgeShadowColor(base, contrast, 2689 brightness, flags); 2690 2691 if ((flags & B_BLEND_FRAME) != 0) { 2692 // assumes the background has already been painted 2693 drawing_mode oldDrawingMode = view->DrawingMode(); 2694 view->SetDrawingMode(B_OP_ALPHA); 2695 2696 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, 2697 edgeLightColor, edgeLightColor, borders); 2698 2699 view->SetDrawingMode(oldDrawingMode); 2700 } else { 2701 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, 2702 edgeLightColor, edgeLightColor, borders); 2703 } 2704 } 2705 2706 2707 void 2708 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left, 2709 const rgb_color& top, const rgb_color& right, const rgb_color& bottom, 2710 uint32 borders) 2711 { 2712 view->BeginLineArray(4); 2713 2714 if (borders & B_LEFT_BORDER) { 2715 view->AddLine( 2716 BPoint(rect.left, rect.bottom), 2717 BPoint(rect.left, rect.top), left); 2718 rect.left++; 2719 } 2720 if (borders & B_TOP_BORDER) { 2721 view->AddLine( 2722 BPoint(rect.left, rect.top), 2723 BPoint(rect.right, rect.top), top); 2724 rect.top++; 2725 } 2726 if (borders & B_RIGHT_BORDER) { 2727 view->AddLine( 2728 BPoint(rect.right, rect.top), 2729 BPoint(rect.right, rect.bottom), right); 2730 rect.right--; 2731 } 2732 if (borders & B_BOTTOM_BORDER) { 2733 view->AddLine( 2734 BPoint(rect.left, rect.bottom), 2735 BPoint(rect.right, rect.bottom), bottom); 2736 rect.bottom--; 2737 } 2738 2739 view->EndLineArray(); 2740 } 2741 2742 2743 void 2744 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left, 2745 const rgb_color& top, const rgb_color& right, const rgb_color& bottom, 2746 const rgb_color& rightTop, const rgb_color& leftBottom, uint32 borders) 2747 { 2748 view->BeginLineArray(6); 2749 2750 if (borders & B_TOP_BORDER) { 2751 if (borders & B_RIGHT_BORDER) { 2752 view->AddLine( 2753 BPoint(rect.left, rect.top), 2754 BPoint(rect.right - 1, rect.top), top); 2755 view->AddLine( 2756 BPoint(rect.right, rect.top), 2757 BPoint(rect.right, rect.top), rightTop); 2758 } else { 2759 view->AddLine( 2760 BPoint(rect.left, rect.top), 2761 BPoint(rect.right, rect.top), top); 2762 } 2763 rect.top++; 2764 } 2765 2766 if (borders & B_LEFT_BORDER) { 2767 view->AddLine( 2768 BPoint(rect.left, rect.top), 2769 BPoint(rect.left, rect.bottom - 1), left); 2770 view->AddLine( 2771 BPoint(rect.left, rect.bottom), 2772 BPoint(rect.left, rect.bottom), leftBottom); 2773 rect.left++; 2774 } 2775 2776 if (borders & B_BOTTOM_BORDER) { 2777 view->AddLine( 2778 BPoint(rect.left, rect.bottom), 2779 BPoint(rect.right, rect.bottom), bottom); 2780 rect.bottom--; 2781 } 2782 2783 if (borders & B_RIGHT_BORDER) { 2784 view->AddLine( 2785 BPoint(rect.right, rect.bottom), 2786 BPoint(rect.right, rect.top), right); 2787 rect.right--; 2788 } 2789 2790 view->EndLineArray(); 2791 } 2792 2793 2794 void 2795 HaikuControlLook::_DrawButtonBackground(BView* view, BRect& rect, 2796 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 2797 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 2798 bool popupIndicator, uint32 flags, uint32 borders, orientation orientation) 2799 { 2800 if (!rect.IsValid()) 2801 return; 2802 2803 // save the clipping constraints of the view 2804 view->PushState(); 2805 2806 // set clipping constraints to updateRect 2807 BRegion clipping(updateRect); 2808 view->ConstrainClippingRegion(&clipping); 2809 2810 // If the button is flat and neither activated nor otherwise highlighted 2811 // (mouse hovering or focussed), draw it flat. 2812 if ((flags & B_FLAT) != 0 2813 && (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0 2814 && ((flags & (B_HOVER | B_FOCUSED)) == 0 2815 || (flags & B_DISABLED) != 0)) { 2816 _DrawFlatButtonBackground(view, rect, updateRect, base, popupIndicator, 2817 flags, borders, orientation); 2818 } else { 2819 _DrawNonFlatButtonBackground(view, rect, updateRect, clipping, 2820 leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, 2821 base, popupIndicator, flags, borders, orientation); 2822 } 2823 2824 // restore the clipping constraints of the view 2825 view->PopState(); 2826 } 2827 2828 2829 void 2830 HaikuControlLook::_DrawFlatButtonBackground(BView* view, BRect& rect, 2831 const BRect& updateRect, const rgb_color& base, bool popupIndicator, 2832 uint32 flags, uint32 borders, orientation orientation) 2833 { 2834 _DrawFrame(view, rect, base, base, base, base, borders); 2835 // Not an actual frame, but the method insets our rect as needed. 2836 2837 view->SetHighColor(base); 2838 view->FillRect(rect); 2839 2840 if (popupIndicator) { 2841 BRect indicatorRect(rect); 2842 rect.right -= ComposeSpacing(kButtonPopUpIndicatorWidth); 2843 indicatorRect.left = rect.right + 3; 2844 // 2 pixels for the separator 2845 2846 view->SetHighColor(base); 2847 view->FillRect(indicatorRect); 2848 2849 _DrawPopUpMarker(view, indicatorRect, base, flags); 2850 } 2851 } 2852 2853 2854 void 2855 HaikuControlLook::_DrawNonFlatButtonBackground(BView* view, BRect& rect, 2856 const BRect& updateRect, BRegion& clipping, float leftTopRadius, 2857 float rightTopRadius, float leftBottomRadius, float rightBottomRadius, 2858 const rgb_color& base, bool popupIndicator, uint32 flags, uint32 borders, 2859 orientation orientation) 2860 { 2861 // inner bevel colors 2862 rgb_color bevelLightColor = _BevelLightColor(base, flags); 2863 rgb_color bevelShadowColor = _BevelShadowColor(base, flags); 2864 2865 // button background color 2866 rgb_color buttonBgColor; 2867 if ((flags & B_DISABLED) != 0) 2868 buttonBgColor = tint_color(base, 0.7); 2869 else 2870 buttonBgColor = tint_color(base, B_LIGHTEN_1_TINT); 2871 2872 // surface top gradient 2873 BGradientLinear fillGradient; 2874 _MakeButtonGradient(fillGradient, rect, base, flags, orientation); 2875 2876 // rounded corners 2877 2878 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0 2879 && leftTopRadius > 0) { 2880 // draw left top rounded corner 2881 BRect leftTopCorner(floorf(rect.left), floorf(rect.top), 2882 floorf(rect.left + leftTopRadius - 2.0), 2883 floorf(rect.top + leftTopRadius - 2.0)); 2884 clipping.Exclude(leftTopCorner); 2885 _DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect, 2886 bevelLightColor, fillGradient); 2887 } 2888 2889 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0 2890 && rightTopRadius > 0) { 2891 // draw right top rounded corner 2892 BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0), 2893 floorf(rect.top), floorf(rect.right), 2894 floorf(rect.top + rightTopRadius - 2.0)); 2895 clipping.Exclude(rightTopCorner); 2896 _DrawRoundCornerBackgroundRightTop(view, rightTopCorner, 2897 updateRect, bevelLightColor, bevelShadowColor, fillGradient); 2898 } 2899 2900 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2901 && leftBottomRadius > 0) { 2902 // draw left bottom rounded corner 2903 BRect leftBottomCorner(floorf(rect.left), 2904 floorf(rect.bottom - leftBottomRadius + 2.0), 2905 floorf(rect.left + leftBottomRadius - 2.0), 2906 floorf(rect.bottom)); 2907 clipping.Exclude(leftBottomCorner); 2908 _DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner, 2909 updateRect, bevelLightColor, bevelShadowColor, fillGradient); 2910 } 2911 2912 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2913 && rightBottomRadius > 0) { 2914 // draw right bottom rounded corner 2915 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0), 2916 floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right), 2917 floorf(rect.bottom)); 2918 clipping.Exclude(rightBottomCorner); 2919 _DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner, 2920 updateRect, bevelShadowColor, fillGradient); 2921 } 2922 2923 // clip out the corners 2924 view->ConstrainClippingRegion(&clipping); 2925 2926 // draw inner bevel 2927 2928 if ((flags & B_ACTIVATED) != 0) { 2929 view->BeginLineArray(4); 2930 2931 // shadow along left/top borders 2932 if (borders & B_LEFT_BORDER) { 2933 view->AddLine(BPoint(rect.left, rect.top), 2934 BPoint(rect.left, rect.bottom), bevelLightColor); 2935 rect.left++; 2936 } 2937 if (borders & B_TOP_BORDER) { 2938 view->AddLine(BPoint(rect.left, rect.top), 2939 BPoint(rect.right, rect.top), bevelLightColor); 2940 rect.top++; 2941 } 2942 2943 // softer shadow along left/top borders 2944 if (borders & B_LEFT_BORDER) { 2945 view->AddLine(BPoint(rect.left, rect.top), 2946 BPoint(rect.left, rect.bottom), bevelShadowColor); 2947 rect.left++; 2948 } 2949 if (borders & B_TOP_BORDER) { 2950 view->AddLine(BPoint(rect.left, rect.top), 2951 BPoint(rect.right, rect.top), bevelShadowColor); 2952 rect.top++; 2953 } 2954 2955 view->EndLineArray(); 2956 } else { 2957 _DrawFrame(view, rect, 2958 bevelLightColor, bevelLightColor, 2959 bevelShadowColor, bevelShadowColor, 2960 buttonBgColor, buttonBgColor, borders); 2961 } 2962 2963 if (popupIndicator) { 2964 BRect indicatorRect(rect); 2965 rect.right -= ComposeSpacing(kButtonPopUpIndicatorWidth); 2966 indicatorRect.left = rect.right + 3; 2967 // 2 pixels for the separator 2968 2969 // Even when depressed we want the pop-up indicator background and 2970 // separator to cover the area up to the top. 2971 if ((flags & B_ACTIVATED) != 0) 2972 indicatorRect.top--; 2973 2974 // draw the separator 2975 rgb_color separatorBaseColor = base; 2976 if ((flags & B_ACTIVATED) != 0) 2977 separatorBaseColor = tint_color(base, B_DARKEN_1_TINT); 2978 2979 rgb_color separatorLightColor = _EdgeLightColor(separatorBaseColor, 2980 (flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags); 2981 rgb_color separatorShadowColor = _EdgeShadowColor(separatorBaseColor, 2982 (flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags); 2983 2984 view->BeginLineArray(2); 2985 2986 view->AddLine(BPoint(indicatorRect.left - 2, indicatorRect.top), 2987 BPoint(indicatorRect.left - 2, indicatorRect.bottom), 2988 separatorShadowColor); 2989 view->AddLine(BPoint(indicatorRect.left - 1, indicatorRect.top), 2990 BPoint(indicatorRect.left - 1, indicatorRect.bottom), 2991 separatorLightColor); 2992 2993 view->EndLineArray(); 2994 2995 // draw background and pop-up marker 2996 _DrawMenuFieldBackgroundInside(view, indicatorRect, updateRect, 2997 0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags, 0); 2998 2999 if ((flags & B_ACTIVATED) != 0) 3000 indicatorRect.top++; 3001 3002 _DrawPopUpMarker(view, indicatorRect, base, flags); 3003 } 3004 3005 // fill in the background 3006 view->FillRect(rect, fillGradient); 3007 } 3008 3009 3010 void 3011 HaikuControlLook::_DrawPopUpMarker(BView* view, const BRect& rect, 3012 const rgb_color& base, uint32 flags) 3013 { 3014 BPoint center(roundf((rect.left + rect.right) / 2.0), 3015 roundf((rect.top + rect.bottom) / 2.0)); 3016 const float metric = roundf(rect.Width() * 3.125f) / 10.0f, 3017 offset = ceilf((metric * 0.2f) * 10.0f) / 10.0f; 3018 BPoint triangle[3]; 3019 triangle[0] = center + BPoint(-metric, -offset); 3020 triangle[1] = center + BPoint(metric, -offset); 3021 triangle[2] = center + BPoint(0.0, metric * 0.8f); 3022 3023 const uint32 viewFlags = view->Flags(); 3024 view->SetFlags(viewFlags | B_SUBPIXEL_PRECISE); 3025 3026 rgb_color markColor; 3027 if ((flags & B_DISABLED) != 0) 3028 markColor = tint_color(base, 1.35); 3029 else 3030 markColor = tint_color(base, 1.65); 3031 3032 view->SetHighColor(markColor); 3033 view->FillTriangle(triangle[0], triangle[1], triangle[2]); 3034 3035 view->SetFlags(viewFlags); 3036 } 3037 3038 3039 void 3040 HaikuControlLook::_DrawMenuFieldBackgroundOutside(BView* view, BRect& rect, 3041 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 3042 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 3043 bool popupIndicator, uint32 flags) 3044 { 3045 if (!rect.IsValid() || !rect.Intersects(updateRect)) 3046 return; 3047 3048 if (popupIndicator) { 3049 const float indicatorWidth = ComposeSpacing(kButtonPopUpIndicatorWidth); 3050 const float spacing = (indicatorWidth <= 11.0f) ? 1.0f : roundf(indicatorWidth / 11.0f); 3051 3052 BRect leftRect(rect); 3053 leftRect.right -= indicatorWidth - spacing; 3054 3055 BRect rightRect(rect); 3056 rightRect.left = rightRect.right - (indicatorWidth - spacing * 2); 3057 3058 _DrawMenuFieldBackgroundInside(view, leftRect, updateRect, 3059 leftTopRadius, 0.0f, leftBottomRadius, 0.0f, base, flags, 3060 B_LEFT_BORDER | B_TOP_BORDER | B_BOTTOM_BORDER); 3061 3062 _DrawMenuFieldBackgroundInside(view, rightRect, updateRect, 3063 0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags, 3064 B_TOP_BORDER | B_RIGHT_BORDER | B_BOTTOM_BORDER); 3065 3066 _DrawPopUpMarker(view, rightRect, base, flags); 3067 3068 // draw a line on the left of the popup frame 3069 rgb_color bevelShadowColor = _BevelShadowColor(base, flags); 3070 view->SetHighColor(bevelShadowColor); 3071 BPoint leftTopCorner(floorf(rightRect.left - spacing), 3072 floorf(rightRect.top - spacing)); 3073 BPoint leftBottomCorner(floorf(rightRect.left - spacing), 3074 floorf(rightRect.bottom + spacing)); 3075 for (float i = 0; i < spacing; i++) { 3076 view->StrokeLine(leftTopCorner + BPoint(i, 0), 3077 leftBottomCorner + BPoint(i, 0)); 3078 } 3079 3080 rect = leftRect; 3081 } else { 3082 _DrawMenuFieldBackgroundInside(view, rect, updateRect, leftTopRadius, 3083 rightTopRadius, leftBottomRadius, rightBottomRadius, base, flags); 3084 } 3085 } 3086 3087 3088 void 3089 HaikuControlLook::_DrawMenuFieldBackgroundInside(BView* view, BRect& rect, 3090 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 3091 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 3092 uint32 flags, uint32 borders) 3093 { 3094 if (!rect.IsValid() || !rect.Intersects(updateRect)) 3095 return; 3096 3097 // save the clipping constraints of the view 3098 view->PushState(); 3099 3100 // set clipping constraints to updateRect 3101 BRegion clipping(updateRect); 3102 view->ConstrainClippingRegion(&clipping); 3103 3104 // frame colors 3105 rgb_color frameLightColor = _FrameLightColor(base, flags); 3106 rgb_color frameShadowColor = _FrameShadowColor(base, flags); 3107 3108 // indicator background color 3109 rgb_color indicatorBase; 3110 if ((borders & B_LEFT_BORDER) != 0) 3111 indicatorBase = base; 3112 else { 3113 if ((flags & B_DISABLED) != 0) 3114 indicatorBase = tint_color(base, 1.05); 3115 else 3116 indicatorBase = tint_color(base, 1.12); 3117 } 3118 3119 // bevel colors 3120 rgb_color cornerColor = tint_color(indicatorBase, 0.85); 3121 rgb_color bevelColor1 = tint_color(indicatorBase, 0.3); 3122 rgb_color bevelColor2 = tint_color(indicatorBase, 0.5); 3123 rgb_color bevelColor3 = tint_color(indicatorBase, 1.03); 3124 3125 if ((flags & B_DISABLED) != 0) { 3126 cornerColor = tint_color(indicatorBase, 0.8); 3127 bevelColor1 = tint_color(indicatorBase, 0.7); 3128 bevelColor2 = tint_color(indicatorBase, 0.8); 3129 bevelColor3 = tint_color(indicatorBase, 1.01); 3130 } else { 3131 cornerColor = tint_color(indicatorBase, 0.85); 3132 bevelColor1 = tint_color(indicatorBase, 0.3); 3133 bevelColor2 = tint_color(indicatorBase, 0.5); 3134 bevelColor3 = tint_color(indicatorBase, 1.03); 3135 } 3136 3137 // surface top gradient 3138 BGradientLinear fillGradient; 3139 _MakeButtonGradient(fillGradient, rect, indicatorBase, flags); 3140 3141 // rounded corners 3142 3143 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0 3144 && leftTopRadius > 0) { 3145 // draw left top rounded corner 3146 BRect leftTopCorner(floorf(rect.left), floorf(rect.top), 3147 floorf(rect.left + leftTopRadius - 2.0), 3148 floorf(rect.top + leftTopRadius - 2.0)); 3149 clipping.Exclude(leftTopCorner); 3150 3151 BRegion cornerClipping(leftTopCorner); 3152 view->ConstrainClippingRegion(&cornerClipping); 3153 3154 BRect ellipseRect(leftTopCorner); 3155 ellipseRect.InsetBy(-1.0, -1.0); 3156 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3157 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3158 3159 // draw the frame (again) 3160 view->SetHighColor(frameLightColor); 3161 view->FillEllipse(ellipseRect); 3162 3163 // draw the bevel and background 3164 _DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect, 3165 bevelColor1, fillGradient); 3166 } 3167 3168 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0 3169 && rightTopRadius > 0) { 3170 // draw right top rounded corner 3171 BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0), 3172 floorf(rect.top), floorf(rect.right), 3173 floorf(rect.top + rightTopRadius - 2.0)); 3174 clipping.Exclude(rightTopCorner); 3175 3176 BRegion cornerClipping(rightTopCorner); 3177 view->ConstrainClippingRegion(&cornerClipping); 3178 3179 BRect ellipseRect(rightTopCorner); 3180 ellipseRect.InsetBy(-1.0, -1.0); 3181 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3182 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3183 3184 // draw the frame (again) 3185 if (frameLightColor == frameShadowColor) { 3186 view->SetHighColor(frameLightColor); 3187 view->FillEllipse(ellipseRect); 3188 } else { 3189 BGradientLinear gradient; 3190 gradient.AddColor(frameLightColor, 0); 3191 gradient.AddColor(frameShadowColor, 255); 3192 gradient.SetStart(rightTopCorner.LeftTop()); 3193 gradient.SetEnd(rightTopCorner.RightBottom()); 3194 view->FillEllipse(ellipseRect, gradient); 3195 } 3196 3197 // draw the bevel and background 3198 _DrawRoundCornerBackgroundRightTop(view, rightTopCorner, updateRect, 3199 bevelColor1, bevelColor3, fillGradient); 3200 } 3201 3202 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 3203 && leftBottomRadius > 0) { 3204 // draw left bottom rounded corner 3205 BRect leftBottomCorner(floorf(rect.left), 3206 floorf(rect.bottom - leftBottomRadius + 2.0), 3207 floorf(rect.left + leftBottomRadius - 2.0), 3208 floorf(rect.bottom)); 3209 clipping.Exclude(leftBottomCorner); 3210 3211 BRegion cornerClipping(leftBottomCorner); 3212 view->ConstrainClippingRegion(&cornerClipping); 3213 3214 BRect ellipseRect(leftBottomCorner); 3215 ellipseRect.InsetBy(-1.0, -1.0); 3216 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3217 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3218 3219 // draw the frame (again) 3220 if (frameLightColor == frameShadowColor) { 3221 view->SetHighColor(frameLightColor); 3222 view->FillEllipse(ellipseRect); 3223 } else { 3224 BGradientLinear gradient; 3225 gradient.AddColor(frameLightColor, 0); 3226 gradient.AddColor(frameShadowColor, 255); 3227 gradient.SetStart(leftBottomCorner.LeftTop()); 3228 gradient.SetEnd(leftBottomCorner.RightBottom()); 3229 view->FillEllipse(ellipseRect, gradient); 3230 } 3231 3232 // draw the bevel and background 3233 _DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner, 3234 updateRect, bevelColor2, bevelColor3, fillGradient); 3235 } 3236 3237 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 3238 && rightBottomRadius > 0) { 3239 // draw right bottom rounded corner 3240 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0), 3241 floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right), 3242 floorf(rect.bottom)); 3243 clipping.Exclude(rightBottomCorner); 3244 3245 BRegion cornerClipping(rightBottomCorner); 3246 view->ConstrainClippingRegion(&cornerClipping); 3247 3248 BRect ellipseRect(rightBottomCorner); 3249 ellipseRect.InsetBy(-1.0, -1.0); 3250 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3251 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3252 3253 // draw the frame (again) 3254 view->SetHighColor(frameShadowColor); 3255 view->FillEllipse(ellipseRect); 3256 3257 // draw the bevel and background 3258 _DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner, 3259 updateRect, bevelColor3, fillGradient); 3260 } 3261 3262 // clip out the corners 3263 view->ConstrainClippingRegion(&clipping); 3264 3265 // draw the bevel 3266 _DrawFrame(view, rect, 3267 bevelColor2, bevelColor1, 3268 bevelColor3, bevelColor3, 3269 cornerColor, cornerColor, 3270 borders); 3271 3272 // fill in the background 3273 view->FillRect(rect, fillGradient); 3274 3275 // restore the clipping constraints of the view 3276 view->PopState(); 3277 } 3278 3279 3280 void 3281 HaikuControlLook::_DrawRoundCornerLeftTop(BView* view, BRect& cornerRect, 3282 const BRect& updateRect, const rgb_color& background, 3283 const rgb_color& edgeColor, const rgb_color& frameColor, 3284 const rgb_color& bevelColor, const BGradientLinear& fillGradient) 3285 { 3286 _DrawRoundCornerFrameLeftTop(view, cornerRect, updateRect, 3287 background, edgeColor, frameColor); 3288 _DrawRoundCornerBackgroundLeftTop(view, cornerRect, updateRect, 3289 bevelColor, fillGradient); 3290 } 3291 3292 3293 void 3294 HaikuControlLook::_DrawRoundCornerFrameLeftTop(BView* view, BRect& cornerRect, 3295 const BRect& updateRect, const rgb_color& background, 3296 const rgb_color& edgeColor, const rgb_color& frameColor) 3297 { 3298 // constrain clipping region to corner 3299 BRegion clipping(cornerRect); 3300 view->ConstrainClippingRegion(&clipping); 3301 3302 // background 3303 view->SetHighColor(background); 3304 view->FillRect(cornerRect); 3305 3306 // outer edge 3307 BRect ellipseRect(cornerRect); 3308 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3309 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3310 3311 view->SetHighColor(edgeColor); 3312 view->FillEllipse(ellipseRect); 3313 3314 // frame 3315 ellipseRect.InsetBy(1, 1); 3316 cornerRect.left++; 3317 cornerRect.top++; 3318 view->SetHighColor(frameColor); 3319 view->FillEllipse(ellipseRect); 3320 3321 // prepare for bevel 3322 cornerRect.left++; 3323 cornerRect.top++; 3324 } 3325 3326 3327 void 3328 HaikuControlLook::_DrawRoundCornerBackgroundLeftTop(BView* view, BRect& cornerRect, 3329 const BRect& updateRect, const rgb_color& bevelColor, 3330 const BGradientLinear& fillGradient) 3331 { 3332 // constrain clipping region to corner 3333 BRegion clipping(cornerRect); 3334 view->ConstrainClippingRegion(&clipping); 3335 3336 BRect ellipseRect(cornerRect); 3337 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3338 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3339 3340 // bevel 3341 view->SetHighColor(bevelColor); 3342 view->FillEllipse(ellipseRect); 3343 3344 // gradient 3345 ellipseRect.InsetBy(1, 1); 3346 view->FillEllipse(ellipseRect, fillGradient); 3347 } 3348 3349 3350 void 3351 HaikuControlLook::_DrawRoundCornerRightTop(BView* view, BRect& cornerRect, 3352 const BRect& updateRect, const rgb_color& background, 3353 const rgb_color& edgeTopColor, const rgb_color& edgeRightColor, 3354 const rgb_color& frameTopColor, const rgb_color& frameRightColor, 3355 const rgb_color& bevelTopColor, const rgb_color& bevelRightColor, 3356 const BGradientLinear& fillGradient) 3357 { 3358 _DrawRoundCornerFrameRightTop(view, cornerRect, updateRect, 3359 background, edgeTopColor, edgeRightColor, frameTopColor, 3360 frameRightColor); 3361 _DrawRoundCornerBackgroundRightTop(view, cornerRect, updateRect, 3362 bevelTopColor, bevelRightColor, fillGradient); 3363 } 3364 3365 3366 void 3367 HaikuControlLook::_DrawRoundCornerFrameRightTop(BView* view, BRect& cornerRect, 3368 const BRect& updateRect, const rgb_color& background, 3369 const rgb_color& edgeTopColor, const rgb_color& edgeRightColor, 3370 const rgb_color& frameTopColor, const rgb_color& frameRightColor) 3371 { 3372 // constrain clipping region to corner 3373 BRegion clipping(cornerRect); 3374 view->ConstrainClippingRegion(&clipping); 3375 3376 // background 3377 view->SetHighColor(background); 3378 view->FillRect(cornerRect); 3379 3380 // outer edge 3381 BRect ellipseRect(cornerRect); 3382 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3383 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3384 3385 BGradientLinear gradient; 3386 gradient.AddColor(edgeTopColor, 0); 3387 gradient.AddColor(edgeRightColor, 255); 3388 gradient.SetStart(cornerRect.LeftTop()); 3389 gradient.SetEnd(cornerRect.RightBottom()); 3390 view->FillEllipse(ellipseRect, gradient); 3391 3392 // frame 3393 ellipseRect.InsetBy(1, 1); 3394 cornerRect.right--; 3395 cornerRect.top++; 3396 if (frameTopColor == frameRightColor) { 3397 view->SetHighColor(frameTopColor); 3398 view->FillEllipse(ellipseRect); 3399 } else { 3400 gradient.SetColor(0, frameTopColor); 3401 gradient.SetColor(1, frameRightColor); 3402 gradient.SetStart(cornerRect.LeftTop()); 3403 gradient.SetEnd(cornerRect.RightBottom()); 3404 view->FillEllipse(ellipseRect, gradient); 3405 } 3406 3407 // prepare for bevel 3408 cornerRect.right--; 3409 cornerRect.top++; 3410 } 3411 3412 3413 void 3414 HaikuControlLook::_DrawRoundCornerBackgroundRightTop(BView* view, BRect& cornerRect, 3415 const BRect& updateRect, const rgb_color& bevelTopColor, 3416 const rgb_color& bevelRightColor, const BGradientLinear& fillGradient) 3417 { 3418 // constrain clipping region to corner 3419 BRegion clipping(cornerRect); 3420 view->ConstrainClippingRegion(&clipping); 3421 3422 BRect ellipseRect(cornerRect); 3423 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3424 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3425 3426 // bevel 3427 BGradientLinear gradient; 3428 gradient.AddColor(bevelTopColor, 0); 3429 gradient.AddColor(bevelRightColor, 255); 3430 gradient.SetStart(cornerRect.LeftTop()); 3431 gradient.SetEnd(cornerRect.RightBottom()); 3432 view->FillEllipse(ellipseRect, gradient); 3433 3434 // gradient 3435 ellipseRect.InsetBy(1, 1); 3436 view->FillEllipse(ellipseRect, fillGradient); 3437 } 3438 3439 3440 void 3441 HaikuControlLook::_DrawRoundCornerLeftBottom(BView* view, BRect& cornerRect, 3442 const BRect& updateRect, const rgb_color& background, 3443 const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor, 3444 const rgb_color& frameLeftColor, const rgb_color& frameBottomColor, 3445 const rgb_color& bevelLeftColor, const rgb_color& bevelBottomColor, 3446 const BGradientLinear& fillGradient) 3447 { 3448 _DrawRoundCornerFrameLeftBottom(view, cornerRect, updateRect, 3449 background, edgeLeftColor, edgeBottomColor, frameLeftColor, 3450 frameBottomColor); 3451 _DrawRoundCornerBackgroundLeftBottom(view, cornerRect, updateRect, 3452 bevelLeftColor, bevelBottomColor, fillGradient); 3453 } 3454 3455 3456 void 3457 HaikuControlLook::_DrawRoundCornerFrameLeftBottom(BView* view, BRect& cornerRect, 3458 const BRect& updateRect, const rgb_color& background, 3459 const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor, 3460 const rgb_color& frameLeftColor, const rgb_color& frameBottomColor) 3461 { 3462 // constrain clipping region to corner 3463 BRegion clipping(cornerRect); 3464 view->ConstrainClippingRegion(&clipping); 3465 3466 // background 3467 view->SetHighColor(background); 3468 view->FillRect(cornerRect); 3469 3470 // outer edge 3471 BRect ellipseRect(cornerRect); 3472 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3473 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3474 3475 BGradientLinear gradient; 3476 gradient.AddColor(edgeLeftColor, 0); 3477 gradient.AddColor(edgeBottomColor, 255); 3478 gradient.SetStart(cornerRect.LeftTop()); 3479 gradient.SetEnd(cornerRect.RightBottom()); 3480 view->FillEllipse(ellipseRect, gradient); 3481 3482 // frame 3483 ellipseRect.InsetBy(1, 1); 3484 cornerRect.left++; 3485 cornerRect.bottom--; 3486 if (frameLeftColor == frameBottomColor) { 3487 view->SetHighColor(frameLeftColor); 3488 view->FillEllipse(ellipseRect); 3489 } else { 3490 gradient.SetColor(0, frameLeftColor); 3491 gradient.SetColor(1, frameBottomColor); 3492 gradient.SetStart(cornerRect.LeftTop()); 3493 gradient.SetEnd(cornerRect.RightBottom()); 3494 view->FillEllipse(ellipseRect, gradient); 3495 } 3496 3497 // prepare for bevel 3498 cornerRect.left++; 3499 cornerRect.bottom--; 3500 } 3501 3502 3503 void 3504 HaikuControlLook::_DrawRoundCornerBackgroundLeftBottom(BView* view, BRect& cornerRect, 3505 const BRect& updateRect, const rgb_color& bevelLeftColor, 3506 const rgb_color& bevelBottomColor, const BGradientLinear& fillGradient) 3507 { 3508 // constrain clipping region to corner 3509 BRegion clipping(cornerRect); 3510 view->ConstrainClippingRegion(&clipping); 3511 3512 BRect ellipseRect(cornerRect); 3513 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3514 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3515 3516 // bevel 3517 BGradientLinear gradient; 3518 gradient.AddColor(bevelLeftColor, 0); 3519 gradient.AddColor(bevelBottomColor, 255); 3520 gradient.SetStart(cornerRect.LeftTop()); 3521 gradient.SetEnd(cornerRect.RightBottom()); 3522 view->FillEllipse(ellipseRect, gradient); 3523 3524 // gradient 3525 ellipseRect.InsetBy(1, 1); 3526 view->FillEllipse(ellipseRect, fillGradient); 3527 } 3528 3529 3530 void 3531 HaikuControlLook::_DrawRoundCornerRightBottom(BView* view, BRect& cornerRect, 3532 const BRect& updateRect, const rgb_color& background, 3533 const rgb_color& edgeColor, const rgb_color& frameColor, 3534 const rgb_color& bevelColor, const BGradientLinear& fillGradient) 3535 { 3536 _DrawRoundCornerFrameRightBottom(view, cornerRect, updateRect, 3537 background, edgeColor, frameColor); 3538 _DrawRoundCornerBackgroundRightBottom(view, cornerRect, updateRect, 3539 bevelColor, fillGradient); 3540 } 3541 3542 3543 void 3544 HaikuControlLook::_DrawRoundCornerFrameRightBottom(BView* view, BRect& cornerRect, 3545 const BRect& updateRect, const rgb_color& background, 3546 const rgb_color& edgeColor, const rgb_color& frameColor) 3547 { 3548 // constrain clipping region to corner 3549 BRegion clipping(cornerRect); 3550 view->ConstrainClippingRegion(&clipping); 3551 3552 // background 3553 view->SetHighColor(background); 3554 view->FillRect(cornerRect); 3555 3556 // outer edge 3557 BRect ellipseRect(cornerRect); 3558 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3559 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3560 3561 view->SetHighColor(edgeColor); 3562 view->FillEllipse(ellipseRect); 3563 3564 // frame 3565 ellipseRect.InsetBy(1, 1); 3566 cornerRect.right--; 3567 cornerRect.bottom--; 3568 view->SetHighColor(frameColor); 3569 view->FillEllipse(ellipseRect); 3570 3571 // prepare for bevel 3572 cornerRect.right--; 3573 cornerRect.bottom--; 3574 } 3575 3576 3577 void 3578 HaikuControlLook::_DrawRoundCornerBackgroundRightBottom(BView* view, 3579 BRect& cornerRect, const BRect& updateRect, const rgb_color& bevelColor, 3580 const BGradientLinear& fillGradient) 3581 { 3582 // constrain clipping region to corner 3583 BRegion clipping(cornerRect); 3584 view->ConstrainClippingRegion(&clipping); 3585 3586 BRect ellipseRect(cornerRect); 3587 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3588 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3589 3590 // bevel 3591 view->SetHighColor(bevelColor); 3592 view->FillEllipse(ellipseRect); 3593 3594 // gradient 3595 ellipseRect.InsetBy(1, 1); 3596 view->FillEllipse(ellipseRect, fillGradient); 3597 } 3598 3599 3600 void 3601 HaikuControlLook::_DrawRoundBarCorner(BView* view, BRect& rect, 3602 const BRect& updateRect, 3603 const rgb_color& edgeLightColor, const rgb_color& edgeShadowColor, 3604 const rgb_color& frameLightColor, const rgb_color& frameShadowColor, 3605 const rgb_color& fillLightColor, const rgb_color& fillShadowColor, 3606 float leftInset, float topInset, float rightInset, float bottomInset, 3607 orientation orientation) 3608 { 3609 if (!rect.IsValid() || !rect.Intersects(updateRect)) 3610 return; 3611 3612 BGradientLinear gradient; 3613 gradient.AddColor(edgeShadowColor, 0); 3614 gradient.AddColor(edgeLightColor, 255); 3615 gradient.SetStart(rect.LeftTop()); 3616 if (orientation == B_HORIZONTAL) 3617 gradient.SetEnd(rect.LeftBottom()); 3618 else 3619 gradient.SetEnd(rect.RightTop()); 3620 3621 view->FillEllipse(rect, gradient); 3622 3623 rect.left += leftInset; 3624 rect.top += topInset; 3625 rect.right += rightInset; 3626 rect.bottom += bottomInset; 3627 3628 gradient.MakeEmpty(); 3629 gradient.AddColor(frameShadowColor, 0); 3630 gradient.AddColor(frameLightColor, 255); 3631 gradient.SetStart(rect.LeftTop()); 3632 if (orientation == B_HORIZONTAL) 3633 gradient.SetEnd(rect.LeftBottom()); 3634 else 3635 gradient.SetEnd(rect.RightTop()); 3636 3637 view->FillEllipse(rect, gradient); 3638 3639 rect.left += leftInset; 3640 rect.top += topInset; 3641 rect.right += rightInset; 3642 rect.bottom += bottomInset; 3643 3644 gradient.MakeEmpty(); 3645 gradient.AddColor(fillShadowColor, 0); 3646 gradient.AddColor(fillLightColor, 255); 3647 gradient.SetStart(rect.LeftTop()); 3648 if (orientation == B_HORIZONTAL) 3649 gradient.SetEnd(rect.LeftBottom()); 3650 else 3651 gradient.SetEnd(rect.RightTop()); 3652 3653 view->FillEllipse(rect, gradient); 3654 } 3655 3656 3657 rgb_color 3658 HaikuControlLook::_EdgeLightColor(const rgb_color& base, float contrast, 3659 float brightness, uint32 flags) 3660 { 3661 rgb_color edgeLightColor; 3662 3663 if ((flags & B_BLEND_FRAME) != 0) { 3664 uint8 alpha = uint8(20 * contrast); 3665 uint8 white = uint8(255 * brightness); 3666 3667 edgeLightColor = (rgb_color){ white, white, white, alpha }; 3668 } else { 3669 // colors 3670 float tintLight = kEdgeBevelLightTint; 3671 3672 if (contrast == 0.0) 3673 tintLight = B_NO_TINT; 3674 else if (contrast != 1.0) 3675 tintLight = B_NO_TINT + (tintLight - B_NO_TINT) * contrast; 3676 3677 edgeLightColor = tint_color(base, tintLight); 3678 3679 if (brightness < 1.0) { 3680 edgeLightColor.red = uint8(edgeLightColor.red * brightness); 3681 edgeLightColor.green = uint8(edgeLightColor.green * brightness); 3682 edgeLightColor.blue = uint8(edgeLightColor.blue * brightness); 3683 } 3684 } 3685 3686 return edgeLightColor; 3687 } 3688 3689 3690 rgb_color 3691 HaikuControlLook::_EdgeShadowColor(const rgb_color& base, float contrast, 3692 float brightness, uint32 flags) 3693 { 3694 rgb_color edgeShadowColor; 3695 3696 if ((flags & B_BLEND_FRAME) != 0) { 3697 uint8 alpha = uint8(20 * contrast); 3698 edgeShadowColor = (rgb_color){ 0, 0, 0, alpha }; 3699 } else { 3700 float tintShadow = kEdgeBevelShadowTint; 3701 3702 if (contrast == 0.0) 3703 tintShadow = B_NO_TINT; 3704 else if (contrast != 1.0) 3705 tintShadow = B_NO_TINT + (tintShadow - B_NO_TINT) * contrast; 3706 3707 edgeShadowColor = tint_color(base, tintShadow); 3708 3709 if (brightness < 1.0) { 3710 edgeShadowColor.red = uint8(edgeShadowColor.red * brightness); 3711 edgeShadowColor.green = uint8(edgeShadowColor.green * brightness); 3712 edgeShadowColor.blue = uint8(edgeShadowColor.blue * brightness); 3713 } 3714 } 3715 3716 return edgeShadowColor; 3717 } 3718 3719 3720 rgb_color 3721 HaikuControlLook::_FrameLightColor(const rgb_color& base, uint32 flags) 3722 { 3723 if ((flags & B_FOCUSED) != 0) 3724 return ui_color(B_KEYBOARD_NAVIGATION_COLOR); 3725 3726 if ((flags & B_ACTIVATED) != 0) 3727 return _FrameShadowColor(base, flags & ~B_ACTIVATED); 3728 3729 rgb_color frameLightColor; 3730 3731 if ((flags & B_DISABLED) != 0) { 3732 // TODO: B_BLEND_FRAME 3733 frameLightColor = tint_color(base, 1.145); 3734 3735 if ((flags & B_DEFAULT_BUTTON) != 0) 3736 frameLightColor = tint_color(frameLightColor, 1.14); 3737 } else { 3738 if ((flags & B_BLEND_FRAME) != 0) 3739 frameLightColor = (rgb_color){ 0, 0, 0, 75 }; 3740 else 3741 frameLightColor = tint_color(base, 1.33); 3742 3743 if ((flags & B_DEFAULT_BUTTON) != 0) 3744 frameLightColor = tint_color(frameLightColor, 1.35); 3745 } 3746 3747 return frameLightColor; 3748 } 3749 3750 3751 rgb_color 3752 HaikuControlLook::_FrameShadowColor(const rgb_color& base, uint32 flags) 3753 { 3754 if ((flags & B_FOCUSED) != 0) 3755 return ui_color(B_KEYBOARD_NAVIGATION_COLOR); 3756 3757 if ((flags & B_ACTIVATED) != 0) 3758 return _FrameLightColor(base, flags & ~B_ACTIVATED); 3759 3760 rgb_color frameShadowColor; 3761 3762 if ((flags & B_DISABLED) != 0) { 3763 // TODO: B_BLEND_FRAME 3764 frameShadowColor = tint_color(base, 1.24); 3765 3766 if ((flags & B_DEFAULT_BUTTON) != 0) { 3767 frameShadowColor = tint_color(base, 1.145); 3768 frameShadowColor = tint_color(frameShadowColor, 1.12); 3769 } 3770 } else { 3771 if ((flags & B_DEFAULT_BUTTON) != 0) { 3772 if ((flags & B_BLEND_FRAME) != 0) 3773 frameShadowColor = (rgb_color){ 0, 0, 0, 75 }; 3774 else 3775 frameShadowColor = tint_color(base, 1.33); 3776 3777 frameShadowColor = tint_color(frameShadowColor, 1.5); 3778 } else { 3779 if ((flags & B_BLEND_FRAME) != 0) 3780 frameShadowColor = (rgb_color){ 0, 0, 0, 95 }; 3781 else 3782 frameShadowColor = tint_color(base, 1.47); 3783 } 3784 } 3785 3786 return frameShadowColor; 3787 } 3788 3789 3790 rgb_color 3791 HaikuControlLook::_BevelLightColor(const rgb_color& base, uint32 flags) 3792 { 3793 rgb_color bevelLightColor = tint_color(base, 0.2); 3794 3795 if ((flags & B_DISABLED) != 0) 3796 bevelLightColor = tint_color(base, B_LIGHTEN_1_TINT); 3797 3798 if ((flags & B_ACTIVATED) != 0) 3799 bevelLightColor = tint_color(base, B_DARKEN_1_TINT); 3800 3801 return bevelLightColor; 3802 } 3803 3804 3805 rgb_color 3806 HaikuControlLook::_BevelShadowColor(const rgb_color& base, uint32 flags) 3807 { 3808 rgb_color bevelShadowColor = tint_color(base, 1.08); 3809 3810 if ((flags & B_DISABLED) != 0) 3811 bevelShadowColor = base; 3812 3813 if ((flags & B_ACTIVATED) != 0) 3814 bevelShadowColor = tint_color(base, B_DARKEN_1_TINT); 3815 3816 return bevelShadowColor; 3817 } 3818 3819 3820 void 3821 HaikuControlLook::_FillGradient(BView* view, const BRect& rect, 3822 const rgb_color& base, float topTint, float bottomTint, 3823 orientation orientation) 3824 { 3825 BGradientLinear gradient; 3826 _MakeGradient(gradient, rect, base, topTint, bottomTint, orientation); 3827 view->FillRect(rect, gradient); 3828 } 3829 3830 3831 void 3832 HaikuControlLook::_FillGlossyGradient(BView* view, const BRect& rect, 3833 const rgb_color& base, float topTint, float middle1Tint, 3834 float middle2Tint, float bottomTint, orientation orientation) 3835 { 3836 BGradientLinear gradient; 3837 _MakeGlossyGradient(gradient, rect, base, topTint, middle1Tint, 3838 middle2Tint, bottomTint, orientation); 3839 view->FillRect(rect, gradient); 3840 } 3841 3842 3843 float 3844 HaikuControlLook::GetScrollBarWidth(orientation orientation) 3845 { 3846 // HaikuControlLook does not make a distinction between the 3847 // width and height of the scrollbar, but other controllooks may 3848 if (be_plain_font->Size() <= 12.0f) 3849 return 14.0f; 3850 return be_plain_font->Size() / 12.0f * 14.0f; 3851 } 3852 3853 3854 void 3855 HaikuControlLook::_MakeGradient(BGradientLinear& gradient, const BRect& rect, 3856 const rgb_color& base, float topTint, float bottomTint, 3857 orientation orientation) const 3858 { 3859 gradient.AddColor(tint_color(base, topTint), 0); 3860 gradient.AddColor(tint_color(base, bottomTint), 255); 3861 gradient.SetStart(rect.LeftTop()); 3862 if (orientation == B_HORIZONTAL) 3863 gradient.SetEnd(rect.LeftBottom()); 3864 else 3865 gradient.SetEnd(rect.RightTop()); 3866 } 3867 3868 3869 void 3870 HaikuControlLook::_MakeGlossyGradient(BGradientLinear& gradient, const BRect& rect, 3871 const rgb_color& base, float topTint, float middle1Tint, 3872 float middle2Tint, float bottomTint, 3873 orientation orientation) const 3874 { 3875 gradient.AddColor(tint_color(base, topTint), 0); 3876 gradient.AddColor(tint_color(base, middle1Tint), 132); 3877 gradient.AddColor(tint_color(base, middle2Tint), 136); 3878 gradient.AddColor(tint_color(base, bottomTint), 255); 3879 gradient.SetStart(rect.LeftTop()); 3880 if (orientation == B_HORIZONTAL) 3881 gradient.SetEnd(rect.LeftBottom()); 3882 else 3883 gradient.SetEnd(rect.RightTop()); 3884 } 3885 3886 3887 void 3888 HaikuControlLook::_MakeButtonGradient(BGradientLinear& gradient, BRect& rect, 3889 const rgb_color& base, uint32 flags, orientation orientation) const 3890 { 3891 float topTint = 0.49; 3892 float middleTint1 = 0.62; 3893 float middleTint2 = 0.76; 3894 float bottomTint = 0.90; 3895 3896 if ((flags & B_ACTIVATED) != 0) { 3897 topTint = 1.11; 3898 bottomTint = 1.08; 3899 } 3900 3901 if ((flags & B_DISABLED) != 0) { 3902 topTint = (topTint + B_NO_TINT) / 2; 3903 middleTint1 = (middleTint1 + B_NO_TINT) / 2; 3904 middleTint2 = (middleTint2 + B_NO_TINT) / 2; 3905 bottomTint = (bottomTint + B_NO_TINT) / 2; 3906 } else if ((flags & B_HOVER) != 0) { 3907 topTint *= kHoverTintFactor; 3908 middleTint1 *= kHoverTintFactor; 3909 middleTint2 *= kHoverTintFactor; 3910 bottomTint *= kHoverTintFactor; 3911 } 3912 3913 if ((flags & B_ACTIVATED) != 0) { 3914 _MakeGradient(gradient, rect, base, topTint, bottomTint, orientation); 3915 } else { 3916 _MakeGlossyGradient(gradient, rect, base, topTint, middleTint1, 3917 middleTint2, bottomTint, orientation); 3918 } 3919 } 3920 3921 3922 bool 3923 HaikuControlLook::_RadioButtonAndCheckBoxMarkColor(const rgb_color& base, 3924 rgb_color& color, uint32 flags) const 3925 { 3926 if ((flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED | B_CLICKED)) == 0) { 3927 // no mark to be drawn at all 3928 return false; 3929 } 3930 3931 color = ui_color(B_CONTROL_MARK_COLOR); 3932 3933 float mix = 1.0; 3934 3935 if ((flags & B_DISABLED) != 0) { 3936 // activated, but disabled 3937 mix = 0.4; 3938 } else if ((flags & B_CLICKED) != 0) { 3939 if ((flags & B_ACTIVATED) != 0) { 3940 // losing activation 3941 mix = 0.7; 3942 } else { 3943 // becoming activated (or losing partial activation) 3944 mix = 0.3; 3945 } 3946 } else if ((flags & B_PARTIALLY_ACTIVATED) != 0) { 3947 // partially activated 3948 mix = 0.5; 3949 } else { 3950 // simply activated 3951 } 3952 3953 color.red = uint8(color.red * mix + base.red * (1.0 - mix)); 3954 color.green = uint8(color.green * mix + base.green * (1.0 - mix)); 3955 color.blue = uint8(color.blue * mix + base.blue * (1.0 - mix)); 3956 3957 return true; 3958 } 3959 3960 } // namespace BPrivate 3961