1 /* 2 * Copyright 2001-2005, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marc Flerackers (mflerackers@androme.be) 7 * Mike Wilber 8 * Stefano Ceccherini (burton666@libero.it) 9 * Ivan Tonizza 10 * Stephan Aßmus, <superstippi@gmx.de> 11 */ 12 13 14 #include <Button.h> 15 16 #include <Font.h> 17 #include <LayoutUtils.h> 18 #include <String.h> 19 #include <Window.h> 20 21 22 BButton::BButton(BRect frame, const char *name, const char *label, BMessage *message, 23 uint32 resizingMode, uint32 flags) 24 : BControl(frame, name, label, message, resizingMode, 25 flags | B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), 26 fPreferredSize(-1, -1), 27 fDrawAsDefault(false) 28 { 29 // Resize to minimum height if needed 30 font_height fh; 31 GetFontHeight(&fh); 32 float minHeight = 12.0f + (float)ceil(fh.ascent + fh.descent); 33 if (Bounds().Height() < minHeight) 34 ResizeTo(Bounds().Width(), minHeight); 35 } 36 37 38 BButton::BButton(const char* name, const char* label, BMessage *message, 39 uint32 flags) 40 : BControl(name, label, message, 41 flags | B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), 42 fPreferredSize(-1, -1), 43 fDrawAsDefault(false) 44 { 45 } 46 47 48 BButton::BButton(const char* label, BMessage *message) 49 : BControl(NULL, label, message, 50 B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE), 51 fPreferredSize(-1, -1), 52 fDrawAsDefault(false) 53 { 54 } 55 56 57 BButton::~BButton() 58 { 59 } 60 61 62 BButton::BButton(BMessage *archive) 63 : BControl(archive), 64 fPreferredSize(-1, -1) 65 { 66 if (archive->FindBool("_default", &fDrawAsDefault) != B_OK) 67 fDrawAsDefault = false; 68 // NOTE: Default button state will be synchronized with the window 69 // in AttachedToWindow(). 70 } 71 72 73 BArchivable * 74 BButton::Instantiate(BMessage *archive) 75 { 76 if (validate_instantiation(archive, "BButton")) 77 return new BButton(archive); 78 79 return NULL; 80 } 81 82 83 status_t 84 BButton::Archive(BMessage* archive, bool deep) const 85 { 86 status_t err = BControl::Archive(archive, deep); 87 88 if (err != B_OK) 89 return err; 90 91 if (IsDefault()) 92 err = archive->AddBool("_default", true); 93 94 return err; 95 } 96 97 98 void 99 BButton::Draw(BRect updateRect) 100 { 101 font_height fh; 102 GetFontHeight(&fh); 103 104 const BRect bounds = Bounds(); 105 BRect rect = bounds; 106 107 const bool enabled = IsEnabled(); 108 const bool pushed = Value() == B_CONTROL_ON; 109 #if 0 110 // Default indicator 111 if (IsDefault()) 112 rect = DrawDefault(rect, enabled); 113 else 114 rect.InsetBy(1.0f, 1.0f); 115 116 BRect fillArea = rect; 117 fillArea.InsetBy(3.0f, 3.0f); 118 119 BString text = Label(); 120 121 #if 1 122 // Label truncation 123 BFont font; 124 GetFont(&font); 125 font.TruncateString(&text, B_TRUNCATE_END, fillArea.Width()); 126 #endif 127 128 // Label position 129 const float stringWidth = StringWidth(text.String()); 130 const float x = (bounds.right - stringWidth) / 2.0f; 131 const float labelY = bounds.top 132 + ((bounds.Height() - fh.ascent - fh.descent) / 2.0f) 133 + fh.ascent + 1.0f; 134 const float focusLineY = labelY + fh.descent; 135 136 /* speed trick: 137 if the focus changes but the button is not pressed then we can 138 redraw only the focus line, 139 if the focus changes and the button is pressed invert the internal rect 140 this block takes care of all the focus changes 141 */ 142 if (IsFocusChanging()) { 143 if (pushed) { 144 rect.InsetBy(2.0, 2.0); 145 InvertRect(rect); 146 } else 147 DrawFocusLine(x, focusLineY, stringWidth, IsFocus() && Window()->IsActive()); 148 149 return; 150 } 151 152 // Colors 153 const rgb_color panelBgColor = ui_color(B_PANEL_BACKGROUND_COLOR); 154 const rgb_color buttonBgColor=tint_color(panelBgColor, B_LIGHTEN_1_TINT); 155 const rgb_color maxLightColor=tint_color(panelBgColor, B_LIGHTEN_MAX_TINT); 156 const rgb_color maxShadowColor=tint_color(panelBgColor, B_DARKEN_MAX_TINT); 157 const rgb_color darkBorderColor = tint_color(panelBgColor, 158 enabled ? B_DARKEN_4_TINT : B_DARKEN_2_TINT); 159 const rgb_color firstBevelColor = enabled ? tint_color(panelBgColor, B_DARKEN_2_TINT) 160 : panelBgColor; 161 const rgb_color cornerColor = IsDefault() ? firstBevelColor : panelBgColor; 162 163 // Fill the button area 164 SetHighColor(buttonBgColor); 165 FillRect(fillArea); 166 167 // external border 168 SetHighColor(darkBorderColor); 169 StrokeRect(rect); 170 171 BeginLineArray(14); 172 173 // Corners 174 AddLine(rect.LeftTop(), rect.LeftTop(), cornerColor); 175 AddLine(rect.LeftBottom(), rect.LeftBottom(), cornerColor); 176 AddLine(rect.RightTop(), rect.RightTop(), cornerColor); 177 AddLine(rect.RightBottom(), rect.RightBottom(), cornerColor); 178 179 rect.InsetBy(1.0f,1.0f); 180 181 // Shadow 182 AddLine(rect.LeftBottom(), rect.RightBottom(), firstBevelColor); 183 AddLine(rect.RightBottom(), rect.RightTop(), firstBevelColor); 184 // Light 185 AddLine(rect.LeftTop(), rect.LeftBottom(),buttonBgColor); 186 AddLine(rect.LeftTop(), rect.RightTop(), buttonBgColor); 187 188 rect.InsetBy(1.0f, 1.0f); 189 190 // Shadow 191 AddLine(rect.LeftBottom(), rect.RightBottom(), panelBgColor); 192 AddLine(rect.RightBottom(), rect.RightTop(), panelBgColor); 193 // Light 194 AddLine(rect.LeftTop(), rect.LeftBottom(),maxLightColor); 195 AddLine(rect.LeftTop(), rect.RightTop(), maxLightColor); 196 197 rect.InsetBy(1.0f,1.0f); 198 199 // Light 200 AddLine(rect.LeftTop(), rect.LeftBottom(),maxLightColor); 201 AddLine(rect.LeftTop(), rect.RightTop(), maxLightColor); 202 203 EndLineArray(); 204 205 // Invert if clicked 206 if (enabled && pushed) { 207 rect.InsetBy(-2.0f, -2.0f); 208 InvertRect(rect); 209 } 210 211 // Label color 212 if (enabled) { 213 if (pushed) { 214 SetHighColor(maxLightColor); 215 SetLowColor(maxShadowColor); 216 } else { 217 SetHighColor(maxShadowColor); 218 SetLowColor(tint_color(panelBgColor, B_LIGHTEN_2_TINT)); 219 } 220 } else { 221 SetHighColor(tint_color(panelBgColor, B_DISABLED_LABEL_TINT)); 222 SetLowColor(tint_color(panelBgColor, B_LIGHTEN_2_TINT)); 223 } 224 225 // Draw the label 226 DrawString(text.String(), BPoint(x, labelY)); 227 228 // Focus line 229 if (enabled && IsFocus() && Window()->IsActive() && !pushed) 230 DrawFocusLine(x,focusLineY,stringWidth,true); 231 #else 232 // Default indicator 233 if (IsDefault()) 234 rect = DrawDefault(rect, enabled); 235 236 BRect fillArea = rect; 237 fillArea.InsetBy(3.0, 3.0); 238 239 BString text = Label(); 240 241 #if 1 242 // Label truncation 243 BFont font; 244 GetFont(&font); 245 font.TruncateString(&text, B_TRUNCATE_END, fillArea.Width() - 4); 246 #endif 247 248 // Label position 249 const float stringWidth = StringWidth(text.String()); 250 const float x = (rect.right - stringWidth) / 2.0; 251 const float labelY = bounds.top 252 + ((bounds.Height() - fh.ascent - fh.descent) / 2.0) 253 + fh.ascent + 1.0; 254 const float focusLineY = labelY + fh.descent; 255 256 /* speed trick: 257 if the focus changes but the button is not pressed then we can 258 redraw only the focus line, 259 if the focus changes and the button is pressed invert the internal rect 260 this block takes care of all the focus changes 261 */ 262 if (IsFocusChanging()) { 263 if (pushed) { 264 rect.InsetBy(2.0, 2.0); 265 InvertRect(rect); 266 } else { 267 DrawFocusLine(x, focusLineY, stringWidth, IsFocus() 268 && Window()->IsActive()); 269 } 270 271 return; 272 } 273 274 // colors 275 rgb_color panelBgColor = ui_color(B_PANEL_BACKGROUND_COLOR); 276 rgb_color buttonBgColor = tint_color(panelBgColor, B_LIGHTEN_1_TINT); 277 rgb_color lightColor; 278 rgb_color maxLightColor; 279 rgb_color maxShadowColor = tint_color(panelBgColor, B_DARKEN_MAX_TINT); 280 281 rgb_color dark1BorderColor; 282 rgb_color dark2BorderColor; 283 284 rgb_color bevelColor1; 285 rgb_color bevelColor2; 286 rgb_color bevelColorRBCorner; 287 288 rgb_color borderBevelShadow; 289 rgb_color borderBevelLight; 290 291 if (enabled) { 292 lightColor = tint_color(panelBgColor, B_LIGHTEN_2_TINT); 293 maxLightColor = tint_color(panelBgColor, B_LIGHTEN_MAX_TINT); 294 295 dark1BorderColor = tint_color(panelBgColor, B_DARKEN_3_TINT); 296 dark2BorderColor = tint_color(panelBgColor, B_DARKEN_4_TINT); 297 298 bevelColor1 = tint_color(panelBgColor, B_DARKEN_2_TINT); 299 bevelColor2 = panelBgColor; 300 301 if (IsDefault()) { 302 borderBevelShadow = tint_color(dark1BorderColor, 303 (B_NO_TINT + B_DARKEN_1_TINT) / 2); 304 borderBevelLight = tint_color(dark1BorderColor, B_LIGHTEN_1_TINT); 305 306 borderBevelLight.red = (borderBevelLight.red + panelBgColor.red) 307 / 2; 308 borderBevelLight.green = (borderBevelLight.green 309 + panelBgColor.green) / 2; 310 borderBevelLight.blue = (borderBevelLight.blue 311 + panelBgColor.blue) / 2; 312 313 dark1BorderColor = tint_color(dark1BorderColor, B_DARKEN_3_TINT); 314 dark2BorderColor = tint_color(dark1BorderColor, B_DARKEN_4_TINT); 315 316 bevelColorRBCorner = borderBevelShadow; 317 } else { 318 borderBevelShadow = tint_color(panelBgColor, 319 (B_NO_TINT + B_DARKEN_1_TINT) / 2); 320 borderBevelLight = buttonBgColor; 321 322 bevelColorRBCorner = dark1BorderColor; 323 } 324 } else { 325 lightColor = tint_color(panelBgColor, B_LIGHTEN_2_TINT); 326 maxLightColor = tint_color(panelBgColor, B_LIGHTEN_1_TINT); 327 328 dark1BorderColor = tint_color(panelBgColor, B_DARKEN_1_TINT); 329 dark2BorderColor = tint_color(panelBgColor, B_DARKEN_2_TINT); 330 331 bevelColor1 = panelBgColor; 332 bevelColor2 = buttonBgColor; 333 334 if (IsDefault()) { 335 borderBevelShadow = dark1BorderColor; 336 borderBevelLight = panelBgColor; 337 dark1BorderColor = tint_color(dark1BorderColor, B_DARKEN_1_TINT); 338 dark2BorderColor = tint_color(dark1BorderColor, 1.16); 339 340 } else { 341 borderBevelShadow = panelBgColor; 342 borderBevelLight = panelBgColor; 343 } 344 345 bevelColorRBCorner = tint_color(panelBgColor, 1.08);; 346 } 347 348 // fill the button area 349 SetHighColor(buttonBgColor); 350 FillRect(fillArea); 351 352 BeginLineArray(22); 353 // bevel around external border 354 AddLine(BPoint(rect.left, rect.bottom), 355 BPoint(rect.left, rect.top), borderBevelShadow); 356 AddLine(BPoint(rect.left + 1, rect.top), 357 BPoint(rect.right, rect.top), borderBevelShadow); 358 359 AddLine(BPoint(rect.right, rect.top + 1), 360 BPoint(rect.right, rect.bottom), borderBevelLight); 361 AddLine(BPoint(rect.left + 1, rect.bottom), 362 BPoint(rect.right - 1, rect.bottom), borderBevelLight); 363 364 rect.InsetBy(1.0, 1.0); 365 366 // external border 367 AddLine(BPoint(rect.left, rect.bottom), 368 BPoint(rect.left, rect.top), dark1BorderColor); 369 AddLine(BPoint(rect.left + 1, rect.top), 370 BPoint(rect.right, rect.top), dark1BorderColor); 371 AddLine(BPoint(rect.right, rect.top + 1), 372 BPoint(rect.right, rect.bottom), dark2BorderColor); 373 AddLine(BPoint(rect.right - 1, rect.bottom), 374 BPoint(rect.left + 1, rect.bottom), dark2BorderColor); 375 376 rect.InsetBy(1.0, 1.0); 377 378 // Light 379 AddLine(BPoint(rect.left, rect.top), 380 BPoint(rect.left, rect.top), buttonBgColor); 381 AddLine(BPoint(rect.left, rect.top + 1), 382 BPoint(rect.left, rect.bottom - 1), lightColor); 383 AddLine(BPoint(rect.left, rect.bottom), 384 BPoint(rect.left, rect.bottom), bevelColor2); 385 AddLine(BPoint(rect.left + 1, rect.top), 386 BPoint(rect.right - 1, rect.top), lightColor); 387 AddLine(BPoint(rect.right, rect.top), 388 BPoint(rect.right, rect.top), bevelColor2); 389 // Shadow 390 AddLine(BPoint(rect.left + 1, rect.bottom), 391 BPoint(rect.right - 1, rect.bottom), bevelColor1); 392 AddLine(BPoint(rect.right, rect.bottom), 393 BPoint(rect.right, rect.bottom), bevelColorRBCorner); 394 AddLine(BPoint(rect.right, rect.bottom - 1), 395 BPoint(rect.right, rect.top + 1), bevelColor1); 396 397 rect.InsetBy(1.0, 1.0); 398 399 // Light 400 AddLine(BPoint(rect.left, rect.top), 401 BPoint(rect.left, rect.bottom - 1), maxLightColor); 402 AddLine(BPoint(rect.left, rect.bottom), 403 BPoint(rect.left, rect.bottom), buttonBgColor); 404 AddLine(BPoint(rect.left + 1, rect.top), 405 BPoint(rect.right - 1, rect.top), maxLightColor); 406 AddLine(BPoint(rect.right, rect.top), 407 BPoint(rect.right, rect.top), buttonBgColor); 408 // Shadow 409 AddLine(BPoint(rect.left + 1, rect.bottom), 410 BPoint(rect.right, rect.bottom), bevelColor2); 411 AddLine(BPoint(rect.right, rect.bottom - 1), 412 BPoint(rect.right, rect.top + 1), bevelColor2); 413 414 rect.InsetBy(1.0,1.0); 415 416 EndLineArray(); 417 418 // Invert if clicked 419 if (enabled && pushed) { 420 rect.InsetBy(-2.0, -2.0); 421 InvertRect(rect); 422 } 423 424 // Label color 425 if (enabled) { 426 if (pushed) { 427 SetHighColor(maxLightColor); 428 SetLowColor(255 - buttonBgColor.red, 429 255 - buttonBgColor.green, 430 255 - buttonBgColor.blue); 431 } else { 432 SetHighColor(ui_color(B_CONTROL_TEXT_COLOR)); 433 SetLowColor(buttonBgColor); 434 } 435 } else { 436 SetHighColor(tint_color(panelBgColor, B_DISABLED_LABEL_TINT)); 437 SetLowColor(buttonBgColor); 438 } 439 440 // Draw the label 441 DrawString(text.String(), BPoint(x, labelY)); 442 443 // Focus line 444 if (enabled && IsFocus() && Window()->IsActive() && !pushed) 445 DrawFocusLine(x, focusLineY, stringWidth, true); 446 #endif 447 } 448 449 450 void 451 BButton::MouseDown(BPoint point) 452 { 453 if (!IsEnabled()) 454 return; 455 456 SetValue(B_CONTROL_ON); 457 458 if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) { 459 SetTracking(true); 460 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); 461 } else { 462 BRect bounds = Bounds(); 463 uint32 buttons; 464 465 do { 466 Window()->UpdateIfNeeded(); 467 snooze(40000); 468 469 GetMouse(&point, &buttons, true); 470 471 bool inside = bounds.Contains(point); 472 473 if ((Value() == B_CONTROL_ON) != inside) 474 SetValue(inside ? B_CONTROL_ON : B_CONTROL_OFF); 475 } while (buttons != 0); 476 477 if (Value() == B_CONTROL_ON) 478 Invoke(); 479 } 480 } 481 482 483 void 484 BButton::AttachedToWindow() 485 { 486 BControl::AttachedToWindow(); 487 // low color will now be the parents view color 488 489 if (IsDefault()) 490 Window()->SetDefaultButton(this); 491 492 SetViewColor(B_TRANSPARENT_COLOR); 493 } 494 495 496 void 497 BButton::KeyDown(const char *bytes, int32 numBytes) 498 { 499 if (*bytes == B_ENTER || *bytes == B_SPACE) { 500 if (!IsEnabled()) 501 return; 502 503 SetValue(B_CONTROL_ON); 504 505 // make sure the user saw that 506 Window()->UpdateIfNeeded(); 507 snooze(25000); 508 509 Invoke(); 510 511 } else 512 BControl::KeyDown(bytes, numBytes); 513 } 514 515 516 void 517 BButton::MakeDefault(bool flag) 518 { 519 BButton *oldDefault = NULL; 520 BWindow *window = Window(); 521 522 if (window) 523 oldDefault = window->DefaultButton(); 524 525 if (flag) { 526 if (fDrawAsDefault && oldDefault == this) 527 return; 528 529 if (!fDrawAsDefault) { 530 fDrawAsDefault = true; 531 532 ResizeBy(6.0f, 6.0f); 533 MoveBy(-3.0f, -3.0f); 534 } 535 536 if (window && oldDefault != this) 537 window->SetDefaultButton(this); 538 } else { 539 if (!fDrawAsDefault) 540 return; 541 542 fDrawAsDefault = false; 543 544 ResizeBy(-6.0f, -6.0f); 545 MoveBy(3.0f, 3.0f); 546 547 if (window && oldDefault == this) 548 window->SetDefaultButton(NULL); 549 } 550 } 551 552 553 void 554 BButton::SetLabel(const char *string) 555 { 556 BControl::SetLabel(string); 557 } 558 559 560 bool 561 BButton::IsDefault() const 562 { 563 return fDrawAsDefault; 564 } 565 566 567 void 568 BButton::MessageReceived(BMessage *message) 569 { 570 BControl::MessageReceived(message); 571 } 572 573 574 void 575 BButton::WindowActivated(bool active) 576 { 577 BControl::WindowActivated(active); 578 } 579 580 581 void 582 BButton::MouseMoved(BPoint point, uint32 transit, const BMessage *message) 583 { 584 if (!IsTracking()) 585 return; 586 587 bool inside = Bounds().Contains(point); 588 589 if ((Value() == B_CONTROL_ON) != inside) 590 SetValue(inside ? B_CONTROL_ON : B_CONTROL_OFF); 591 } 592 593 594 void 595 BButton::MouseUp(BPoint point) 596 { 597 if (!IsTracking()) 598 return; 599 600 if (Bounds().Contains(point)) 601 Invoke(); 602 603 SetTracking(false); 604 } 605 606 607 void 608 BButton::DetachedFromWindow() 609 { 610 BControl::DetachedFromWindow(); 611 } 612 613 614 void 615 BButton::SetValue(int32 value) 616 { 617 if (value != Value()) 618 BControl::SetValue(value); 619 } 620 621 622 void 623 BButton::GetPreferredSize(float *_width, float *_height) 624 { 625 _ValidatePreferredSize(); 626 627 if (_width) 628 *_width = fPreferredSize.width; 629 630 if (_height) 631 *_height = fPreferredSize.height; 632 } 633 634 635 void 636 BButton::ResizeToPreferred() 637 { 638 BControl::ResizeToPreferred(); 639 } 640 641 642 status_t 643 BButton::Invoke(BMessage *message) 644 { 645 Sync(); 646 snooze(50000); 647 648 status_t err = BControl::Invoke(message); 649 650 SetValue(B_CONTROL_OFF); 651 652 return err; 653 } 654 655 656 void 657 BButton::FrameMoved(BPoint newLocation) 658 { 659 BControl::FrameMoved(newLocation); 660 } 661 662 663 void 664 BButton::FrameResized(float width, float height) 665 { 666 BControl::FrameResized(width, height); 667 } 668 669 670 void 671 BButton::MakeFocus(bool focused) 672 { 673 BControl::MakeFocus(focused); 674 } 675 676 677 void 678 BButton::AllAttached() 679 { 680 BControl::AllAttached(); 681 } 682 683 684 void 685 BButton::AllDetached() 686 { 687 BControl::AllDetached(); 688 } 689 690 691 BHandler * 692 BButton::ResolveSpecifier(BMessage *message, int32 index, 693 BMessage *specifier, int32 what, 694 const char *property) 695 { 696 return BControl::ResolveSpecifier(message, index, specifier, what, property); 697 } 698 699 700 status_t 701 BButton::GetSupportedSuites(BMessage *message) 702 { 703 return BControl::GetSupportedSuites(message); 704 } 705 706 707 status_t 708 BButton::Perform(perform_code d, void *arg) 709 { 710 return BControl::Perform(d, arg); 711 } 712 713 714 void 715 BButton::InvalidateLayout(bool descendants) 716 { 717 // invalidate cached preferred size 718 fPreferredSize.Set(-1, -1); 719 720 BControl::InvalidateLayout(descendants); 721 } 722 723 724 BSize 725 BButton::MinSize() 726 { 727 return BLayoutUtils::ComposeSize(ExplicitMinSize(), 728 _ValidatePreferredSize()); 729 } 730 731 732 BSize 733 BButton::MaxSize() 734 { 735 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), 736 _ValidatePreferredSize()); 737 } 738 739 740 BSize 741 BButton::PreferredSize() 742 { 743 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), 744 _ValidatePreferredSize()); 745 } 746 747 748 void BButton::_ReservedButton1() {} 749 void BButton::_ReservedButton2() {} 750 void BButton::_ReservedButton3() {} 751 752 753 BButton & 754 BButton::operator=(const BButton &) 755 { 756 return *this; 757 } 758 759 760 BRect 761 BButton::DrawDefault(BRect bounds, bool enabled) 762 { 763 #if 0 764 rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR), 765 lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT), 766 darken1 = tint_color(no_tint, B_DARKEN_1_TINT); 767 768 rgb_color borderColor; 769 if (enabled) 770 borderColor = tint_color(no_tint, B_DARKEN_4_TINT); 771 else 772 borderColor = darken1; 773 774 // Dark border 775 BeginLineArray(4); 776 AddLine(BPoint(bounds.left, bounds.bottom - 1.0f), 777 BPoint(bounds.left, bounds.top + 1.0f), borderColor); 778 AddLine(BPoint(bounds.left + 1.0f, bounds.top), 779 BPoint(bounds.right - 1.0f, bounds.top), borderColor); 780 AddLine(BPoint(bounds.right, bounds.top + 1.0f), 781 BPoint(bounds.right, bounds.bottom - 1.0f), borderColor); 782 AddLine(BPoint(bounds.left + 1.0f, bounds.bottom), 783 BPoint(bounds.right - 1.0f, bounds.bottom), borderColor); 784 EndLineArray(); 785 786 if (enabled) { 787 // Bevel 788 bounds.InsetBy(1.0f, 1.0f); 789 SetHighColor(darken1); 790 StrokeRect(bounds); 791 } 792 793 bounds.InsetBy(1.0f, 1.0f); 794 795 // Filling 796 float inset = enabled? 2.0f : 3.0f; 797 SetHighColor(lighten1); 798 799 FillRect(BRect(bounds.left, bounds.top, 800 bounds.right, bounds.top+inset-1.0f)); 801 FillRect(BRect(bounds.left, bounds.bottom-inset+1.0f, 802 bounds.right, bounds.bottom)); 803 FillRect(BRect(bounds.left, bounds.top+inset-1.0f, 804 bounds.left+inset-1.0f, bounds.bottom-inset+1.0f)); 805 FillRect(BRect(bounds.right-inset+1.0f, bounds.top+inset-1.0f, 806 bounds.right, bounds.bottom-inset+1.0f)); 807 808 bounds.InsetBy(inset,inset); 809 810 return bounds; 811 #else 812 rgb_color low = LowColor(); 813 rgb_color focusColor = tint_color(low, enabled ? (B_DARKEN_1_TINT + B_DARKEN_2_TINT) / 2 814 : (B_NO_TINT + B_DARKEN_1_TINT) / 2); 815 816 SetHighColor(focusColor); 817 818 StrokeRect(bounds, B_SOLID_LOW); 819 bounds.InsetBy(1.0, 1.0); 820 StrokeRect(bounds); 821 bounds.InsetBy(1.0, 1.0); 822 StrokeRect(bounds); 823 bounds.InsetBy(1.0, 1.0); 824 825 return bounds; 826 #endif 827 } 828 829 830 status_t 831 BButton::Execute() 832 { 833 if (!IsEnabled()) 834 return B_ERROR; 835 836 SetValue(B_CONTROL_ON); 837 return Invoke(); 838 } 839 840 841 void 842 BButton::DrawFocusLine(float x, float y, float width, bool visible) 843 { 844 if (visible) 845 SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); 846 else { 847 SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 848 B_LIGHTEN_1_TINT)); 849 } 850 851 // Blue Line 852 StrokeLine(BPoint(x, y), BPoint(x + width, y)); 853 854 if (visible) 855 SetHighColor(255, 255, 255); 856 // White Line 857 StrokeLine(BPoint(x, y + 1.0f), BPoint(x + width, y + 1.0f)); 858 } 859 860 861 BSize 862 BButton::_ValidatePreferredSize() 863 { 864 if (fPreferredSize.width < 0) { 865 // width 866 float width = 20.0f + (float)ceil(StringWidth(Label())); 867 if (width < 75.0f) 868 width = 75.0f; 869 870 if (fDrawAsDefault) 871 width += 6.0f; 872 873 fPreferredSize.width = width; 874 875 // height 876 font_height fontHeight; 877 GetFontHeight(&fontHeight); 878 879 fPreferredSize.height 880 = ceilf((fontHeight.ascent + fontHeight.descent) * 1.8) 881 + (fDrawAsDefault ? 6.0f : 0); 882 } 883 884 return fPreferredSize; 885 } 886 887