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