1 /* 2 * Copyright 2001-2016 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 * Axel Dörfler, axeld@pinc-software.de 8 * Marc Flerackers (mflerackers@androme.be) 9 */ 10 11 12 #include <Slider.h> 13 14 #include <algorithm> 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 20 #include <Bitmap.h> 21 #include <ControlLook.h> 22 #include <Errors.h> 23 #include <LayoutUtils.h> 24 #include <Message.h> 25 #include <Region.h> 26 #include <String.h> 27 #include <Window.h> 28 29 #include <binary_compatibility/Interface.h> 30 31 32 #define USE_OFF_SCREEN_VIEW 0 33 34 35 BSlider::BSlider( 36 BRect frame, const char* name, const char* label, BMessage* message, 37 int32 minValue, int32 maxValue, thumb_style thumbType, uint32 resizingMode, 38 uint32 flags) 39 : 40 BControl(frame, name, label, message, resizingMode, flags), 41 fModificationMessage(NULL), 42 fSnoozeAmount(20000), 43 44 fMinLimitLabel(NULL), 45 fMaxLimitLabel(NULL), 46 47 fMinValue(minValue), 48 fMaxValue(maxValue), 49 fKeyIncrementValue(1), 50 51 fHashMarkCount(0), 52 fHashMarks(B_HASH_MARKS_NONE), 53 54 fStyle(thumbType), 55 56 fOrientation(B_HORIZONTAL), 57 fBarThickness(6.0) 58 { 59 _InitBarColor(); 60 61 _InitObject(); 62 SetValue(0); 63 } 64 65 66 BSlider::BSlider(BRect frame, const char* name, const char* label, 67 BMessage* message, int32 minValue, int32 maxValue, orientation posture, 68 thumb_style thumbType, uint32 resizingMode, uint32 flags) 69 : 70 BControl(frame, name, label, message, resizingMode, flags), 71 fModificationMessage(NULL), 72 fSnoozeAmount(20000), 73 74 fMinLimitLabel(NULL), 75 fMaxLimitLabel(NULL), 76 77 fMinValue(minValue), 78 fMaxValue(maxValue), 79 fKeyIncrementValue(1), 80 81 fHashMarkCount(0), 82 fHashMarks(B_HASH_MARKS_NONE), 83 84 fStyle(thumbType), 85 86 fOrientation(posture), 87 fBarThickness(6.0) 88 { 89 _InitBarColor(); 90 91 _InitObject(); 92 SetValue(0); 93 } 94 95 96 BSlider::BSlider(const char* name, const char* label, BMessage* message, 97 int32 minValue, int32 maxValue, orientation posture, thumb_style thumbType, 98 uint32 flags) 99 : 100 BControl(name, label, message, flags), 101 fModificationMessage(NULL), 102 fSnoozeAmount(20000), 103 104 fMinLimitLabel(NULL), 105 fMaxLimitLabel(NULL), 106 107 fMinValue(minValue), 108 fMaxValue(maxValue), 109 fKeyIncrementValue(1), 110 111 fHashMarkCount(0), 112 fHashMarks(B_HASH_MARKS_NONE), 113 114 fStyle(thumbType), 115 116 fOrientation(posture), 117 fBarThickness(6.0) 118 { 119 _InitBarColor(); 120 121 _InitObject(); 122 SetValue(0); 123 } 124 125 126 BSlider::BSlider(BMessage* archive) 127 : 128 BControl(archive) 129 { 130 fModificationMessage = NULL; 131 132 if (archive->HasMessage("_mod_msg")) { 133 BMessage* message = new BMessage; 134 135 archive->FindMessage("_mod_msg", message); 136 137 SetModificationMessage(message); 138 } 139 140 if (archive->FindInt32("_sdelay", &fSnoozeAmount) != B_OK) 141 SetSnoozeAmount(20000); 142 143 rgb_color color; 144 if (archive->FindInt32("_fcolor", (int32*)&color) == B_OK) 145 UseFillColor(true, &color); 146 else 147 UseFillColor(false); 148 149 int32 orient; 150 if (archive->FindInt32("_orient", &orient) == B_OK) 151 fOrientation = (orientation)orient; 152 else 153 fOrientation = B_HORIZONTAL; 154 155 fMinLimitLabel = NULL; 156 fMaxLimitLabel = NULL; 157 158 const char* minlbl = NULL; 159 const char* maxlbl = NULL; 160 161 archive->FindString("_minlbl", &minlbl); 162 archive->FindString("_maxlbl", &maxlbl); 163 164 SetLimitLabels(minlbl, maxlbl); 165 166 if (archive->FindInt32("_min", &fMinValue) != B_OK) 167 fMinValue = 0; 168 169 if (archive->FindInt32("_max", &fMaxValue) != B_OK) 170 fMaxValue = 100; 171 172 if (archive->FindInt32("_incrementvalue", &fKeyIncrementValue) != B_OK) 173 fKeyIncrementValue = 1; 174 175 if (archive->FindInt32("_hashcount", &fHashMarkCount) != B_OK) 176 fHashMarkCount = 11; 177 178 int16 hashloc; 179 if (archive->FindInt16("_hashloc", &hashloc) == B_OK) 180 fHashMarks = (hash_mark_location)hashloc; 181 else 182 fHashMarks = B_HASH_MARKS_NONE; 183 184 int16 sstyle; 185 if (archive->FindInt16("_sstyle", &sstyle) == B_OK) 186 fStyle = (thumb_style)sstyle; 187 else 188 fStyle = B_BLOCK_THUMB; 189 190 if (archive->FindInt32("_bcolor", (int32*)&color) != B_OK) 191 color = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_DARKEN_4_TINT); 192 SetBarColor(color); 193 194 float bthickness; 195 if (archive->FindFloat("_bthickness", &bthickness) == B_OK) 196 fBarThickness = bthickness; 197 else 198 fBarThickness = 6.0f; 199 200 _InitObject(); 201 } 202 203 204 BSlider::~BSlider() 205 { 206 #if USE_OFF_SCREEN_VIEW 207 delete fOffScreenBits; 208 #endif 209 210 delete fModificationMessage; 211 free(fMinLimitLabel); 212 free(fMaxLimitLabel); 213 } 214 215 216 void 217 BSlider::_InitBarColor() 218 { 219 SetBarColor(be_control_look->SliderBarColor( 220 ui_color(B_PANEL_BACKGROUND_COLOR))); 221 UseFillColor(false, NULL); 222 } 223 224 225 void 226 BSlider::_InitObject() 227 { 228 fLocation.x = 0; 229 fLocation.y = 0; 230 fInitialLocation.x = 0; 231 fInitialLocation.y = 0; 232 233 #if USE_OFF_SCREEN_VIEW 234 fOffScreenBits = NULL; 235 fOffScreenView = NULL; 236 #endif 237 238 fUpdateText = NULL; 239 fMinSize.Set(-1, -1); 240 fMaxUpdateTextWidth = -1.0; 241 } 242 243 244 BArchivable* 245 BSlider::Instantiate(BMessage* archive) 246 { 247 if (validate_instantiation(archive, "BSlider")) 248 return new BSlider(archive); 249 250 return NULL; 251 } 252 253 254 status_t 255 BSlider::Archive(BMessage* archive, bool deep) const 256 { 257 status_t ret = BControl::Archive(archive, deep); 258 259 if (ModificationMessage() && ret == B_OK) 260 ret = archive->AddMessage("_mod_msg", ModificationMessage()); 261 262 if (ret == B_OK) 263 ret = archive->AddInt32("_sdelay", fSnoozeAmount); 264 265 if (ret == B_OK) 266 ret = archive->AddInt32("_bcolor", (const uint32&)fBarColor); 267 268 if (FillColor(NULL) && ret == B_OK) 269 ret = archive->AddInt32("_fcolor", (const uint32&)fFillColor); 270 271 if (ret == B_OK && fMinLimitLabel != NULL) 272 ret = archive->AddString("_minlbl", fMinLimitLabel); 273 274 if (ret == B_OK && fMaxLimitLabel != NULL) 275 ret = archive->AddString("_maxlbl", fMaxLimitLabel); 276 277 if (ret == B_OK) 278 ret = archive->AddInt32("_min", fMinValue); 279 280 if (ret == B_OK) 281 ret = archive->AddInt32("_max", fMaxValue); 282 283 if (ret == B_OK) 284 ret = archive->AddInt32("_incrementvalue", fKeyIncrementValue); 285 286 if (ret == B_OK) 287 ret = archive->AddInt32("_hashcount", fHashMarkCount); 288 289 if (ret == B_OK) 290 ret = archive->AddInt16("_hashloc", fHashMarks); 291 292 if (ret == B_OK) 293 ret = archive->AddInt16("_sstyle", fStyle); 294 295 if (ret == B_OK) 296 ret = archive->AddInt32("_orient", fOrientation); 297 298 if (ret == B_OK) 299 ret = archive->AddFloat("_bthickness", fBarThickness); 300 301 return ret; 302 } 303 304 305 status_t 306 BSlider::Perform(perform_code code, void* _data) 307 { 308 switch (code) { 309 case PERFORM_CODE_MIN_SIZE: 310 ((perform_data_min_size*)_data)->return_value = BSlider::MinSize(); 311 return B_OK; 312 313 case PERFORM_CODE_MAX_SIZE: 314 ((perform_data_max_size*)_data)->return_value = BSlider::MaxSize(); 315 return B_OK; 316 317 case PERFORM_CODE_PREFERRED_SIZE: 318 ((perform_data_preferred_size*)_data)->return_value 319 = BSlider::PreferredSize(); 320 return B_OK; 321 322 case PERFORM_CODE_LAYOUT_ALIGNMENT: 323 ((perform_data_layout_alignment*)_data)->return_value 324 = BSlider::LayoutAlignment(); 325 return B_OK; 326 327 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 328 ((perform_data_has_height_for_width*)_data)->return_value 329 = BSlider::HasHeightForWidth(); 330 return B_OK; 331 332 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 333 { 334 perform_data_get_height_for_width* data 335 = (perform_data_get_height_for_width*)_data; 336 BSlider::GetHeightForWidth(data->width, &data->min, &data->max, 337 &data->preferred); 338 return B_OK; 339 } 340 341 case PERFORM_CODE_SET_LAYOUT: 342 { 343 perform_data_set_layout* data = (perform_data_set_layout*)_data; 344 BSlider::SetLayout(data->layout); 345 return B_OK; 346 } 347 348 case PERFORM_CODE_LAYOUT_INVALIDATED: 349 { 350 perform_data_layout_invalidated* data 351 = (perform_data_layout_invalidated*)_data; 352 BSlider::LayoutInvalidated(data->descendants); 353 return B_OK; 354 } 355 356 case PERFORM_CODE_DO_LAYOUT: 357 { 358 BSlider::DoLayout(); 359 return B_OK; 360 } 361 362 case PERFORM_CODE_SET_ICON: 363 { 364 perform_data_set_icon* data = (perform_data_set_icon*)_data; 365 return BSlider::SetIcon(data->icon, data->flags); 366 } 367 } 368 369 return BControl::Perform(code, _data); 370 } 371 372 373 void 374 BSlider::WindowActivated(bool state) 375 { 376 BControl::WindowActivated(state); 377 } 378 379 380 void 381 BSlider::AttachedToWindow() 382 { 383 ResizeToPreferred(); 384 385 #if USE_OFF_SCREEN_VIEW 386 BRect bounds(Bounds()); 387 388 if (!fOffScreenView) { 389 fOffScreenView = new BView(bounds, "", B_FOLLOW_ALL, B_WILL_DRAW); 390 391 BFont font; 392 GetFont(&font); 393 fOffScreenView->SetFont(&font); 394 } 395 396 if (!fOffScreenBits) { 397 fOffScreenBits = new BBitmap(bounds, B_RGBA32, true, false); 398 399 if (fOffScreenBits && fOffScreenView) 400 fOffScreenBits->AddChild(fOffScreenView); 401 402 } else if (fOffScreenView) 403 fOffScreenBits->AddChild(fOffScreenView); 404 #endif // USE_OFF_SCREEN_VIEW 405 406 BControl::AttachedToWindow(); 407 408 BView* view = OffscreenView(); 409 if (view != NULL && view->LockLooper()) { 410 view->SetViewColor(B_TRANSPARENT_COLOR); 411 if (LowUIColor() != B_NO_COLOR) 412 view->SetLowUIColor(LowUIColor()); 413 else 414 view->SetLowColor(LowColor()); 415 416 view->UnlockLooper(); 417 } 418 419 int32 value = Value(); 420 SetValue(value); 421 // makes sure the value is within valid bounds 422 _SetLocationForValue(Value()); 423 // makes sure the location is correct 424 UpdateTextChanged(); 425 } 426 427 428 void 429 BSlider::AllAttached() 430 { 431 BControl::AllAttached(); 432 433 // When using a layout we may not have a parent, so we need to employ the 434 // standard system colors manually. Due to how layouts work, this must 435 // happen here, rather than in AttachedToWindow(). 436 if (Parent() == NULL) 437 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 438 } 439 440 441 void 442 BSlider::AllDetached() 443 { 444 BControl::AllDetached(); 445 } 446 447 448 void 449 BSlider::DetachedFromWindow() 450 { 451 BControl::DetachedFromWindow(); 452 453 #if USE_OFF_SCREEN_VIEW 454 if (fOffScreenBits) { 455 delete fOffScreenBits; 456 fOffScreenBits = NULL; 457 fOffScreenView = NULL; 458 } 459 #endif 460 } 461 462 463 void 464 BSlider::MessageReceived(BMessage* message) 465 { 466 BControl::MessageReceived(message); 467 } 468 469 470 void 471 BSlider::FrameMoved(BPoint new_position) 472 { 473 BControl::FrameMoved(new_position); 474 } 475 476 477 void 478 BSlider::FrameResized(float w,float h) 479 { 480 BControl::FrameResized(w, h); 481 482 BRect bounds(Bounds()); 483 484 if (bounds.right <= 0.0f || bounds.bottom <= 0.0f) 485 return; 486 487 #if USE_OFF_SCREEN_VIEW 488 if (fOffScreenBits) { 489 fOffScreenBits->RemoveChild(fOffScreenView); 490 delete fOffScreenBits; 491 492 fOffScreenView->ResizeTo(bounds.Width(), bounds.Height()); 493 494 fOffScreenBits = new BBitmap(Bounds(), B_RGBA32, true, false); 495 fOffScreenBits->AddChild(fOffScreenView); 496 } 497 #endif 498 499 Invalidate(); 500 } 501 502 503 void 504 BSlider::KeyDown(const char* bytes, int32 numBytes) 505 { 506 if (!IsEnabled() || IsHidden()) 507 return; 508 509 int32 newValue = Value(); 510 511 switch (bytes[0]) { 512 case B_LEFT_ARROW: 513 case B_DOWN_ARROW: 514 newValue -= KeyIncrementValue(); 515 break; 516 517 case B_RIGHT_ARROW: 518 case B_UP_ARROW: 519 newValue += KeyIncrementValue(); 520 break; 521 522 case B_HOME: 523 newValue = fMinValue; 524 break; 525 526 case B_END: 527 newValue = fMaxValue; 528 break; 529 530 default: 531 BControl::KeyDown(bytes, numBytes); 532 return; 533 } 534 535 if (newValue < fMinValue) 536 newValue = fMinValue; 537 538 if (newValue > fMaxValue) 539 newValue = fMaxValue; 540 541 if (newValue != Value()) { 542 fInitialLocation = _Location(); 543 SetValue(newValue); 544 InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED); 545 } 546 } 547 548 void 549 BSlider::KeyUp(const char* bytes, int32 numBytes) 550 { 551 if (fInitialLocation != _Location()) { 552 // The last KeyDown event triggered the modification message or no 553 // notification at all, we may also have sent the modification message 554 // continually while the user kept pressing the key. In either case, 555 // finish with the final message to make the behavior consistent with 556 // changing the value by mouse. 557 Invoke(); 558 } 559 } 560 561 562 /*! 563 Makes sure the \a point is within valid bounds. 564 Returns \c true if the relevant coordinate (depending on the orientation 565 of the slider) differs from \a comparePoint. 566 */ 567 bool 568 BSlider::_ConstrainPoint(BPoint& point, BPoint comparePoint) const 569 { 570 if (fOrientation == B_HORIZONTAL) { 571 if (point.x != comparePoint.x) { 572 if (point.x < _MinPosition()) 573 point.x = _MinPosition(); 574 else if (point.x > _MaxPosition()) 575 point.x = _MaxPosition(); 576 577 return true; 578 } 579 } else { 580 if (point.y != comparePoint.y) { 581 if (point.y > _MinPosition()) 582 point.y = _MinPosition(); 583 else if (point.y < _MaxPosition()) 584 point.y = _MaxPosition(); 585 586 return true; 587 } 588 } 589 590 return false; 591 } 592 593 594 void 595 BSlider::MouseDown(BPoint point) 596 { 597 if (!IsEnabled()) 598 return; 599 600 if (BarFrame().Contains(point) || ThumbFrame().Contains(point)) 601 fInitialLocation = _Location(); 602 603 uint32 buttons; 604 GetMouse(&point, &buttons, true); 605 606 _ConstrainPoint(point, fInitialLocation); 607 SetValue(ValueForPoint(point)); 608 609 if (_Location() != fInitialLocation) 610 InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED); 611 612 if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) { 613 SetTracking(true); 614 SetMouseEventMask(B_POINTER_EVENTS, 615 B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY); 616 } else { 617 // synchronous mouse tracking 618 BPoint prevPoint; 619 620 while (buttons) { 621 prevPoint = point; 622 623 snooze(SnoozeAmount()); 624 GetMouse(&point, &buttons, true); 625 626 if (_ConstrainPoint(point, prevPoint)) { 627 int32 value = ValueForPoint(point); 628 if (value != Value()) { 629 SetValue(value); 630 InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED); 631 } 632 } 633 } 634 if (_Location() != fInitialLocation) 635 Invoke(); 636 } 637 } 638 639 640 void 641 BSlider::MouseUp(BPoint point) 642 { 643 if (IsTracking()) { 644 if (_Location() != fInitialLocation) 645 Invoke(); 646 647 SetTracking(false); 648 } else 649 BControl::MouseUp(point); 650 } 651 652 653 void 654 BSlider::MouseMoved(BPoint point, uint32 transit, const BMessage* message) 655 { 656 if (IsTracking()) { 657 if (_ConstrainPoint(point, _Location())) { 658 int32 value = ValueForPoint(point); 659 if (value != Value()) { 660 SetValue(value); 661 InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED); 662 } 663 } 664 } else 665 BControl::MouseMoved(point, transit, message); 666 } 667 668 669 void 670 BSlider::Pulse() 671 { 672 BControl::Pulse(); 673 } 674 675 676 void 677 BSlider::SetLabel(const char* label) 678 { 679 BControl::SetLabel(label); 680 } 681 682 683 void 684 BSlider::SetLimitLabels(const char* minLabel, const char* maxLabel) 685 { 686 free(fMinLimitLabel); 687 fMinLimitLabel = minLabel ? strdup(minLabel) : NULL; 688 689 free(fMaxLimitLabel); 690 fMaxLimitLabel = maxLabel ? strdup(maxLabel) : NULL; 691 692 InvalidateLayout(); 693 694 // TODO: This is for backwards compatibility and should 695 // probably be removed when breaking binary compatiblity. 696 // Applications like our own Mouse rely on this behavior. 697 if ((Flags() & B_SUPPORTS_LAYOUT) == 0) 698 ResizeToPreferred(); 699 700 Invalidate(); 701 } 702 703 704 const char* 705 BSlider::MinLimitLabel() const 706 { 707 return fMinLimitLabel; 708 } 709 710 711 const char* 712 BSlider::MaxLimitLabel() const 713 { 714 return fMaxLimitLabel; 715 } 716 717 718 void 719 BSlider::SetValue(int32 value) 720 { 721 if (value < fMinValue) 722 value = fMinValue; 723 724 if (value > fMaxValue) 725 value = fMaxValue; 726 727 if (value == Value()) 728 return; 729 730 _SetLocationForValue(value); 731 732 BRect oldThumbFrame = ThumbFrame(); 733 734 // While it would be enough to do this dependent on fUseFillColor, 735 // that doesn't work out if DrawBar() has been overridden by a sub class 736 if (fOrientation == B_HORIZONTAL) 737 oldThumbFrame.top = BarFrame().top; 738 else 739 oldThumbFrame.left = BarFrame().left; 740 741 BControl::SetValueNoUpdate(value); 742 BRect invalid = oldThumbFrame | ThumbFrame(); 743 744 if (Style() == B_TRIANGLE_THUMB) { 745 // 1) We need to take care of pixels touched because of anti-aliasing. 746 // 2) We need to update the region with the focus mark as well. (A 747 // method BSlider::FocusMarkFrame() would be nice as well.) 748 if (fOrientation == B_HORIZONTAL) { 749 if (IsFocus()) 750 invalid.bottom += 2; 751 invalid.InsetBy(-1, 0); 752 } else { 753 if (IsFocus()) 754 invalid.left -= 2; 755 invalid.InsetBy(0, -1); 756 } 757 } 758 759 Invalidate(invalid); 760 761 UpdateTextChanged(); 762 } 763 764 765 int32 766 BSlider::ValueForPoint(BPoint location) const 767 { 768 float min; 769 float max; 770 float position; 771 if (fOrientation == B_HORIZONTAL) { 772 min = _MinPosition(); 773 max = _MaxPosition(); 774 position = location.x; 775 } else { 776 max = _MinPosition(); 777 min = _MaxPosition(); 778 position = min + (max - location.y); 779 } 780 781 if (position < min) 782 position = min; 783 784 if (position > max) 785 position = max; 786 787 return (int32)roundf(((position - min) * (fMaxValue - fMinValue) 788 / (max - min)) + fMinValue); 789 } 790 791 792 void 793 BSlider::SetPosition(float position) 794 { 795 if (position <= 0.0f) 796 SetValue(fMinValue); 797 else if (position >= 1.0f) 798 SetValue(fMaxValue); 799 else 800 SetValue((int32)(position * (fMaxValue - fMinValue) + fMinValue)); 801 } 802 803 804 float 805 BSlider::Position() const 806 { 807 float range = (float)(fMaxValue - fMinValue); 808 if (range == 0.0f) 809 range = 1.0f; 810 811 return (float)(Value() - fMinValue) / range; 812 } 813 814 815 void 816 BSlider::SetEnabled(bool on) 817 { 818 BControl::SetEnabled(on); 819 } 820 821 822 void 823 BSlider::GetLimits(int32* minimum, int32* maximum) const 824 { 825 if (minimum != NULL) 826 *minimum = fMinValue; 827 828 if (maximum != NULL) 829 *maximum = fMaxValue; 830 } 831 832 833 // #pragma mark - drawing 834 835 836 void 837 BSlider::Draw(BRect updateRect) 838 { 839 // clear out background 840 BRegion background(updateRect); 841 background.Exclude(BarFrame()); 842 bool drawBackground = true; 843 if (Parent() != NULL && (Parent()->Flags() & B_DRAW_ON_CHILDREN) != 0) { 844 // This view is embedded somewhere, most likely the Tracker Desktop 845 // shelf. 846 drawBackground = false; 847 } 848 849 #if USE_OFF_SCREEN_VIEW 850 if (!fOffScreenBits) 851 return; 852 853 if (fOffScreenBits->Lock()) { 854 fOffScreenView->SetViewColor(ViewColor()); 855 fOffScreenView->SetLowColor(LowColor()); 856 #endif 857 858 if (drawBackground && background.Frame().IsValid()) 859 OffscreenView()->FillRegion(&background, B_SOLID_LOW); 860 861 #if USE_OFF_SCREEN_VIEW 862 fOffScreenView->Sync(); 863 fOffScreenBits->Unlock(); 864 } 865 #endif 866 867 DrawSlider(); 868 } 869 870 871 void 872 BSlider::DrawSlider() 873 { 874 if (LockLooper()) { 875 #if USE_OFF_SCREEN_VIEW 876 if (fOffScreenBits == NULL) 877 return; 878 879 if (fOffScreenBits->Lock()) { 880 #endif 881 DrawBar(); 882 DrawHashMarks(); 883 DrawThumb(); 884 DrawFocusMark(); 885 DrawText(); 886 887 #if USE_OFF_SCREEN_VIEW 888 fOffScreenView->Sync(); 889 fOffScreenBits->Unlock(); 890 891 DrawBitmap(fOffScreenBits, B_ORIGIN); 892 } 893 #endif 894 UnlockLooper(); 895 } 896 } 897 898 899 void 900 BSlider::DrawBar() 901 { 902 BRect frame = BarFrame(); 903 BView* view = OffscreenView(); 904 905 uint32 flags = be_control_look->Flags(this); 906 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 907 rgb_color rightFillColor = fBarColor; 908 rgb_color leftFillColor = fUseFillColor ? fFillColor : fBarColor; 909 be_control_look->DrawSliderBar(view, frame, frame, base, leftFillColor, 910 rightFillColor, Position(), flags, fOrientation); 911 } 912 913 914 void 915 BSlider::DrawHashMarks() 916 { 917 if (fHashMarks == B_HASH_MARKS_NONE) 918 return; 919 920 BRect frame = HashMarksFrame(); 921 BView* view = OffscreenView(); 922 923 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 924 uint32 flags = be_control_look->Flags(this); 925 be_control_look->DrawSliderHashMarks(view, frame, frame, base, 926 fHashMarkCount, fHashMarks, flags, fOrientation); 927 } 928 929 930 void 931 BSlider::DrawThumb() 932 { 933 if (Style() == B_BLOCK_THUMB) 934 _DrawBlockThumb(); 935 else 936 _DrawTriangleThumb(); 937 } 938 939 940 void 941 BSlider::DrawFocusMark() 942 { 943 if (!IsFocus()) 944 return; 945 946 OffscreenView()->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); 947 948 BRect frame = ThumbFrame(); 949 950 if (fStyle == B_BLOCK_THUMB) { 951 frame.left += 2.0f; 952 frame.top += 2.0f; 953 frame.right -= 3.0f; 954 frame.bottom -= 3.0f; 955 OffscreenView()->StrokeRect(frame); 956 } else { 957 if (fOrientation == B_HORIZONTAL) { 958 OffscreenView()->StrokeLine(BPoint(frame.left, frame.bottom + 2.0f), 959 BPoint(frame.right, frame.bottom + 2.0f)); 960 } else { 961 OffscreenView()->StrokeLine(BPoint(frame.left - 2.0f, frame.top), 962 BPoint(frame.left - 2.0f, frame.bottom)); 963 } 964 } 965 } 966 967 968 void 969 BSlider::DrawText() 970 { 971 BRect bounds(Bounds()); 972 BView* view = OffscreenView(); 973 974 rgb_color base = ViewColor(); 975 uint32 flags = be_control_look->Flags(this); 976 977 font_height fontHeight; 978 GetFontHeight(&fontHeight); 979 if (Orientation() == B_HORIZONTAL) { 980 if (Label() != NULL) { 981 be_control_look->DrawLabel(view, Label(), base, flags, 982 BPoint(0.0f, ceilf(fontHeight.ascent))); 983 } 984 985 // the update text is updated in SetValue() only 986 if (fUpdateText != NULL) { 987 be_control_look->DrawLabel(view, fUpdateText, base, flags, 988 BPoint(bounds.right - StringWidth(fUpdateText), 989 ceilf(fontHeight.ascent))); 990 } 991 992 if (fMinLimitLabel != NULL) { 993 be_control_look->DrawLabel(view, fMinLimitLabel, base, flags, 994 BPoint(0.0f, bounds.bottom - fontHeight.descent)); 995 } 996 997 if (fMaxLimitLabel != NULL) { 998 be_control_look->DrawLabel(view, fMaxLimitLabel, base, flags, 999 BPoint(bounds.right - StringWidth(fMaxLimitLabel), 1000 bounds.bottom - fontHeight.descent)); 1001 } 1002 } else { 1003 float lineHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent) 1004 + ceilf(fontHeight.leading); 1005 float baseLine = ceilf(fontHeight.ascent); 1006 1007 if (Label() != NULL) { 1008 be_control_look->DrawLabel(view, Label(), base, flags, 1009 BPoint((bounds.Width() - StringWidth(Label())) / 2.0, 1010 baseLine)); 1011 baseLine += lineHeight; 1012 } 1013 1014 if (fMaxLimitLabel != NULL) { 1015 be_control_look->DrawLabel(view, fMaxLimitLabel, base, flags, 1016 BPoint((bounds.Width() - StringWidth(fMaxLimitLabel)) / 2.0, 1017 baseLine)); 1018 } 1019 1020 baseLine = bounds.bottom - ceilf(fontHeight.descent); 1021 1022 if (fMinLimitLabel != NULL) { 1023 be_control_look->DrawLabel(view, fMinLimitLabel, base, flags, 1024 BPoint((bounds.Width() - StringWidth(fMinLimitLabel)) / 2.0, 1025 baseLine)); 1026 baseLine -= lineHeight; 1027 } 1028 1029 if (fUpdateText != NULL) { 1030 be_control_look->DrawLabel(view, fUpdateText, base, flags, 1031 BPoint((bounds.Width() - StringWidth(fUpdateText)) / 2.0, 1032 baseLine)); 1033 } 1034 } 1035 } 1036 1037 1038 // #pragma mark - 1039 1040 1041 const char* 1042 BSlider::UpdateText() const 1043 { 1044 return NULL; 1045 } 1046 1047 1048 void 1049 BSlider::UpdateTextChanged() 1050 { 1051 // update text label 1052 float oldWidth = 0.0; 1053 if (fUpdateText != NULL) 1054 oldWidth = StringWidth(fUpdateText); 1055 1056 const char* oldUpdateText = fUpdateText; 1057 fUpdateText = UpdateText(); 1058 bool updateTextOnOff = (fUpdateText == NULL && oldUpdateText != NULL) 1059 || (fUpdateText != NULL && oldUpdateText == NULL); 1060 1061 float newWidth = 0.0; 1062 if (fUpdateText != NULL) 1063 newWidth = StringWidth(fUpdateText); 1064 1065 float width = ceilf(std::max(newWidth, oldWidth)) + 2.0f; 1066 if (width != 0) { 1067 font_height fontHeight; 1068 GetFontHeight(&fontHeight); 1069 1070 float height = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); 1071 float lineHeight = height + ceilf(fontHeight.leading); 1072 BRect invalid(Bounds()); 1073 if (fOrientation == B_HORIZONTAL) 1074 invalid = BRect(invalid.right - width, 0, invalid.right, height); 1075 else { 1076 if (!updateTextOnOff) { 1077 invalid.left = (invalid.left + invalid.right - width) / 2; 1078 invalid.right = invalid.left + width; 1079 if (fMinLimitLabel != NULL) 1080 invalid.bottom -= lineHeight; 1081 1082 invalid.top = invalid.bottom - height; 1083 } 1084 } 1085 Invalidate(invalid); 1086 } 1087 1088 float oldMaxUpdateTextWidth = fMaxUpdateTextWidth; 1089 fMaxUpdateTextWidth = MaxUpdateTextWidth(); 1090 if (oldMaxUpdateTextWidth != fMaxUpdateTextWidth) 1091 InvalidateLayout(); 1092 } 1093 1094 1095 BRect 1096 BSlider::BarFrame() const 1097 { 1098 BRect frame(Bounds()); 1099 1100 font_height fontHeight; 1101 GetFontHeight(&fontHeight); 1102 1103 float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); 1104 float leading = ceilf(fontHeight.leading); 1105 1106 float thumbInset; 1107 if (fStyle == B_BLOCK_THUMB) 1108 thumbInset = 8.0; 1109 else 1110 thumbInset = 7.0; 1111 1112 if (Orientation() == B_HORIZONTAL) { 1113 frame.left = thumbInset; 1114 frame.top = 6.0 + (Label() || fUpdateText ? textHeight + 4.0 : 0.0); 1115 frame.right -= thumbInset; 1116 frame.bottom = frame.top + fBarThickness; 1117 } else { 1118 frame.left = floorf((frame.Width() - fBarThickness) / 2.0); 1119 frame.top = thumbInset; 1120 if (Label() != NULL) 1121 frame.top += textHeight; 1122 1123 if (fMaxLimitLabel != NULL) { 1124 frame.top += textHeight; 1125 if (Label()) 1126 frame.top += leading; 1127 } 1128 1129 frame.right = frame.left + fBarThickness; 1130 frame.bottom = frame.bottom - thumbInset; 1131 if (fMinLimitLabel != NULL) 1132 frame.bottom -= textHeight; 1133 1134 if (fUpdateText != NULL) { 1135 frame.bottom -= textHeight; 1136 if (fMinLimitLabel != NULL) 1137 frame.bottom -= leading; 1138 } 1139 } 1140 1141 return frame; 1142 } 1143 1144 1145 BRect 1146 BSlider::HashMarksFrame() const 1147 { 1148 BRect frame(BarFrame()); 1149 1150 if (fOrientation == B_HORIZONTAL) { 1151 frame.top -= 6.0; 1152 frame.bottom += 6.0; 1153 } else { 1154 frame.left -= 6.0; 1155 frame.right += 6.0; 1156 } 1157 1158 return frame; 1159 } 1160 1161 1162 BRect 1163 BSlider::ThumbFrame() const 1164 { 1165 // TODO: The slider looks really ugly and broken when it is too little. 1166 // I would suggest using BarFrame() here to get the top and bottom coords 1167 // and spread them further apart for the thumb 1168 1169 BRect frame = Bounds(); 1170 1171 font_height fontHeight; 1172 GetFontHeight(&fontHeight); 1173 1174 float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); 1175 1176 if (fStyle == B_BLOCK_THUMB) { 1177 if (Orientation() == B_HORIZONTAL) { 1178 frame.left = floorf(Position() * (_MaxPosition() 1179 - _MinPosition()) + _MinPosition()) - 8; 1180 frame.top = 2 + (Label() || fUpdateText ? textHeight + 4 : 0); 1181 frame.right = frame.left + 17; 1182 frame.bottom = frame.top + fBarThickness + 7; 1183 } else { 1184 frame.left = floor((frame.Width() - fBarThickness) / 2) - 4; 1185 frame.top = floorf(Position() * (_MaxPosition() 1186 - _MinPosition()) + _MinPosition()) - 8; 1187 frame.right = frame.left + fBarThickness + 7; 1188 frame.bottom = frame.top + 17; 1189 } 1190 } else { 1191 if (Orientation() == B_HORIZONTAL) { 1192 frame.left = floorf(Position() * (_MaxPosition() 1193 - _MinPosition()) + _MinPosition()) - 6; 1194 frame.right = frame.left + 12; 1195 frame.top = 3 + fBarThickness + (Label() ? textHeight + 4 : 0); 1196 frame.bottom = frame.top + 8; 1197 } else { 1198 frame.left = floorf((frame.Width() + fBarThickness) / 2) - 3; 1199 frame.top = floorf(Position() * (_MaxPosition() 1200 - _MinPosition())) + _MinPosition() - 6; 1201 frame.right = frame.left + 8; 1202 frame.bottom = frame.top + 12; 1203 } 1204 } 1205 1206 return frame; 1207 } 1208 1209 1210 void 1211 BSlider::SetFlags(uint32 flags) 1212 { 1213 BControl::SetFlags(flags); 1214 } 1215 1216 1217 void 1218 BSlider::SetResizingMode(uint32 mode) 1219 { 1220 BControl::SetResizingMode(mode); 1221 } 1222 1223 1224 void 1225 BSlider::GetPreferredSize(float* _width, float* _height) 1226 { 1227 BSize preferredSize = PreferredSize(); 1228 1229 if (Orientation() == B_HORIZONTAL) { 1230 if (_width != NULL) { 1231 // NOTE: For compatibility reasons, a horizontal BSlider 1232 // never shrinks horizontally. This only affects applications 1233 // which do not use the new layout system. 1234 *_width = std::max(Bounds().Width(), preferredSize.width); 1235 } 1236 1237 if (_height != NULL) 1238 *_height = preferredSize.height; 1239 } else { 1240 if (_width != NULL) 1241 *_width = preferredSize.width; 1242 1243 if (_height != NULL) { 1244 // NOTE: Similarly, a vertical BSlider never shrinks 1245 // vertically. This only affects applications which do not 1246 // use the new layout system. 1247 *_height = std::max(Bounds().Height(), preferredSize.height); 1248 } 1249 } 1250 } 1251 1252 1253 void 1254 BSlider::ResizeToPreferred() 1255 { 1256 BControl::ResizeToPreferred(); 1257 } 1258 1259 1260 status_t 1261 BSlider::Invoke(BMessage* message) 1262 { 1263 return BControl::Invoke(message); 1264 } 1265 1266 1267 BHandler* 1268 BSlider::ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier, 1269 int32 command, const char* property) 1270 { 1271 return BControl::ResolveSpecifier(message, index, specifier, command, 1272 property); 1273 } 1274 1275 1276 status_t 1277 BSlider::GetSupportedSuites(BMessage* message) 1278 { 1279 return BControl::GetSupportedSuites(message); 1280 } 1281 1282 1283 void 1284 BSlider::SetModificationMessage(BMessage* message) 1285 { 1286 delete fModificationMessage; 1287 fModificationMessage = message; 1288 } 1289 1290 1291 BMessage* 1292 BSlider::ModificationMessage() const 1293 { 1294 return fModificationMessage; 1295 } 1296 1297 1298 void 1299 BSlider::SetSnoozeAmount(int32 snoozeTime) 1300 { 1301 if (snoozeTime < 10000) 1302 snoozeTime = 10000; 1303 else if (snoozeTime > 1000000) 1304 snoozeTime = 1000000; 1305 1306 fSnoozeAmount = snoozeTime; 1307 } 1308 1309 1310 int32 1311 BSlider::SnoozeAmount() const 1312 { 1313 return fSnoozeAmount; 1314 } 1315 1316 1317 void 1318 BSlider::SetKeyIncrementValue(int32 incrementValue) 1319 { 1320 fKeyIncrementValue = incrementValue; 1321 } 1322 1323 1324 int32 1325 BSlider::KeyIncrementValue() const 1326 { 1327 return fKeyIncrementValue; 1328 } 1329 1330 1331 void 1332 BSlider::SetHashMarkCount(int32 hashMarkCount) 1333 { 1334 fHashMarkCount = hashMarkCount; 1335 Invalidate(); 1336 } 1337 1338 1339 int32 1340 BSlider::HashMarkCount() const 1341 { 1342 return fHashMarkCount; 1343 } 1344 1345 1346 void 1347 BSlider::SetHashMarks(hash_mark_location where) 1348 { 1349 fHashMarks = where; 1350 // TODO: enable if the hashmark look is influencing the control size! 1351 // InvalidateLayout(); 1352 Invalidate(); 1353 } 1354 1355 1356 hash_mark_location 1357 BSlider::HashMarks() const 1358 { 1359 return fHashMarks; 1360 } 1361 1362 1363 void 1364 BSlider::SetStyle(thumb_style style) 1365 { 1366 fStyle = style; 1367 InvalidateLayout(); 1368 Invalidate(); 1369 } 1370 1371 1372 thumb_style 1373 BSlider::Style() const 1374 { 1375 return fStyle; 1376 } 1377 1378 1379 void 1380 BSlider::SetBarColor(rgb_color barColor) 1381 { 1382 fBarColor = barColor; 1383 Invalidate(BarFrame()); 1384 } 1385 1386 1387 rgb_color 1388 BSlider::BarColor() const 1389 { 1390 return fBarColor; 1391 } 1392 1393 1394 void 1395 BSlider::UseFillColor(bool useFill, const rgb_color* barColor) 1396 { 1397 fUseFillColor = useFill; 1398 1399 if (useFill && barColor) 1400 fFillColor = *barColor; 1401 1402 Invalidate(BarFrame()); 1403 } 1404 1405 1406 bool 1407 BSlider::FillColor(rgb_color* barColor) const 1408 { 1409 if (barColor && fUseFillColor) 1410 *barColor = fFillColor; 1411 1412 return fUseFillColor; 1413 } 1414 1415 1416 BView* 1417 BSlider::OffscreenView() const 1418 { 1419 #if USE_OFF_SCREEN_VIEW 1420 return fOffScreenView; 1421 #else 1422 return (BView*)this; 1423 #endif 1424 } 1425 1426 1427 orientation 1428 BSlider::Orientation() const 1429 { 1430 return fOrientation; 1431 } 1432 1433 1434 void 1435 BSlider::SetOrientation(orientation posture) 1436 { 1437 if (fOrientation == posture) 1438 return; 1439 1440 fOrientation = posture; 1441 InvalidateLayout(); 1442 Invalidate(); 1443 } 1444 1445 1446 float 1447 BSlider::BarThickness() const 1448 { 1449 return fBarThickness; 1450 } 1451 1452 1453 void 1454 BSlider::SetBarThickness(float thickness) 1455 { 1456 if (thickness < 1.0) 1457 thickness = 1.0; 1458 else 1459 thickness = roundf(thickness); 1460 1461 if (thickness != fBarThickness) { 1462 // calculate invalid barframe and extend by hashmark size 1463 float hInset = 0.0; 1464 float vInset = 0.0; 1465 if (fOrientation == B_HORIZONTAL) 1466 vInset = -6.0; 1467 else 1468 hInset = -6.0; 1469 BRect invalid = BarFrame().InsetByCopy(hInset, vInset) | ThumbFrame(); 1470 1471 fBarThickness = thickness; 1472 1473 invalid = invalid | BarFrame().InsetByCopy(hInset, vInset) 1474 | ThumbFrame(); 1475 Invalidate(invalid); 1476 InvalidateLayout(); 1477 } 1478 } 1479 1480 1481 void 1482 BSlider::SetFont(const BFont* font, uint32 properties) 1483 { 1484 BControl::SetFont(font, properties); 1485 1486 #if USE_OFF_SCREEN_VIEW 1487 if (fOffScreenView && fOffScreenBits) { 1488 if (fOffScreenBits->Lock()) { 1489 fOffScreenView->SetFont(font, properties); 1490 fOffScreenBits->Unlock(); 1491 } 1492 } 1493 #endif 1494 1495 InvalidateLayout(); 1496 } 1497 1498 1499 void 1500 BSlider::SetLimits(int32 minimum, int32 maximum) 1501 { 1502 if (minimum <= maximum) { 1503 fMinValue = minimum; 1504 fMaxValue = maximum; 1505 1506 int32 value = Value(); 1507 value = std::max(minimum, value); 1508 value = std::min(maximum, value); 1509 1510 if (value != Value()) 1511 SetValue(value); 1512 } 1513 } 1514 1515 1516 float 1517 BSlider::MaxUpdateTextWidth() 1518 { 1519 // very simplistic implementation that assumes the string will be widest 1520 // at the maximum value 1521 int32 value = Value(); 1522 SetValueNoUpdate(fMaxValue); 1523 float width = StringWidth(UpdateText()); 1524 SetValueNoUpdate(value); 1525 // in case the derived class uses a fixed buffer, the contents 1526 // should be reset for the old value 1527 UpdateText(); 1528 1529 return width; 1530 } 1531 1532 1533 // #pragma mark - layout related 1534 1535 1536 BSize 1537 BSlider::MinSize() 1538 { 1539 return BLayoutUtils::ComposeSize(ExplicitMinSize(), _ValidateMinSize()); 1540 } 1541 1542 1543 BSize 1544 BSlider::MaxSize() 1545 { 1546 BSize maxSize = _ValidateMinSize(); 1547 if (fOrientation == B_HORIZONTAL) 1548 maxSize.width = B_SIZE_UNLIMITED; 1549 else 1550 maxSize.height = B_SIZE_UNLIMITED; 1551 1552 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), maxSize); 1553 } 1554 1555 1556 BSize 1557 BSlider::PreferredSize() 1558 { 1559 BSize preferredSize = _ValidateMinSize(); 1560 if (fOrientation == B_HORIZONTAL) 1561 preferredSize.width = std::max(100.0f, preferredSize.width); 1562 else 1563 preferredSize.height = std::max(100.0f, preferredSize.height); 1564 1565 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), preferredSize); 1566 } 1567 1568 1569 status_t 1570 BSlider::SetIcon(const BBitmap* icon, uint32 flags) 1571 { 1572 return BControl::SetIcon(icon, flags); 1573 } 1574 1575 1576 void 1577 BSlider::LayoutInvalidated(bool descendants) 1578 { 1579 // invalidate cached preferred size 1580 fMinSize.Set(-1, -1); 1581 } 1582 1583 1584 // #pragma mark - private 1585 1586 1587 void 1588 BSlider::_DrawBlockThumb() 1589 { 1590 BRect frame = ThumbFrame(); 1591 BView* view = OffscreenView(); 1592 1593 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 1594 uint32 flags = be_control_look->Flags(this); 1595 be_control_look->DrawSliderThumb(view, frame, frame, base, flags, 1596 fOrientation); 1597 } 1598 1599 1600 void 1601 BSlider::_DrawTriangleThumb() 1602 { 1603 BRect frame = ThumbFrame(); 1604 BView* view = OffscreenView(); 1605 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 1606 uint32 flags = be_control_look->Flags(this); 1607 be_control_look->DrawSliderTriangle(view, frame, frame, base, flags, 1608 fOrientation); 1609 } 1610 1611 1612 BPoint 1613 BSlider::_Location() const 1614 { 1615 return fLocation; 1616 } 1617 1618 1619 void 1620 BSlider::_SetLocationForValue(int32 value) 1621 { 1622 BPoint loc; 1623 float range = (float)(fMaxValue - fMinValue); 1624 if (range == 0) 1625 range = 1; 1626 1627 float pos = (float)(value - fMinValue) / range * 1628 (_MaxPosition() - _MinPosition()); 1629 1630 if (fOrientation == B_HORIZONTAL) { 1631 loc.x = ceil(_MinPosition() + pos); 1632 loc.y = 0; 1633 } else { 1634 loc.x = 0; 1635 loc.y = floor(_MaxPosition() - pos); 1636 } 1637 fLocation = loc; 1638 } 1639 1640 1641 float 1642 BSlider::_MinPosition() const 1643 { 1644 if (fOrientation == B_HORIZONTAL) 1645 return BarFrame().left + 1.0f; 1646 1647 return BarFrame().bottom - 1.0f; 1648 } 1649 1650 1651 float 1652 BSlider::_MaxPosition() const 1653 { 1654 if (fOrientation == B_HORIZONTAL) 1655 return BarFrame().right - 1.0f; 1656 1657 return BarFrame().top + 1.0f; 1658 } 1659 1660 1661 BSize 1662 BSlider::_ValidateMinSize() 1663 { 1664 if (fMinSize.width >= 0) { 1665 // the preferred size is up to date 1666 return fMinSize; 1667 } 1668 1669 font_height fontHeight; 1670 GetFontHeight(&fontHeight); 1671 1672 float width = 0.0f; 1673 float height = 0.0f; 1674 1675 if (fMaxUpdateTextWidth < 0.0f) 1676 fMaxUpdateTextWidth = MaxUpdateTextWidth(); 1677 1678 if (Orientation() == B_HORIZONTAL) { 1679 height = 12.0f + fBarThickness; 1680 int32 rows = 0; 1681 1682 float labelWidth = 0; 1683 int32 labelRows = 0; 1684 float labelSpacing = StringWidth("M") * 2; 1685 if (Label() != NULL) { 1686 labelWidth = StringWidth(Label()); 1687 labelRows = 1; 1688 } 1689 if (fMaxUpdateTextWidth > 0.0f) { 1690 if (labelWidth > 0) 1691 labelWidth += labelSpacing; 1692 1693 labelWidth += fMaxUpdateTextWidth; 1694 labelRows = 1; 1695 } 1696 rows += labelRows; 1697 1698 if (MinLimitLabel() != NULL) 1699 width = StringWidth(MinLimitLabel()); 1700 1701 if (MaxLimitLabel() != NULL) { 1702 // some space between the labels 1703 if (MinLimitLabel() != NULL) 1704 width += labelSpacing; 1705 1706 width += StringWidth(MaxLimitLabel()); 1707 } 1708 1709 if (labelWidth > width) 1710 width = labelWidth; 1711 1712 if (width < 32.0f) 1713 width = 32.0f; 1714 1715 if (MinLimitLabel() || MaxLimitLabel()) 1716 rows++; 1717 1718 height += rows * (ceilf(fontHeight.ascent) 1719 + ceilf(fontHeight.descent) + 4.0); 1720 } else { 1721 // B_VERTICAL 1722 width = 12.0f + fBarThickness; 1723 height = 32.0f; 1724 1725 float lineHeightNoLeading = ceilf(fontHeight.ascent) 1726 + ceilf(fontHeight.descent); 1727 float lineHeight = lineHeightNoLeading + ceilf(fontHeight.leading); 1728 1729 // find largest label 1730 float labelWidth = 0; 1731 if (Label() != NULL) { 1732 labelWidth = StringWidth(Label()); 1733 height += lineHeightNoLeading; 1734 } 1735 if (MaxLimitLabel() != NULL) { 1736 labelWidth = std::max(labelWidth, StringWidth(MaxLimitLabel())); 1737 height += Label() ? lineHeight : lineHeightNoLeading; 1738 } 1739 if (MinLimitLabel() != NULL) { 1740 labelWidth = std::max(labelWidth, StringWidth(MinLimitLabel())); 1741 height += lineHeightNoLeading; 1742 } 1743 if (fMaxUpdateTextWidth > 0.0f) { 1744 labelWidth = std::max(labelWidth, fMaxUpdateTextWidth); 1745 height += MinLimitLabel() ? lineHeight : lineHeightNoLeading; 1746 } 1747 1748 width = std::max(labelWidth, width); 1749 } 1750 1751 fMinSize.width = width; 1752 fMinSize.height = height; 1753 1754 ResetLayoutInvalidation(); 1755 1756 return fMinSize; 1757 } 1758 1759 1760 // #pragma mark - FBC padding 1761 1762 void BSlider::_ReservedSlider6() {} 1763 void BSlider::_ReservedSlider7() {} 1764 void BSlider::_ReservedSlider8() {} 1765 void BSlider::_ReservedSlider9() {} 1766 void BSlider::_ReservedSlider10() {} 1767 void BSlider::_ReservedSlider11() {} 1768 void BSlider::_ReservedSlider12() {} 1769 1770 1771 BSlider& 1772 BSlider::operator=(const BSlider&) 1773 { 1774 return *this; 1775 } 1776 1777 1778 // #pragma mark - BeOS compatibility 1779 1780 1781 #if __GNUC__ < 3 1782 1783 extern "C" void 1784 GetLimits__7BSliderPlT1(BSlider* slider, int32* minimum, int32* maximum) 1785 { 1786 slider->GetLimits(minimum, maximum); 1787 } 1788 1789 1790 extern "C" void 1791 _ReservedSlider4__7BSlider(BSlider* slider, int32 minimum, int32 maximum) 1792 { 1793 slider->BSlider::SetLimits(minimum, maximum); 1794 } 1795 1796 extern "C" float 1797 _ReservedSlider5__7BSlider(BSlider* slider) 1798 { 1799 return slider->BSlider::MaxUpdateTextWidth(); 1800 } 1801 1802 1803 extern "C" void 1804 _ReservedSlider1__7BSlider(BSlider* slider, orientation _orientation) 1805 { 1806 slider->BSlider::SetOrientation(_orientation); 1807 } 1808 1809 1810 extern "C" void 1811 _ReservedSlider2__7BSlider(BSlider* slider, float thickness) 1812 { 1813 slider->BSlider::SetBarThickness(thickness); 1814 } 1815 1816 1817 extern "C" void 1818 _ReservedSlider3__7BSlider(BSlider* slider, const BFont* font, 1819 uint32 properties) 1820 { 1821 slider->BSlider::SetFont(font, properties); 1822 } 1823 1824 1825 #endif // __GNUC__ < 3 1826 1827 1828 extern "C" void 1829 B_IF_GCC_2(InvalidateLayout__7BSliderb, _ZN7BSlider16InvalidateLayoutEb)( 1830 BView* view, bool descendants) 1831 { 1832 perform_data_layout_invalidated data; 1833 data.descendants = descendants; 1834 1835 view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data); 1836 } 1837