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