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