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