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