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 (base.red + base.green + base.blue <= 128 * 3) { 1729 scrollbarFrameColor = tint_color(base, B_LIGHTEN_1_TINT); 1730 } 1731 1732 if ((flags & B_FOCUSED) != 0) 1733 scrollbarFrameColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 1734 1735 if (borderStyle == B_FANCY_BORDER) 1736 _DrawOuterResessedFrame(view, rect, base, 1.0, 1.0, flags, borders); 1737 1738 _DrawFrame(view, rect, scrollbarFrameColor, scrollbarFrameColor, 1739 scrollbarFrameColor, scrollbarFrameColor, borders); 1740 } 1741 1742 1743 void 1744 HaikuControlLook::DrawRaisedBorder(BView* view, BRect& rect, 1745 const BRect& updateRect, const rgb_color& base, uint32 flags, 1746 uint32 borders) 1747 { 1748 rgb_color lightColor; 1749 rgb_color shadowColor; 1750 1751 if ((flags & B_DISABLED) != 0) { 1752 lightColor = base; 1753 shadowColor = base; 1754 } else { 1755 lightColor = tint_color(base, 0.85); 1756 shadowColor = tint_color(base, 1.07); 1757 } 1758 1759 _DrawFrame(view, rect, lightColor, lightColor, shadowColor, shadowColor, 1760 borders); 1761 } 1762 1763 1764 void 1765 HaikuControlLook::DrawTextControlBorder(BView* view, BRect& rect, 1766 const BRect& updateRect, const rgb_color& base, uint32 flags, 1767 uint32 borders) 1768 { 1769 if (!rect.Intersects(updateRect)) 1770 return; 1771 1772 rgb_color dark1BorderColor; 1773 rgb_color dark2BorderColor; 1774 rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 1775 rgb_color invalidColor = ui_color(B_FAILURE_COLOR); 1776 1777 if ((flags & B_DISABLED) != 0) { 1778 _DrawOuterResessedFrame(view, rect, base, 0.0, 1.0, flags, borders); 1779 1780 if ((flags & B_BLEND_FRAME) != 0) 1781 dark1BorderColor = (rgb_color){ 0, 0, 0, 40 }; 1782 else 1783 dark1BorderColor = tint_color(base, 1.15); 1784 dark2BorderColor = dark1BorderColor; 1785 } else if ((flags & B_CLICKED) != 0) { 1786 dark1BorderColor = tint_color(base, 1.50); 1787 dark2BorderColor = tint_color(base, 1.49); 1788 1789 // BCheckBox uses this to indicate the clicked state... 1790 _DrawFrame(view, rect, 1791 dark1BorderColor, dark1BorderColor, 1792 dark2BorderColor, dark2BorderColor); 1793 1794 dark2BorderColor = dark1BorderColor; 1795 } else { 1796 _DrawOuterResessedFrame(view, rect, base, 0.6, 1.0, flags, borders); 1797 1798 if ((flags & B_BLEND_FRAME) != 0) { 1799 dark1BorderColor = (rgb_color){ 0, 0, 0, 102 }; 1800 dark2BorderColor = (rgb_color){ 0, 0, 0, 97 }; 1801 } else { 1802 dark1BorderColor = tint_color(base, 1.40); 1803 dark2BorderColor = tint_color(base, 1.38); 1804 } 1805 } 1806 1807 if ((flags & B_DISABLED) == 0 && (flags & B_FOCUSED) != 0) { 1808 dark1BorderColor = navigationColor; 1809 dark2BorderColor = navigationColor; 1810 } 1811 1812 if ((flags & B_DISABLED) == 0 && (flags & B_INVALID) != 0) { 1813 dark1BorderColor = invalidColor; 1814 dark2BorderColor = invalidColor; 1815 } 1816 1817 if ((flags & B_BLEND_FRAME) != 0) { 1818 drawing_mode oldMode = view->DrawingMode(); 1819 view->SetDrawingMode(B_OP_ALPHA); 1820 1821 _DrawFrame(view, rect, 1822 dark1BorderColor, dark1BorderColor, 1823 dark2BorderColor, dark2BorderColor, borders); 1824 1825 view->SetDrawingMode(oldMode); 1826 } else { 1827 _DrawFrame(view, rect, 1828 dark1BorderColor, dark1BorderColor, 1829 dark2BorderColor, dark2BorderColor, borders); 1830 } 1831 } 1832 1833 1834 void 1835 HaikuControlLook::DrawGroupFrame(BView* view, BRect& rect, const BRect& updateRect, 1836 const rgb_color& base, uint32 borders) 1837 { 1838 rgb_color frameColor = tint_color(base, 1.30); 1839 rgb_color bevelLight = tint_color(base, 0.8); 1840 rgb_color bevelShadow = tint_color(base, 1.03); 1841 1842 _DrawFrame(view, rect, bevelShadow, bevelShadow, bevelLight, bevelLight, 1843 borders); 1844 1845 _DrawFrame(view, rect, frameColor, frameColor, frameColor, frameColor, 1846 borders); 1847 1848 _DrawFrame(view, rect, bevelLight, bevelLight, bevelShadow, bevelShadow, 1849 borders); 1850 } 1851 1852 1853 void 1854 HaikuControlLook::DrawLabel(BView* view, const char* label, BRect rect, 1855 const BRect& updateRect, const rgb_color& base, uint32 flags, 1856 const rgb_color* textColor) 1857 { 1858 DrawLabel(view, label, NULL, rect, updateRect, base, flags, 1859 DefaultLabelAlignment(), textColor); 1860 } 1861 1862 1863 void 1864 HaikuControlLook::DrawLabel(BView* view, const char* label, BRect rect, 1865 const BRect& updateRect, const rgb_color& base, uint32 flags, 1866 const BAlignment& alignment, const rgb_color* textColor) 1867 { 1868 DrawLabel(view, label, NULL, rect, updateRect, base, flags, alignment, 1869 textColor); 1870 } 1871 1872 1873 void 1874 HaikuControlLook::DrawLabel(BView* view, const char* label, const rgb_color& base, 1875 uint32 flags, const BPoint& where, const rgb_color* textColor) 1876 { 1877 // setup the text color 1878 1879 BWindow* window = view->Window(); 1880 bool isDesktop = window 1881 && window->Feel() == kDesktopWindowFeel 1882 && window->Look() == kDesktopWindowLook 1883 && view->Parent() 1884 && view->Parent()->Parent() == NULL 1885 && (flags & B_IGNORE_OUTLINE) == 0; 1886 1887 rgb_color low; 1888 rgb_color color; 1889 rgb_color glowColor; 1890 1891 if (textColor != NULL) 1892 glowColor = *textColor; 1893 else if ((flags & B_IS_CONTROL) != 0) 1894 glowColor = ui_color(B_CONTROL_TEXT_COLOR); 1895 else 1896 glowColor = ui_color(B_PANEL_TEXT_COLOR); 1897 1898 color = glowColor; 1899 1900 if (isDesktop) 1901 low = view->Parent()->ViewColor(); 1902 else 1903 low = base; 1904 1905 if ((flags & B_DISABLED) != 0) { 1906 color.red = (uint8)(((int32)low.red + color.red + 1) / 2); 1907 color.green = (uint8)(((int32)low.green + color.green + 1) / 2); 1908 color.blue = (uint8)(((int32)low.blue + color.blue + 1) / 2); 1909 } 1910 1911 drawing_mode oldMode = view->DrawingMode(); 1912 1913 if (isDesktop) { 1914 // enforce proper use of desktop label colors 1915 if (low.Brightness() < 100) { 1916 if (textColor == NULL) 1917 color = make_color(255, 255, 255); 1918 1919 glowColor = make_color(0, 0, 0); 1920 } else { 1921 if (textColor == NULL) 1922 color = make_color(0, 0, 0); 1923 1924 glowColor = make_color(255, 255, 255); 1925 } 1926 1927 // drawing occurs on the desktop 1928 if (fCachedWorkspace != current_workspace()) { 1929 int8 indice = 0; 1930 int32 mask; 1931 bool tmpOutline; 1932 while (fBackgroundInfo.FindInt32("be:bgndimginfoworkspaces", 1933 indice, &mask) == B_OK 1934 && fBackgroundInfo.FindBool("be:bgndimginfoerasetext", 1935 indice, &tmpOutline) == B_OK) { 1936 1937 if (((1 << current_workspace()) & mask) != 0) { 1938 fCachedOutline = tmpOutline; 1939 fCachedWorkspace = current_workspace(); 1940 break; 1941 } 1942 indice++; 1943 } 1944 } 1945 1946 if (fCachedOutline) { 1947 BFont font; 1948 view->GetFont(&font); 1949 1950 view->SetDrawingMode(B_OP_ALPHA); 1951 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY); 1952 // Draw glow or outline 1953 if (glowColor.Brightness() > 128) { 1954 font.SetFalseBoldWidth(2.0); 1955 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 1956 1957 glowColor.alpha = 30; 1958 view->SetHighColor(glowColor); 1959 view->DrawString(label, where); 1960 1961 font.SetFalseBoldWidth(1.0); 1962 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 1963 1964 glowColor.alpha = 65; 1965 view->SetHighColor(glowColor); 1966 view->DrawString(label, where); 1967 1968 font.SetFalseBoldWidth(0.0); 1969 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 1970 } else { 1971 font.SetFalseBoldWidth(1.0); 1972 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 1973 1974 glowColor.alpha = 30; 1975 view->SetHighColor(glowColor); 1976 view->DrawString(label, where); 1977 1978 font.SetFalseBoldWidth(0.0); 1979 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH); 1980 1981 glowColor.alpha = 200; 1982 view->SetHighColor(glowColor); 1983 view->DrawString(label, BPoint(where.x + 1, where.y + 1)); 1984 } 1985 } 1986 } 1987 1988 view->SetHighColor(color); 1989 view->SetDrawingMode(B_OP_OVER); 1990 view->DrawString(label, where); 1991 view->SetDrawingMode(oldMode); 1992 } 1993 1994 1995 void 1996 HaikuControlLook::DrawLabel(BView* view, const char* label, const BBitmap* icon, 1997 BRect rect, const BRect& updateRect, const rgb_color& base, uint32 flags, 1998 const BAlignment& alignment, const rgb_color* textColor) 1999 { 2000 if (!rect.Intersects(updateRect)) 2001 return; 2002 2003 if (label == NULL && icon == NULL) 2004 return; 2005 2006 if (label == NULL) { 2007 // icon only 2008 BRect alignedRect = BLayoutUtils::AlignInFrame(rect, 2009 icon->Bounds().Size(), alignment); 2010 drawing_mode oldMode = view->DrawingMode(); 2011 view->SetDrawingMode(B_OP_OVER); 2012 view->DrawBitmap(icon, alignedRect.LeftTop()); 2013 view->SetDrawingMode(oldMode); 2014 return; 2015 } 2016 2017 // label, possibly with icon 2018 float availableWidth = rect.Width() + 1; 2019 float width = 0; 2020 float textOffset = 0; 2021 float height = 0; 2022 2023 if (icon != NULL) { 2024 width = icon->Bounds().Width() + DefaultLabelSpacing() + 1; 2025 height = icon->Bounds().Height() + 1; 2026 textOffset = width; 2027 availableWidth -= textOffset; 2028 } 2029 2030 // truncate the label if necessary and get the width and height 2031 BString truncatedLabel(label); 2032 2033 BFont font; 2034 view->GetFont(&font); 2035 2036 font.TruncateString(&truncatedLabel, B_TRUNCATE_END, availableWidth); 2037 width += ceilf(font.StringWidth(truncatedLabel.String())); 2038 2039 font_height fontHeight; 2040 font.GetHeight(&fontHeight); 2041 float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); 2042 height = std::max(height, textHeight); 2043 2044 // handle alignment 2045 BRect alignedRect(BLayoutUtils::AlignOnRect(rect, 2046 BSize(width - 1, height - 1), alignment)); 2047 2048 if (icon != NULL) { 2049 BPoint location(alignedRect.LeftTop()); 2050 if (icon->Bounds().Height() + 1 < height) 2051 location.y += ceilf((height - icon->Bounds().Height() - 1) / 2); 2052 2053 drawing_mode oldMode = view->DrawingMode(); 2054 view->SetDrawingMode(B_OP_OVER); 2055 view->DrawBitmap(icon, location); 2056 view->SetDrawingMode(oldMode); 2057 } 2058 2059 BPoint location(alignedRect.left + textOffset, 2060 alignedRect.top + ceilf(fontHeight.ascent)); 2061 if (textHeight < height) 2062 location.y += ceilf((height - textHeight) / 2); 2063 2064 DrawLabel(view, truncatedLabel.String(), base, flags, location, textColor); 2065 } 2066 2067 2068 void 2069 HaikuControlLook::GetFrameInsets(frame_type frameType, uint32 flags, float& _left, 2070 float& _top, float& _right, float& _bottom) 2071 { 2072 // All frames have the same inset on each side. 2073 float inset = 0; 2074 2075 switch (frameType) { 2076 case B_BUTTON_FRAME: 2077 inset = (flags & B_DEFAULT_BUTTON) != 0 ? 5 : 2; 2078 break; 2079 case B_GROUP_FRAME: 2080 case B_MENU_FIELD_FRAME: 2081 inset = 3; 2082 break; 2083 case B_SCROLL_VIEW_FRAME: 2084 case B_TEXT_CONTROL_FRAME: 2085 inset = 2; 2086 break; 2087 } 2088 2089 _left = inset; 2090 _top = inset; 2091 _right = inset; 2092 _bottom = inset; 2093 } 2094 2095 2096 void 2097 HaikuControlLook::GetBackgroundInsets(background_type backgroundType, 2098 uint32 flags, float& _left, float& _top, float& _right, float& _bottom) 2099 { 2100 // Most backgrounds have the same inset on each side. 2101 float inset = 0; 2102 2103 switch (backgroundType) { 2104 case B_BUTTON_BACKGROUND: 2105 case B_MENU_BACKGROUND: 2106 case B_MENU_BAR_BACKGROUND: 2107 case B_MENU_FIELD_BACKGROUND: 2108 case B_MENU_ITEM_BACKGROUND: 2109 inset = 1; 2110 break; 2111 case B_BUTTON_WITH_POP_UP_BACKGROUND: 2112 _left = 1; 2113 _top = 1; 2114 _right = 1 + kButtonPopUpIndicatorWidth; 2115 _bottom = 1; 2116 return; 2117 case B_HORIZONTAL_SCROLL_BAR_BACKGROUND: 2118 _left = 2; 2119 _top = 0; 2120 _right = 1; 2121 _bottom = 0; 2122 return; 2123 case B_VERTICAL_SCROLL_BAR_BACKGROUND: 2124 _left = 0; 2125 _top = 2; 2126 _right = 0; 2127 _bottom = 1; 2128 return; 2129 } 2130 2131 _left = inset; 2132 _top = inset; 2133 _right = inset; 2134 _bottom = inset; 2135 } 2136 2137 2138 void 2139 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect, 2140 const BRect& updateRect, const rgb_color& base, uint32 flags, 2141 uint32 borders, orientation orientation) 2142 { 2143 _DrawButtonBackground(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f, 2144 base, true, flags, borders, orientation); 2145 } 2146 2147 2148 void 2149 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect, 2150 const BRect& updateRect, float radius, const rgb_color& base, uint32 flags, 2151 uint32 borders, orientation orientation) 2152 { 2153 _DrawButtonBackground(view, rect, updateRect, radius, radius, radius, 2154 radius, base, true, flags, borders, orientation); 2155 } 2156 2157 2158 void 2159 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect, 2160 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 2161 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 2162 uint32 flags, uint32 borders, orientation orientation) 2163 { 2164 _DrawButtonBackground(view, rect, updateRect, leftTopRadius, 2165 rightTopRadius, leftBottomRadius, rightBottomRadius, base, true, flags, 2166 borders, orientation); 2167 } 2168 2169 2170 // #pragma mark - 2171 2172 2173 void 2174 HaikuControlLook::_DrawButtonFrame(BView* view, BRect& rect, 2175 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 2176 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 2177 const rgb_color& background, float contrast, float brightness, 2178 uint32 flags, uint32 borders) 2179 { 2180 if (!rect.IsValid()) 2181 return; 2182 2183 // save the clipping constraints of the view 2184 view->PushState(); 2185 2186 // set clipping constraints to updateRect 2187 BRegion clipping(updateRect); 2188 view->ConstrainClippingRegion(&clipping); 2189 2190 // If the button is flat and neither activated nor otherwise highlighted 2191 // (mouse hovering or focussed), draw it flat. 2192 if ((flags & B_FLAT) != 0 2193 && (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0 2194 && ((flags & (B_HOVER | B_FOCUSED)) == 0 2195 || (flags & B_DISABLED) != 0)) { 2196 _DrawFrame(view, rect, background, background, background, 2197 background, borders); 2198 _DrawFrame(view, rect, background, background, background, 2199 background, borders); 2200 view->PopState(); 2201 return; 2202 } 2203 2204 // outer edge colors 2205 rgb_color edgeLightColor; 2206 rgb_color edgeShadowColor; 2207 2208 // default button frame color 2209 rgb_color defaultIndicatorColor = ui_color(B_CONTROL_BORDER_COLOR); 2210 rgb_color cornerBgColor; 2211 2212 if ((flags & B_DISABLED) != 0) { 2213 defaultIndicatorColor = disable_color(defaultIndicatorColor, 2214 background); 2215 } 2216 2217 drawing_mode oldMode = view->DrawingMode(); 2218 2219 if ((flags & B_DEFAULT_BUTTON) != 0) { 2220 cornerBgColor = defaultIndicatorColor; 2221 edgeLightColor = _EdgeLightColor(defaultIndicatorColor, 2222 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8), 2223 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags); 2224 edgeShadowColor = _EdgeShadowColor(defaultIndicatorColor, 2225 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8), 2226 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags); 2227 2228 // draw default button indicator 2229 // Allow a 1-pixel border of the background to come through. 2230 rect.InsetBy(1, 1); 2231 2232 view->SetHighColor(defaultIndicatorColor); 2233 view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius); 2234 rect.InsetBy(1, 1); 2235 2236 view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius); 2237 rect.InsetBy(1, 1); 2238 } else { 2239 cornerBgColor = background; 2240 if ((flags & B_BLEND_FRAME) != 0) { 2241 // set the background color to transparent for the case 2242 // that we are on the desktop 2243 cornerBgColor.alpha = 0; 2244 view->SetDrawingMode(B_OP_ALPHA); 2245 } 2246 2247 edgeLightColor = _EdgeLightColor(background, 2248 contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0), 2249 brightness * 1.0, flags); 2250 edgeShadowColor = _EdgeShadowColor(background, 2251 contrast * (flags & B_DISABLED) != 0 ? 0.0 : 1.0, 2252 brightness * 1.0, flags); 2253 } 2254 2255 // frame colors 2256 rgb_color frameLightColor = _FrameLightColor(base, flags); 2257 rgb_color frameShadowColor = _FrameShadowColor(base, flags); 2258 2259 // rounded corners 2260 2261 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0 2262 && leftTopRadius > 0) { 2263 // draw left top rounded corner 2264 BRect leftTopCorner(floorf(rect.left), floorf(rect.top), 2265 floorf(rect.left + leftTopRadius), 2266 floorf(rect.top + leftTopRadius)); 2267 clipping.Exclude(leftTopCorner); 2268 _DrawRoundCornerFrameLeftTop(view, leftTopCorner, updateRect, 2269 cornerBgColor, edgeShadowColor, frameLightColor); 2270 } 2271 2272 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0 2273 && rightTopRadius > 0) { 2274 // draw right top rounded corner 2275 BRect rightTopCorner(floorf(rect.right - rightTopRadius), 2276 floorf(rect.top), floorf(rect.right), 2277 floorf(rect.top + rightTopRadius)); 2278 clipping.Exclude(rightTopCorner); 2279 _DrawRoundCornerFrameRightTop(view, rightTopCorner, updateRect, 2280 cornerBgColor, edgeShadowColor, edgeLightColor, 2281 frameLightColor, frameShadowColor); 2282 } 2283 2284 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2285 && leftBottomRadius > 0) { 2286 // draw left bottom rounded corner 2287 BRect leftBottomCorner(floorf(rect.left), 2288 floorf(rect.bottom - leftBottomRadius), 2289 floorf(rect.left + leftBottomRadius), floorf(rect.bottom)); 2290 clipping.Exclude(leftBottomCorner); 2291 _DrawRoundCornerFrameLeftBottom(view, leftBottomCorner, updateRect, 2292 cornerBgColor, edgeShadowColor, edgeLightColor, 2293 frameLightColor, frameShadowColor); 2294 } 2295 2296 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2297 && rightBottomRadius > 0) { 2298 // draw right bottom rounded corner 2299 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius), 2300 floorf(rect.bottom - rightBottomRadius), floorf(rect.right), 2301 floorf(rect.bottom)); 2302 clipping.Exclude(rightBottomCorner); 2303 _DrawRoundCornerFrameRightBottom(view, rightBottomCorner, 2304 updateRect, cornerBgColor, edgeLightColor, frameShadowColor); 2305 } 2306 2307 // clip out the corners 2308 view->ConstrainClippingRegion(&clipping); 2309 2310 // draw outer edge 2311 if ((flags & B_DEFAULT_BUTTON) != 0) { 2312 _DrawOuterResessedFrame(view, rect, defaultIndicatorColor, 2313 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8), 2314 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), 2315 flags, borders); 2316 } else { 2317 _DrawOuterResessedFrame(view, rect, background, 2318 contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0), 2319 brightness * 1.0, flags, borders); 2320 } 2321 2322 view->SetDrawingMode(oldMode); 2323 2324 // draw frame 2325 if ((flags & B_BLEND_FRAME) != 0) { 2326 drawing_mode oldDrawingMode = view->DrawingMode(); 2327 view->SetDrawingMode(B_OP_ALPHA); 2328 2329 _DrawFrame(view, rect, frameLightColor, frameLightColor, 2330 frameShadowColor, frameShadowColor, borders); 2331 2332 view->SetDrawingMode(oldDrawingMode); 2333 } else { 2334 _DrawFrame(view, rect, frameLightColor, frameLightColor, 2335 frameShadowColor, frameShadowColor, borders); 2336 } 2337 2338 // restore the clipping constraints of the view 2339 view->PopState(); 2340 } 2341 2342 2343 void 2344 HaikuControlLook::_DrawOuterResessedFrame(BView* view, BRect& rect, 2345 const rgb_color& base, float contrast, float brightness, uint32 flags, 2346 uint32 borders) 2347 { 2348 rgb_color edgeLightColor = _EdgeLightColor(base, contrast, 2349 brightness, flags); 2350 rgb_color edgeShadowColor = _EdgeShadowColor(base, contrast, 2351 brightness, flags); 2352 2353 if ((flags & B_BLEND_FRAME) != 0) { 2354 // assumes the background has already been painted 2355 drawing_mode oldDrawingMode = view->DrawingMode(); 2356 view->SetDrawingMode(B_OP_ALPHA); 2357 2358 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, 2359 edgeLightColor, edgeLightColor, borders); 2360 2361 view->SetDrawingMode(oldDrawingMode); 2362 } else { 2363 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, 2364 edgeLightColor, edgeLightColor, borders); 2365 } 2366 } 2367 2368 2369 void 2370 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left, 2371 const rgb_color& top, const rgb_color& right, const rgb_color& bottom, 2372 uint32 borders) 2373 { 2374 view->BeginLineArray(4); 2375 2376 if (borders & B_LEFT_BORDER) { 2377 view->AddLine( 2378 BPoint(rect.left, rect.bottom), 2379 BPoint(rect.left, rect.top), left); 2380 rect.left++; 2381 } 2382 if (borders & B_TOP_BORDER) { 2383 view->AddLine( 2384 BPoint(rect.left, rect.top), 2385 BPoint(rect.right, rect.top), top); 2386 rect.top++; 2387 } 2388 if (borders & B_RIGHT_BORDER) { 2389 view->AddLine( 2390 BPoint(rect.right, rect.top), 2391 BPoint(rect.right, rect.bottom), right); 2392 rect.right--; 2393 } 2394 if (borders & B_BOTTOM_BORDER) { 2395 view->AddLine( 2396 BPoint(rect.left, rect.bottom), 2397 BPoint(rect.right, rect.bottom), bottom); 2398 rect.bottom--; 2399 } 2400 2401 view->EndLineArray(); 2402 } 2403 2404 2405 void 2406 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left, 2407 const rgb_color& top, const rgb_color& right, const rgb_color& bottom, 2408 const rgb_color& rightTop, const rgb_color& leftBottom, uint32 borders) 2409 { 2410 view->BeginLineArray(6); 2411 2412 if (borders & B_TOP_BORDER) { 2413 if (borders & B_RIGHT_BORDER) { 2414 view->AddLine( 2415 BPoint(rect.left, rect.top), 2416 BPoint(rect.right - 1, rect.top), top); 2417 view->AddLine( 2418 BPoint(rect.right, rect.top), 2419 BPoint(rect.right, rect.top), rightTop); 2420 } else { 2421 view->AddLine( 2422 BPoint(rect.left, rect.top), 2423 BPoint(rect.right, rect.top), top); 2424 } 2425 rect.top++; 2426 } 2427 2428 if (borders & B_LEFT_BORDER) { 2429 view->AddLine( 2430 BPoint(rect.left, rect.top), 2431 BPoint(rect.left, rect.bottom - 1), left); 2432 view->AddLine( 2433 BPoint(rect.left, rect.bottom), 2434 BPoint(rect.left, rect.bottom), leftBottom); 2435 rect.left++; 2436 } 2437 2438 if (borders & B_BOTTOM_BORDER) { 2439 view->AddLine( 2440 BPoint(rect.left, rect.bottom), 2441 BPoint(rect.right, rect.bottom), bottom); 2442 rect.bottom--; 2443 } 2444 2445 if (borders & B_RIGHT_BORDER) { 2446 view->AddLine( 2447 BPoint(rect.right, rect.bottom), 2448 BPoint(rect.right, rect.top), right); 2449 rect.right--; 2450 } 2451 2452 view->EndLineArray(); 2453 } 2454 2455 2456 void 2457 HaikuControlLook::_DrawButtonBackground(BView* view, BRect& rect, 2458 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 2459 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 2460 bool popupIndicator, uint32 flags, uint32 borders, orientation orientation) 2461 { 2462 if (!rect.IsValid()) 2463 return; 2464 2465 // save the clipping constraints of the view 2466 view->PushState(); 2467 2468 // set clipping constraints to updateRect 2469 BRegion clipping(updateRect); 2470 view->ConstrainClippingRegion(&clipping); 2471 2472 // If the button is flat and neither activated nor otherwise highlighted 2473 // (mouse hovering or focussed), draw it flat. 2474 if ((flags & B_FLAT) != 0 2475 && (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0 2476 && ((flags & (B_HOVER | B_FOCUSED)) == 0 2477 || (flags & B_DISABLED) != 0)) { 2478 _DrawFlatButtonBackground(view, rect, updateRect, base, popupIndicator, 2479 flags, borders, orientation); 2480 } else { 2481 _DrawNonFlatButtonBackground(view, rect, updateRect, clipping, 2482 leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius, 2483 base, popupIndicator, flags, borders, orientation); 2484 } 2485 2486 // restore the clipping constraints of the view 2487 view->PopState(); 2488 } 2489 2490 2491 void 2492 HaikuControlLook::_DrawFlatButtonBackground(BView* view, BRect& rect, 2493 const BRect& updateRect, const rgb_color& base, bool popupIndicator, 2494 uint32 flags, uint32 borders, orientation orientation) 2495 { 2496 _DrawFrame(view, rect, base, base, base, base, borders); 2497 // Not an actual frame, but the method insets our rect as needed. 2498 2499 view->SetHighColor(base); 2500 view->FillRect(rect); 2501 2502 if (popupIndicator) { 2503 BRect indicatorRect(rect); 2504 rect.right -= kButtonPopUpIndicatorWidth; 2505 indicatorRect.left = rect.right + 3; 2506 // 2 pixels for the separator 2507 2508 view->SetHighColor(base); 2509 view->FillRect(indicatorRect); 2510 2511 _DrawPopUpMarker(view, indicatorRect, base, flags); 2512 } 2513 } 2514 2515 2516 void 2517 HaikuControlLook::_DrawNonFlatButtonBackground(BView* view, BRect& rect, 2518 const BRect& updateRect, BRegion& clipping, float leftTopRadius, 2519 float rightTopRadius, float leftBottomRadius, float rightBottomRadius, 2520 const rgb_color& base, bool popupIndicator, uint32 flags, uint32 borders, 2521 orientation orientation) 2522 { 2523 // inner bevel colors 2524 rgb_color bevelLightColor = _BevelLightColor(base, flags); 2525 rgb_color bevelShadowColor = _BevelShadowColor(base, flags); 2526 2527 // button background color 2528 rgb_color buttonBgColor; 2529 if ((flags & B_DISABLED) != 0) 2530 buttonBgColor = tint_color(base, 0.7); 2531 else 2532 buttonBgColor = tint_color(base, B_LIGHTEN_1_TINT); 2533 2534 // surface top gradient 2535 BGradientLinear fillGradient; 2536 _MakeButtonGradient(fillGradient, rect, base, flags, orientation); 2537 2538 // rounded corners 2539 2540 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0 2541 && leftTopRadius > 0) { 2542 // draw left top rounded corner 2543 BRect leftTopCorner(floorf(rect.left), floorf(rect.top), 2544 floorf(rect.left + leftTopRadius - 2.0), 2545 floorf(rect.top + leftTopRadius - 2.0)); 2546 clipping.Exclude(leftTopCorner); 2547 _DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect, 2548 bevelLightColor, fillGradient); 2549 } 2550 2551 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0 2552 && rightTopRadius > 0) { 2553 // draw right top rounded corner 2554 BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0), 2555 floorf(rect.top), floorf(rect.right), 2556 floorf(rect.top + rightTopRadius - 2.0)); 2557 clipping.Exclude(rightTopCorner); 2558 _DrawRoundCornerBackgroundRightTop(view, rightTopCorner, 2559 updateRect, bevelLightColor, bevelShadowColor, fillGradient); 2560 } 2561 2562 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2563 && leftBottomRadius > 0) { 2564 // draw left bottom rounded corner 2565 BRect leftBottomCorner(floorf(rect.left), 2566 floorf(rect.bottom - leftBottomRadius + 2.0), 2567 floorf(rect.left + leftBottomRadius - 2.0), 2568 floorf(rect.bottom)); 2569 clipping.Exclude(leftBottomCorner); 2570 _DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner, 2571 updateRect, bevelLightColor, bevelShadowColor, fillGradient); 2572 } 2573 2574 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2575 && rightBottomRadius > 0) { 2576 // draw right bottom rounded corner 2577 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0), 2578 floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right), 2579 floorf(rect.bottom)); 2580 clipping.Exclude(rightBottomCorner); 2581 _DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner, 2582 updateRect, bevelShadowColor, fillGradient); 2583 } 2584 2585 // clip out the corners 2586 view->ConstrainClippingRegion(&clipping); 2587 2588 // draw inner bevel 2589 2590 if ((flags & B_ACTIVATED) != 0) { 2591 view->BeginLineArray(4); 2592 2593 // shadow along left/top borders 2594 if (borders & B_LEFT_BORDER) { 2595 view->AddLine(BPoint(rect.left, rect.top), 2596 BPoint(rect.left, rect.bottom), bevelLightColor); 2597 rect.left++; 2598 } 2599 if (borders & B_TOP_BORDER) { 2600 view->AddLine(BPoint(rect.left, rect.top), 2601 BPoint(rect.right, rect.top), bevelLightColor); 2602 rect.top++; 2603 } 2604 2605 // softer shadow along left/top borders 2606 if (borders & B_LEFT_BORDER) { 2607 view->AddLine(BPoint(rect.left, rect.top), 2608 BPoint(rect.left, rect.bottom), bevelShadowColor); 2609 rect.left++; 2610 } 2611 if (borders & B_TOP_BORDER) { 2612 view->AddLine(BPoint(rect.left, rect.top), 2613 BPoint(rect.right, rect.top), bevelShadowColor); 2614 rect.top++; 2615 } 2616 2617 view->EndLineArray(); 2618 } else { 2619 _DrawFrame(view, rect, 2620 bevelLightColor, bevelLightColor, 2621 bevelShadowColor, bevelShadowColor, 2622 buttonBgColor, buttonBgColor, borders); 2623 } 2624 2625 if (popupIndicator) { 2626 BRect indicatorRect(rect); 2627 rect.right -= kButtonPopUpIndicatorWidth; 2628 indicatorRect.left = rect.right + 3; 2629 // 2 pixels for the separator 2630 2631 // Even when depressed we want the pop-up indicator background and 2632 // separator to cover the area up to the top. 2633 if ((flags & B_ACTIVATED) != 0) 2634 indicatorRect.top--; 2635 2636 // draw the separator 2637 rgb_color separatorBaseColor = base; 2638 if ((flags & B_ACTIVATED) != 0) 2639 separatorBaseColor = tint_color(base, B_DARKEN_1_TINT); 2640 2641 rgb_color separatorLightColor = _EdgeLightColor(separatorBaseColor, 2642 (flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags); 2643 rgb_color separatorShadowColor = _EdgeShadowColor(separatorBaseColor, 2644 (flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags); 2645 2646 view->BeginLineArray(2); 2647 2648 view->AddLine(BPoint(indicatorRect.left - 2, indicatorRect.top), 2649 BPoint(indicatorRect.left - 2, indicatorRect.bottom), 2650 separatorShadowColor); 2651 view->AddLine(BPoint(indicatorRect.left - 1, indicatorRect.top), 2652 BPoint(indicatorRect.left - 1, indicatorRect.bottom), 2653 separatorLightColor); 2654 2655 view->EndLineArray(); 2656 2657 // draw background and pop-up marker 2658 _DrawMenuFieldBackgroundInside(view, indicatorRect, updateRect, 2659 0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags, 0); 2660 2661 if ((flags & B_ACTIVATED) != 0) 2662 indicatorRect.top++; 2663 2664 _DrawPopUpMarker(view, indicatorRect, base, flags); 2665 } 2666 2667 // fill in the background 2668 view->FillRect(rect, fillGradient); 2669 } 2670 2671 2672 void 2673 HaikuControlLook::_DrawPopUpMarker(BView* view, const BRect& rect, 2674 const rgb_color& base, uint32 flags) 2675 { 2676 BPoint center(roundf((rect.left + rect.right) / 2.0), 2677 roundf((rect.top + rect.bottom) / 2.0)); 2678 BPoint triangle[3]; 2679 triangle[0] = center + BPoint(-2.5, -0.5); 2680 triangle[1] = center + BPoint(2.5, -0.5); 2681 triangle[2] = center + BPoint(0.0, 2.0); 2682 2683 uint32 viewFlags = view->Flags(); 2684 view->SetFlags(viewFlags | B_SUBPIXEL_PRECISE); 2685 2686 rgb_color markColor; 2687 if ((flags & B_DISABLED) != 0) 2688 markColor = tint_color(base, 1.35); 2689 else 2690 markColor = tint_color(base, 1.65); 2691 2692 view->SetHighColor(markColor); 2693 view->FillTriangle(triangle[0], triangle[1], triangle[2]); 2694 2695 view->SetFlags(viewFlags); 2696 } 2697 2698 2699 void 2700 HaikuControlLook::_DrawMenuFieldBackgroundOutside(BView* view, BRect& rect, 2701 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 2702 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 2703 bool popupIndicator, uint32 flags) 2704 { 2705 if (!rect.IsValid() || !rect.Intersects(updateRect)) 2706 return; 2707 2708 if (popupIndicator) { 2709 BRect leftRect(rect); 2710 leftRect.right -= 10; 2711 2712 BRect rightRect(rect); 2713 rightRect.left = rightRect.right - 9; 2714 2715 _DrawMenuFieldBackgroundInside(view, leftRect, updateRect, 2716 leftTopRadius, 0.0f, leftBottomRadius, 0.0f, base, flags, 2717 B_LEFT_BORDER | B_TOP_BORDER | B_BOTTOM_BORDER); 2718 2719 _DrawMenuFieldBackgroundInside(view, rightRect, updateRect, 2720 0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags, 2721 B_TOP_BORDER | B_RIGHT_BORDER | B_BOTTOM_BORDER); 2722 2723 _DrawPopUpMarker(view, rightRect, base, flags); 2724 2725 // draw a line on the left of the popup frame 2726 rgb_color bevelShadowColor = _BevelShadowColor(base, flags); 2727 view->SetHighColor(bevelShadowColor); 2728 BPoint leftTopCorner(floorf(rightRect.left - 1.0), 2729 floorf(rightRect.top - 1.0)); 2730 BPoint leftBottomCorner(floorf(rightRect.left - 1.0), 2731 floorf(rightRect.bottom + 1.0)); 2732 view->StrokeLine(leftTopCorner, leftBottomCorner); 2733 2734 rect = leftRect; 2735 } else { 2736 _DrawMenuFieldBackgroundInside(view, rect, updateRect, leftTopRadius, 2737 rightTopRadius, leftBottomRadius, rightBottomRadius, base, flags); 2738 } 2739 } 2740 2741 2742 void 2743 HaikuControlLook::_DrawMenuFieldBackgroundInside(BView* view, BRect& rect, 2744 const BRect& updateRect, float leftTopRadius, float rightTopRadius, 2745 float leftBottomRadius, float rightBottomRadius, const rgb_color& base, 2746 uint32 flags, uint32 borders) 2747 { 2748 if (!rect.IsValid() || !rect.Intersects(updateRect)) 2749 return; 2750 2751 // save the clipping constraints of the view 2752 view->PushState(); 2753 2754 // set clipping constraints to updateRect 2755 BRegion clipping(updateRect); 2756 view->ConstrainClippingRegion(&clipping); 2757 2758 // frame colors 2759 rgb_color frameLightColor = _FrameLightColor(base, flags); 2760 rgb_color frameShadowColor = _FrameShadowColor(base, flags); 2761 2762 // indicator background color 2763 rgb_color indicatorBase; 2764 if ((borders & B_LEFT_BORDER) != 0) 2765 indicatorBase = base; 2766 else { 2767 if ((flags & B_DISABLED) != 0) 2768 indicatorBase = tint_color(base, 1.05); 2769 else 2770 indicatorBase = tint_color(base, 1.12); 2771 } 2772 2773 // bevel colors 2774 rgb_color cornerColor = tint_color(indicatorBase, 0.85); 2775 rgb_color bevelColor1 = tint_color(indicatorBase, 0.3); 2776 rgb_color bevelColor2 = tint_color(indicatorBase, 0.5); 2777 rgb_color bevelColor3 = tint_color(indicatorBase, 1.03); 2778 2779 if ((flags & B_DISABLED) != 0) { 2780 cornerColor = tint_color(indicatorBase, 0.8); 2781 bevelColor1 = tint_color(indicatorBase, 0.7); 2782 bevelColor2 = tint_color(indicatorBase, 0.8); 2783 bevelColor3 = tint_color(indicatorBase, 1.01); 2784 } else { 2785 cornerColor = tint_color(indicatorBase, 0.85); 2786 bevelColor1 = tint_color(indicatorBase, 0.3); 2787 bevelColor2 = tint_color(indicatorBase, 0.5); 2788 bevelColor3 = tint_color(indicatorBase, 1.03); 2789 } 2790 2791 // surface top gradient 2792 BGradientLinear fillGradient; 2793 _MakeButtonGradient(fillGradient, rect, indicatorBase, flags); 2794 2795 // rounded corners 2796 2797 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0 2798 && leftTopRadius > 0) { 2799 // draw left top rounded corner 2800 BRect leftTopCorner(floorf(rect.left), floorf(rect.top), 2801 floorf(rect.left + leftTopRadius - 2.0), 2802 floorf(rect.top + leftTopRadius - 2.0)); 2803 clipping.Exclude(leftTopCorner); 2804 2805 BRegion cornerClipping(leftTopCorner); 2806 view->ConstrainClippingRegion(&cornerClipping); 2807 2808 BRect ellipseRect(leftTopCorner); 2809 ellipseRect.InsetBy(-1.0, -1.0); 2810 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 2811 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 2812 2813 // draw the frame (again) 2814 view->SetHighColor(frameLightColor); 2815 view->FillEllipse(ellipseRect); 2816 2817 // draw the bevel and background 2818 _DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect, 2819 bevelColor1, fillGradient); 2820 } 2821 2822 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0 2823 && rightTopRadius > 0) { 2824 // draw right top rounded corner 2825 BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0), 2826 floorf(rect.top), floorf(rect.right), 2827 floorf(rect.top + rightTopRadius - 2.0)); 2828 clipping.Exclude(rightTopCorner); 2829 2830 BRegion cornerClipping(rightTopCorner); 2831 view->ConstrainClippingRegion(&cornerClipping); 2832 2833 BRect ellipseRect(rightTopCorner); 2834 ellipseRect.InsetBy(-1.0, -1.0); 2835 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 2836 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 2837 2838 // draw the frame (again) 2839 if (frameLightColor == frameShadowColor) { 2840 view->SetHighColor(frameLightColor); 2841 view->FillEllipse(ellipseRect); 2842 } else { 2843 BGradientLinear gradient; 2844 gradient.AddColor(frameLightColor, 0); 2845 gradient.AddColor(frameShadowColor, 255); 2846 gradient.SetStart(rightTopCorner.LeftTop()); 2847 gradient.SetEnd(rightTopCorner.RightBottom()); 2848 view->FillEllipse(ellipseRect, gradient); 2849 } 2850 2851 // draw the bevel and background 2852 _DrawRoundCornerBackgroundRightTop(view, rightTopCorner, updateRect, 2853 bevelColor1, bevelColor3, fillGradient); 2854 } 2855 2856 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2857 && leftBottomRadius > 0) { 2858 // draw left bottom rounded corner 2859 BRect leftBottomCorner(floorf(rect.left), 2860 floorf(rect.bottom - leftBottomRadius + 2.0), 2861 floorf(rect.left + leftBottomRadius - 2.0), 2862 floorf(rect.bottom)); 2863 clipping.Exclude(leftBottomCorner); 2864 2865 BRegion cornerClipping(leftBottomCorner); 2866 view->ConstrainClippingRegion(&cornerClipping); 2867 2868 BRect ellipseRect(leftBottomCorner); 2869 ellipseRect.InsetBy(-1.0, -1.0); 2870 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 2871 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 2872 2873 // draw the frame (again) 2874 if (frameLightColor == frameShadowColor) { 2875 view->SetHighColor(frameLightColor); 2876 view->FillEllipse(ellipseRect); 2877 } else { 2878 BGradientLinear gradient; 2879 gradient.AddColor(frameLightColor, 0); 2880 gradient.AddColor(frameShadowColor, 255); 2881 gradient.SetStart(leftBottomCorner.LeftTop()); 2882 gradient.SetEnd(leftBottomCorner.RightBottom()); 2883 view->FillEllipse(ellipseRect, gradient); 2884 } 2885 2886 // draw the bevel and background 2887 _DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner, 2888 updateRect, bevelColor2, bevelColor3, fillGradient); 2889 } 2890 2891 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0 2892 && rightBottomRadius > 0) { 2893 // draw right bottom rounded corner 2894 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0), 2895 floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right), 2896 floorf(rect.bottom)); 2897 clipping.Exclude(rightBottomCorner); 2898 2899 BRegion cornerClipping(rightBottomCorner); 2900 view->ConstrainClippingRegion(&cornerClipping); 2901 2902 BRect ellipseRect(rightBottomCorner); 2903 ellipseRect.InsetBy(-1.0, -1.0); 2904 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 2905 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 2906 2907 // draw the frame (again) 2908 view->SetHighColor(frameShadowColor); 2909 view->FillEllipse(ellipseRect); 2910 2911 // draw the bevel and background 2912 _DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner, 2913 updateRect, bevelColor3, fillGradient); 2914 } 2915 2916 // clip out the corners 2917 view->ConstrainClippingRegion(&clipping); 2918 2919 // draw the bevel 2920 _DrawFrame(view, rect, 2921 bevelColor2, bevelColor1, 2922 bevelColor3, bevelColor3, 2923 cornerColor, cornerColor, 2924 borders); 2925 2926 // fill in the background 2927 view->FillRect(rect, fillGradient); 2928 2929 // restore the clipping constraints of the view 2930 view->PopState(); 2931 } 2932 2933 2934 void 2935 HaikuControlLook::_DrawRoundCornerLeftTop(BView* view, BRect& cornerRect, 2936 const BRect& updateRect, const rgb_color& background, 2937 const rgb_color& edgeColor, const rgb_color& frameColor, 2938 const rgb_color& bevelColor, const BGradientLinear& fillGradient) 2939 { 2940 _DrawRoundCornerFrameLeftTop(view, cornerRect, updateRect, 2941 background, edgeColor, frameColor); 2942 _DrawRoundCornerBackgroundLeftTop(view, cornerRect, updateRect, 2943 bevelColor, fillGradient); 2944 } 2945 2946 2947 void 2948 HaikuControlLook::_DrawRoundCornerFrameLeftTop(BView* view, BRect& cornerRect, 2949 const BRect& updateRect, const rgb_color& background, 2950 const rgb_color& edgeColor, const rgb_color& frameColor) 2951 { 2952 // constrain clipping region to corner 2953 BRegion clipping(cornerRect); 2954 view->ConstrainClippingRegion(&clipping); 2955 2956 // background 2957 view->SetHighColor(background); 2958 view->FillRect(cornerRect); 2959 2960 // outer edge 2961 BRect ellipseRect(cornerRect); 2962 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 2963 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 2964 2965 view->SetHighColor(edgeColor); 2966 view->FillEllipse(ellipseRect); 2967 2968 // frame 2969 ellipseRect.InsetBy(1, 1); 2970 cornerRect.left++; 2971 cornerRect.top++; 2972 view->SetHighColor(frameColor); 2973 view->FillEllipse(ellipseRect); 2974 2975 // prepare for bevel 2976 cornerRect.left++; 2977 cornerRect.top++; 2978 } 2979 2980 2981 void 2982 HaikuControlLook::_DrawRoundCornerBackgroundLeftTop(BView* view, BRect& cornerRect, 2983 const BRect& updateRect, const rgb_color& bevelColor, 2984 const BGradientLinear& fillGradient) 2985 { 2986 // constrain clipping region to corner 2987 BRegion clipping(cornerRect); 2988 view->ConstrainClippingRegion(&clipping); 2989 2990 BRect ellipseRect(cornerRect); 2991 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 2992 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 2993 2994 // bevel 2995 view->SetHighColor(bevelColor); 2996 view->FillEllipse(ellipseRect); 2997 2998 // gradient 2999 ellipseRect.InsetBy(1, 1); 3000 view->FillEllipse(ellipseRect, fillGradient); 3001 } 3002 3003 3004 void 3005 HaikuControlLook::_DrawRoundCornerRightTop(BView* view, BRect& cornerRect, 3006 const BRect& updateRect, const rgb_color& background, 3007 const rgb_color& edgeTopColor, const rgb_color& edgeRightColor, 3008 const rgb_color& frameTopColor, const rgb_color& frameRightColor, 3009 const rgb_color& bevelTopColor, const rgb_color& bevelRightColor, 3010 const BGradientLinear& fillGradient) 3011 { 3012 _DrawRoundCornerFrameRightTop(view, cornerRect, updateRect, 3013 background, edgeTopColor, edgeRightColor, frameTopColor, 3014 frameRightColor); 3015 _DrawRoundCornerBackgroundRightTop(view, cornerRect, updateRect, 3016 bevelTopColor, bevelRightColor, fillGradient); 3017 } 3018 3019 3020 void 3021 HaikuControlLook::_DrawRoundCornerFrameRightTop(BView* view, BRect& cornerRect, 3022 const BRect& updateRect, const rgb_color& background, 3023 const rgb_color& edgeTopColor, const rgb_color& edgeRightColor, 3024 const rgb_color& frameTopColor, const rgb_color& frameRightColor) 3025 { 3026 // constrain clipping region to corner 3027 BRegion clipping(cornerRect); 3028 view->ConstrainClippingRegion(&clipping); 3029 3030 // background 3031 view->SetHighColor(background); 3032 view->FillRect(cornerRect); 3033 3034 // outer edge 3035 BRect ellipseRect(cornerRect); 3036 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3037 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3038 3039 BGradientLinear gradient; 3040 gradient.AddColor(edgeTopColor, 0); 3041 gradient.AddColor(edgeRightColor, 255); 3042 gradient.SetStart(cornerRect.LeftTop()); 3043 gradient.SetEnd(cornerRect.RightBottom()); 3044 view->FillEllipse(ellipseRect, gradient); 3045 3046 // frame 3047 ellipseRect.InsetBy(1, 1); 3048 cornerRect.right--; 3049 cornerRect.top++; 3050 if (frameTopColor == frameRightColor) { 3051 view->SetHighColor(frameTopColor); 3052 view->FillEllipse(ellipseRect); 3053 } else { 3054 gradient.SetColor(0, frameTopColor); 3055 gradient.SetColor(1, frameRightColor); 3056 gradient.SetStart(cornerRect.LeftTop()); 3057 gradient.SetEnd(cornerRect.RightBottom()); 3058 view->FillEllipse(ellipseRect, gradient); 3059 } 3060 3061 // prepare for bevel 3062 cornerRect.right--; 3063 cornerRect.top++; 3064 } 3065 3066 3067 void 3068 HaikuControlLook::_DrawRoundCornerBackgroundRightTop(BView* view, BRect& cornerRect, 3069 const BRect& updateRect, const rgb_color& bevelTopColor, 3070 const rgb_color& bevelRightColor, const BGradientLinear& fillGradient) 3071 { 3072 // constrain clipping region to corner 3073 BRegion clipping(cornerRect); 3074 view->ConstrainClippingRegion(&clipping); 3075 3076 BRect ellipseRect(cornerRect); 3077 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3078 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2; 3079 3080 // bevel 3081 BGradientLinear gradient; 3082 gradient.AddColor(bevelTopColor, 0); 3083 gradient.AddColor(bevelRightColor, 255); 3084 gradient.SetStart(cornerRect.LeftTop()); 3085 gradient.SetEnd(cornerRect.RightBottom()); 3086 view->FillEllipse(ellipseRect, gradient); 3087 3088 // gradient 3089 ellipseRect.InsetBy(1, 1); 3090 view->FillEllipse(ellipseRect, fillGradient); 3091 } 3092 3093 3094 void 3095 HaikuControlLook::_DrawRoundCornerLeftBottom(BView* view, BRect& cornerRect, 3096 const BRect& updateRect, const rgb_color& background, 3097 const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor, 3098 const rgb_color& frameLeftColor, const rgb_color& frameBottomColor, 3099 const rgb_color& bevelLeftColor, const rgb_color& bevelBottomColor, 3100 const BGradientLinear& fillGradient) 3101 { 3102 _DrawRoundCornerFrameLeftBottom(view, cornerRect, updateRect, 3103 background, edgeLeftColor, edgeBottomColor, frameLeftColor, 3104 frameBottomColor); 3105 _DrawRoundCornerBackgroundLeftBottom(view, cornerRect, updateRect, 3106 bevelLeftColor, bevelBottomColor, fillGradient); 3107 } 3108 3109 3110 void 3111 HaikuControlLook::_DrawRoundCornerFrameLeftBottom(BView* view, BRect& cornerRect, 3112 const BRect& updateRect, const rgb_color& background, 3113 const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor, 3114 const rgb_color& frameLeftColor, const rgb_color& frameBottomColor) 3115 { 3116 // constrain clipping region to corner 3117 BRegion clipping(cornerRect); 3118 view->ConstrainClippingRegion(&clipping); 3119 3120 // background 3121 view->SetHighColor(background); 3122 view->FillRect(cornerRect); 3123 3124 // outer edge 3125 BRect ellipseRect(cornerRect); 3126 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3127 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3128 3129 BGradientLinear gradient; 3130 gradient.AddColor(edgeLeftColor, 0); 3131 gradient.AddColor(edgeBottomColor, 255); 3132 gradient.SetStart(cornerRect.LeftTop()); 3133 gradient.SetEnd(cornerRect.RightBottom()); 3134 view->FillEllipse(ellipseRect, gradient); 3135 3136 // frame 3137 ellipseRect.InsetBy(1, 1); 3138 cornerRect.left++; 3139 cornerRect.bottom--; 3140 if (frameLeftColor == frameBottomColor) { 3141 view->SetHighColor(frameLeftColor); 3142 view->FillEllipse(ellipseRect); 3143 } else { 3144 gradient.SetColor(0, frameLeftColor); 3145 gradient.SetColor(1, frameBottomColor); 3146 gradient.SetStart(cornerRect.LeftTop()); 3147 gradient.SetEnd(cornerRect.RightBottom()); 3148 view->FillEllipse(ellipseRect, gradient); 3149 } 3150 3151 // prepare for bevel 3152 cornerRect.left++; 3153 cornerRect.bottom--; 3154 } 3155 3156 3157 void 3158 HaikuControlLook::_DrawRoundCornerBackgroundLeftBottom(BView* view, BRect& cornerRect, 3159 const BRect& updateRect, const rgb_color& bevelLeftColor, 3160 const rgb_color& bevelBottomColor, const BGradientLinear& fillGradient) 3161 { 3162 // constrain clipping region to corner 3163 BRegion clipping(cornerRect); 3164 view->ConstrainClippingRegion(&clipping); 3165 3166 BRect ellipseRect(cornerRect); 3167 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2; 3168 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3169 3170 // bevel 3171 BGradientLinear gradient; 3172 gradient.AddColor(bevelLeftColor, 0); 3173 gradient.AddColor(bevelBottomColor, 255); 3174 gradient.SetStart(cornerRect.LeftTop()); 3175 gradient.SetEnd(cornerRect.RightBottom()); 3176 view->FillEllipse(ellipseRect, gradient); 3177 3178 // gradient 3179 ellipseRect.InsetBy(1, 1); 3180 view->FillEllipse(ellipseRect, fillGradient); 3181 } 3182 3183 3184 void 3185 HaikuControlLook::_DrawRoundCornerRightBottom(BView* view, BRect& cornerRect, 3186 const BRect& updateRect, const rgb_color& background, 3187 const rgb_color& edgeColor, const rgb_color& frameColor, 3188 const rgb_color& bevelColor, const BGradientLinear& fillGradient) 3189 { 3190 _DrawRoundCornerFrameRightBottom(view, cornerRect, updateRect, 3191 background, edgeColor, frameColor); 3192 _DrawRoundCornerBackgroundRightBottom(view, cornerRect, updateRect, 3193 bevelColor, fillGradient); 3194 } 3195 3196 3197 void 3198 HaikuControlLook::_DrawRoundCornerFrameRightBottom(BView* view, BRect& cornerRect, 3199 const BRect& updateRect, const rgb_color& background, 3200 const rgb_color& edgeColor, const rgb_color& frameColor) 3201 { 3202 // constrain clipping region to corner 3203 BRegion clipping(cornerRect); 3204 view->ConstrainClippingRegion(&clipping); 3205 3206 // background 3207 view->SetHighColor(background); 3208 view->FillRect(cornerRect); 3209 3210 // outer edge 3211 BRect ellipseRect(cornerRect); 3212 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3213 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3214 3215 view->SetHighColor(edgeColor); 3216 view->FillEllipse(ellipseRect); 3217 3218 // frame 3219 ellipseRect.InsetBy(1, 1); 3220 cornerRect.right--; 3221 cornerRect.bottom--; 3222 view->SetHighColor(frameColor); 3223 view->FillEllipse(ellipseRect); 3224 3225 // prepare for bevel 3226 cornerRect.right--; 3227 cornerRect.bottom--; 3228 } 3229 3230 3231 void 3232 HaikuControlLook::_DrawRoundCornerBackgroundRightBottom(BView* view, 3233 BRect& cornerRect, const BRect& updateRect, const rgb_color& bevelColor, 3234 const BGradientLinear& fillGradient) 3235 { 3236 // constrain clipping region to corner 3237 BRegion clipping(cornerRect); 3238 view->ConstrainClippingRegion(&clipping); 3239 3240 BRect ellipseRect(cornerRect); 3241 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2; 3242 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2; 3243 3244 // bevel 3245 view->SetHighColor(bevelColor); 3246 view->FillEllipse(ellipseRect); 3247 3248 // gradient 3249 ellipseRect.InsetBy(1, 1); 3250 view->FillEllipse(ellipseRect, fillGradient); 3251 } 3252 3253 3254 void 3255 HaikuControlLook::_DrawRoundBarCorner(BView* view, BRect& rect, 3256 const BRect& updateRect, 3257 const rgb_color& edgeLightColor, const rgb_color& edgeShadowColor, 3258 const rgb_color& frameLightColor, const rgb_color& frameShadowColor, 3259 const rgb_color& fillLightColor, const rgb_color& fillShadowColor, 3260 float leftInset, float topInset, float rightInset, float bottomInset, 3261 orientation orientation) 3262 { 3263 if (!rect.IsValid() || !rect.Intersects(updateRect)) 3264 return; 3265 3266 BGradientLinear gradient; 3267 gradient.AddColor(edgeShadowColor, 0); 3268 gradient.AddColor(edgeLightColor, 255); 3269 gradient.SetStart(rect.LeftTop()); 3270 if (orientation == B_HORIZONTAL) 3271 gradient.SetEnd(rect.LeftBottom()); 3272 else 3273 gradient.SetEnd(rect.RightTop()); 3274 3275 view->FillEllipse(rect, gradient); 3276 3277 rect.left += leftInset; 3278 rect.top += topInset; 3279 rect.right += rightInset; 3280 rect.bottom += bottomInset; 3281 3282 gradient.MakeEmpty(); 3283 gradient.AddColor(frameShadowColor, 0); 3284 gradient.AddColor(frameLightColor, 255); 3285 gradient.SetStart(rect.LeftTop()); 3286 if (orientation == B_HORIZONTAL) 3287 gradient.SetEnd(rect.LeftBottom()); 3288 else 3289 gradient.SetEnd(rect.RightTop()); 3290 3291 view->FillEllipse(rect, gradient); 3292 3293 rect.left += leftInset; 3294 rect.top += topInset; 3295 rect.right += rightInset; 3296 rect.bottom += bottomInset; 3297 3298 gradient.MakeEmpty(); 3299 gradient.AddColor(fillShadowColor, 0); 3300 gradient.AddColor(fillLightColor, 255); 3301 gradient.SetStart(rect.LeftTop()); 3302 if (orientation == B_HORIZONTAL) 3303 gradient.SetEnd(rect.LeftBottom()); 3304 else 3305 gradient.SetEnd(rect.RightTop()); 3306 3307 view->FillEllipse(rect, gradient); 3308 } 3309 3310 3311 rgb_color 3312 HaikuControlLook::_EdgeLightColor(const rgb_color& base, float contrast, 3313 float brightness, uint32 flags) 3314 { 3315 rgb_color edgeLightColor; 3316 3317 if ((flags & B_BLEND_FRAME) != 0) { 3318 uint8 alpha = uint8(20 * contrast); 3319 uint8 white = uint8(255 * brightness); 3320 3321 edgeLightColor = (rgb_color){ white, white, white, alpha }; 3322 } else { 3323 // colors 3324 float tintLight = kEdgeBevelLightTint; 3325 3326 if (contrast == 0.0) 3327 tintLight = B_NO_TINT; 3328 else if (contrast != 1.0) 3329 tintLight = B_NO_TINT + (tintLight - B_NO_TINT) * contrast; 3330 3331 edgeLightColor = tint_color(base, tintLight); 3332 3333 if (brightness < 1.0) { 3334 edgeLightColor.red = uint8(edgeLightColor.red * brightness); 3335 edgeLightColor.green = uint8(edgeLightColor.green * brightness); 3336 edgeLightColor.blue = uint8(edgeLightColor.blue * brightness); 3337 } 3338 } 3339 3340 return edgeLightColor; 3341 } 3342 3343 3344 rgb_color 3345 HaikuControlLook::_EdgeShadowColor(const rgb_color& base, float contrast, 3346 float brightness, uint32 flags) 3347 { 3348 rgb_color edgeShadowColor; 3349 3350 if ((flags & B_BLEND_FRAME) != 0) { 3351 uint8 alpha = uint8(20 * contrast); 3352 edgeShadowColor = (rgb_color){ 0, 0, 0, alpha }; 3353 } else { 3354 float tintShadow = kEdgeBevelShadowTint; 3355 3356 if (contrast == 0.0) 3357 tintShadow = B_NO_TINT; 3358 else if (contrast != 1.0) 3359 tintShadow = B_NO_TINT + (tintShadow - B_NO_TINT) * contrast; 3360 3361 edgeShadowColor = tint_color(base, tintShadow); 3362 3363 if (brightness < 1.0) { 3364 edgeShadowColor.red = uint8(edgeShadowColor.red * brightness); 3365 edgeShadowColor.green = uint8(edgeShadowColor.green * brightness); 3366 edgeShadowColor.blue = uint8(edgeShadowColor.blue * brightness); 3367 } 3368 } 3369 3370 return edgeShadowColor; 3371 } 3372 3373 3374 rgb_color 3375 HaikuControlLook::_FrameLightColor(const rgb_color& base, uint32 flags) 3376 { 3377 if ((flags & B_FOCUSED) != 0) 3378 return ui_color(B_KEYBOARD_NAVIGATION_COLOR); 3379 3380 if ((flags & B_ACTIVATED) != 0) 3381 return _FrameShadowColor(base, flags & ~B_ACTIVATED); 3382 3383 rgb_color frameLightColor; 3384 3385 if ((flags & B_DISABLED) != 0) { 3386 // TODO: B_BLEND_FRAME 3387 frameLightColor = tint_color(base, 1.145); 3388 3389 if ((flags & B_DEFAULT_BUTTON) != 0) 3390 frameLightColor = tint_color(frameLightColor, 1.14); 3391 } else { 3392 if ((flags & B_BLEND_FRAME) != 0) 3393 frameLightColor = (rgb_color){ 0, 0, 0, 75 }; 3394 else 3395 frameLightColor = tint_color(base, 1.33); 3396 3397 if ((flags & B_DEFAULT_BUTTON) != 0) 3398 frameLightColor = tint_color(frameLightColor, 1.35); 3399 } 3400 3401 return frameLightColor; 3402 } 3403 3404 3405 rgb_color 3406 HaikuControlLook::_FrameShadowColor(const rgb_color& base, uint32 flags) 3407 { 3408 if ((flags & B_FOCUSED) != 0) 3409 return ui_color(B_KEYBOARD_NAVIGATION_COLOR); 3410 3411 if ((flags & B_ACTIVATED) != 0) 3412 return _FrameLightColor(base, flags & ~B_ACTIVATED); 3413 3414 rgb_color frameShadowColor; 3415 3416 if ((flags & B_DISABLED) != 0) { 3417 // TODO: B_BLEND_FRAME 3418 frameShadowColor = tint_color(base, 1.24); 3419 3420 if ((flags & B_DEFAULT_BUTTON) != 0) { 3421 frameShadowColor = tint_color(base, 1.145); 3422 frameShadowColor = tint_color(frameShadowColor, 1.12); 3423 } 3424 } else { 3425 if ((flags & B_DEFAULT_BUTTON) != 0) { 3426 if ((flags & B_BLEND_FRAME) != 0) 3427 frameShadowColor = (rgb_color){ 0, 0, 0, 75 }; 3428 else 3429 frameShadowColor = tint_color(base, 1.33); 3430 3431 frameShadowColor = tint_color(frameShadowColor, 1.5); 3432 } else { 3433 if ((flags & B_BLEND_FRAME) != 0) 3434 frameShadowColor = (rgb_color){ 0, 0, 0, 95 }; 3435 else 3436 frameShadowColor = tint_color(base, 1.47); 3437 } 3438 } 3439 3440 return frameShadowColor; 3441 } 3442 3443 3444 rgb_color 3445 HaikuControlLook::_BevelLightColor(const rgb_color& base, uint32 flags) 3446 { 3447 rgb_color bevelLightColor = tint_color(base, 0.2); 3448 3449 if ((flags & B_DISABLED) != 0) 3450 bevelLightColor = tint_color(base, B_LIGHTEN_1_TINT); 3451 3452 if ((flags & B_ACTIVATED) != 0) 3453 bevelLightColor = tint_color(base, B_DARKEN_1_TINT); 3454 3455 return bevelLightColor; 3456 } 3457 3458 3459 rgb_color 3460 HaikuControlLook::_BevelShadowColor(const rgb_color& base, uint32 flags) 3461 { 3462 rgb_color bevelShadowColor = tint_color(base, 1.08); 3463 3464 if ((flags & B_DISABLED) != 0) 3465 bevelShadowColor = base; 3466 3467 if ((flags & B_ACTIVATED) != 0) 3468 bevelShadowColor = tint_color(base, B_DARKEN_1_TINT); 3469 3470 return bevelShadowColor; 3471 } 3472 3473 3474 void 3475 HaikuControlLook::_FillGradient(BView* view, const BRect& rect, 3476 const rgb_color& base, float topTint, float bottomTint, 3477 orientation orientation) 3478 { 3479 BGradientLinear gradient; 3480 _MakeGradient(gradient, rect, base, topTint, bottomTint, orientation); 3481 view->FillRect(rect, gradient); 3482 } 3483 3484 3485 void 3486 HaikuControlLook::_FillGlossyGradient(BView* view, const BRect& rect, 3487 const rgb_color& base, float topTint, float middle1Tint, 3488 float middle2Tint, float bottomTint, orientation orientation) 3489 { 3490 BGradientLinear gradient; 3491 _MakeGlossyGradient(gradient, rect, base, topTint, middle1Tint, 3492 middle2Tint, bottomTint, orientation); 3493 view->FillRect(rect, gradient); 3494 } 3495 3496 3497 void 3498 HaikuControlLook::_MakeGradient(BGradientLinear& gradient, const BRect& rect, 3499 const rgb_color& base, float topTint, float bottomTint, 3500 orientation orientation) const 3501 { 3502 gradient.AddColor(tint_color(base, topTint), 0); 3503 gradient.AddColor(tint_color(base, bottomTint), 255); 3504 gradient.SetStart(rect.LeftTop()); 3505 if (orientation == B_HORIZONTAL) 3506 gradient.SetEnd(rect.LeftBottom()); 3507 else 3508 gradient.SetEnd(rect.RightTop()); 3509 } 3510 3511 3512 void 3513 HaikuControlLook::_MakeGlossyGradient(BGradientLinear& gradient, const BRect& rect, 3514 const rgb_color& base, float topTint, float middle1Tint, 3515 float middle2Tint, float bottomTint, 3516 orientation orientation) const 3517 { 3518 gradient.AddColor(tint_color(base, topTint), 0); 3519 gradient.AddColor(tint_color(base, middle1Tint), 132); 3520 gradient.AddColor(tint_color(base, middle2Tint), 136); 3521 gradient.AddColor(tint_color(base, bottomTint), 255); 3522 gradient.SetStart(rect.LeftTop()); 3523 if (orientation == B_HORIZONTAL) 3524 gradient.SetEnd(rect.LeftBottom()); 3525 else 3526 gradient.SetEnd(rect.RightTop()); 3527 } 3528 3529 3530 void 3531 HaikuControlLook::_MakeButtonGradient(BGradientLinear& gradient, BRect& rect, 3532 const rgb_color& base, uint32 flags, orientation orientation) const 3533 { 3534 float topTint = 0.49; 3535 float middleTint1 = 0.62; 3536 float middleTint2 = 0.76; 3537 float bottomTint = 0.90; 3538 3539 if ((flags & B_ACTIVATED) != 0) { 3540 topTint = 1.11; 3541 bottomTint = 1.08; 3542 } 3543 3544 if ((flags & B_DISABLED) != 0) { 3545 topTint = (topTint + B_NO_TINT) / 2; 3546 middleTint1 = (middleTint1 + B_NO_TINT) / 2; 3547 middleTint2 = (middleTint2 + B_NO_TINT) / 2; 3548 bottomTint = (bottomTint + B_NO_TINT) / 2; 3549 } else if ((flags & B_HOVER) != 0) { 3550 topTint *= kHoverTintFactor; 3551 middleTint1 *= kHoverTintFactor; 3552 middleTint2 *= kHoverTintFactor; 3553 bottomTint *= kHoverTintFactor; 3554 } 3555 3556 if ((flags & B_ACTIVATED) != 0) { 3557 _MakeGradient(gradient, rect, base, topTint, bottomTint, orientation); 3558 } else { 3559 _MakeGlossyGradient(gradient, rect, base, topTint, middleTint1, 3560 middleTint2, bottomTint, orientation); 3561 } 3562 } 3563 3564 3565 3566 bool 3567 HaikuControlLook::_RadioButtonAndCheckBoxMarkColor(const rgb_color& base, 3568 rgb_color& color, uint32 flags) const 3569 { 3570 if ((flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED | B_CLICKED)) == 0) { 3571 // no mark to be drawn at all 3572 return false; 3573 } 3574 3575 color = ui_color(B_CONTROL_MARK_COLOR); 3576 3577 float mix = 1.0; 3578 3579 if ((flags & B_DISABLED) != 0) { 3580 // activated, but disabled 3581 mix = 0.4; 3582 } else if ((flags & B_CLICKED) != 0) { 3583 if ((flags & B_ACTIVATED) != 0) { 3584 // losing activation 3585 mix = 0.7; 3586 } else { 3587 // becoming activated (or losing partial activation) 3588 mix = 0.3; 3589 } 3590 } else if ((flags & B_PARTIALLY_ACTIVATED) != 0) { 3591 // partially activated 3592 mix = 0.5; 3593 } else { 3594 // simply activated 3595 } 3596 3597 color.red = uint8(color.red * mix + base.red * (1.0 - mix)); 3598 color.green = uint8(color.green * mix + base.green * (1.0 - mix)); 3599 color.blue = uint8(color.blue * mix + base.blue * (1.0 - mix)); 3600 3601 return true; 3602 } 3603 3604 3605 } // namespace BPrivate 3606