1 /* 2 * Copyright 2004-2009, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2009 Stephan Aßmus, superstippi@gmx.de. 4 * Copyright 2014 Haiku, Inc. All rights reserved. 5 * Distributed under the terms of the MIT License. 6 * 7 * Authors: 8 * Stephan Aßmus, superstippi@gmx.de 9 * Axel Dörfler, axeld@pinc-software.de 10 * John Scipione, jscpione@gmail.com 11 */ 12 13 14 #include <ScrollView.h> 15 16 #include <ControlLook.h> 17 #include <LayoutUtils.h> 18 #include <Message.h> 19 #include <Region.h> 20 #include <Window.h> 21 22 #include <binary_compatibility/Interface.h> 23 24 25 static const float kFancyBorderSize = 2; 26 static const float kPlainBorderSize = 1; 27 28 29 BScrollView::BScrollView(const char* name, BView* target, uint32 resizingMode, 30 uint32 flags, bool horizontal, bool vertical, border_style border) 31 : 32 BView(_ComputeFrame(target, horizontal, vertical, border), name, 33 resizingMode, _ModifyFlags(flags, border)), 34 fTarget(target), 35 fBorder(border) 36 { 37 _Init(horizontal, vertical); 38 } 39 40 41 BScrollView::BScrollView(const char* name, BView* target, uint32 flags, 42 bool horizontal, bool vertical, border_style border) 43 : 44 BView(name, _ModifyFlags(flags, border)), 45 fTarget(target), 46 fBorder(border) 47 { 48 _Init(horizontal, vertical); 49 } 50 51 52 BScrollView::BScrollView(BMessage* archive) 53 : 54 BView(archive), 55 fHighlighted(false) 56 { 57 int32 border; 58 fBorder = archive->FindInt32("_style", &border) == B_OK ? 59 (border_style)border : B_FANCY_BORDER; 60 61 // in a shallow archive, we may not have a target anymore. We must 62 // be prepared for this case 63 64 // don't confuse our scroll bars with our (eventual) target 65 int32 firstBar = 0; 66 if (!archive->FindBool("_no_target_")) { 67 fTarget = ChildAt(0); 68 firstBar++; 69 } else 70 fTarget = NULL; 71 72 // search for our scroll bars 73 // This will not work for managed archives (when the layout kit is used). 74 // In that case the children are attached later, and we perform the search 75 // again in the AllUnarchived method. 76 77 fHorizontalScrollBar = NULL; 78 fVerticalScrollBar = NULL; 79 80 BView* view; 81 while ((view = ChildAt(firstBar++)) != NULL) { 82 BScrollBar *bar = dynamic_cast<BScrollBar *>(view); 83 if (bar == NULL) 84 continue; 85 86 if (bar->Orientation() == B_HORIZONTAL) 87 fHorizontalScrollBar = bar; 88 else if (bar->Orientation() == B_VERTICAL) 89 fVerticalScrollBar = bar; 90 } 91 92 fPreviousWidth = uint16(Bounds().Width()); 93 fPreviousHeight = uint16(Bounds().Height()); 94 95 } 96 97 98 BScrollView::~BScrollView() 99 { 100 } 101 102 103 // #pragma mark - Archiving 104 105 106 BArchivable* 107 BScrollView::Instantiate(BMessage* archive) 108 { 109 if (validate_instantiation(archive, "BScrollView")) 110 return new BScrollView(archive); 111 112 return NULL; 113 } 114 115 116 status_t 117 BScrollView::Archive(BMessage* archive, bool deep) const 118 { 119 status_t status = BView::Archive(archive, deep); 120 if (status != B_OK) 121 return status; 122 123 // If this is a deep archive, the BView class will take care 124 // of our children. 125 126 if (status == B_OK && fBorder != B_FANCY_BORDER) 127 status = archive->AddInt32("_style", fBorder); 128 if (status == B_OK && fTarget == NULL) 129 status = archive->AddBool("_no_target_", true); 130 131 // The highlighted state is not archived, but since it is 132 // usually (or should be) used to indicate focus, this 133 // is probably the right thing to do. 134 135 return status; 136 } 137 138 139 status_t 140 BScrollView::AllUnarchived(const BMessage* archive) 141 { 142 status_t result = BView::AllUnarchived(archive); 143 if (result != B_OK) 144 return result; 145 146 // search for our scroll bars and target 147 int32 firstBar = 0; 148 BView* view; 149 while ((view = ChildAt(firstBar++)) != NULL) { 150 BScrollBar *bar = dynamic_cast<BScrollBar *>(view); 151 // We assume that the first non-scrollbar child view is the target. 152 // So the target view can't be a BScrollBar, but who would do that? 153 if (bar == NULL) { 154 // in a shallow archive, we may not have a target anymore. We must 155 // be prepared for this case 156 if (fTarget == NULL && !archive->FindBool("_no_target_")) 157 fTarget = view; 158 continue; 159 } 160 161 if (bar->Orientation() == B_HORIZONTAL) 162 fHorizontalScrollBar = bar; 163 else if (bar->Orientation() == B_VERTICAL) 164 fVerticalScrollBar = bar; 165 } 166 167 // Now connect the bars to the target, and make the target aware of them 168 if (fHorizontalScrollBar) 169 fHorizontalScrollBar->SetTarget(fTarget); 170 if (fVerticalScrollBar) 171 fVerticalScrollBar->SetTarget(fTarget); 172 173 if (fTarget) 174 fTarget->TargetedByScrollView(this); 175 176 fPreviousWidth = uint16(Bounds().Width()); 177 fPreviousHeight = uint16(Bounds().Height()); 178 179 return B_OK; 180 } 181 182 183 // #pragma mark - Hook methods 184 185 186 void 187 BScrollView::AttachedToWindow() 188 { 189 BView::AttachedToWindow(); 190 191 if ((fHorizontalScrollBar == NULL && fVerticalScrollBar == NULL) 192 || (fHorizontalScrollBar != NULL && fVerticalScrollBar != NULL) 193 || Window()->Look() != B_DOCUMENT_WINDOW_LOOK) { 194 return; 195 } 196 197 // If we have only one bar, we need to check if we are in the 198 // bottom right edge of a window with the B_DOCUMENT_LOOK to 199 // adjust the size of the bar to acknowledge the resize knob. 200 201 BRect bounds = ConvertToScreen(Bounds()); 202 BRect windowBounds = Window()->Frame(); 203 204 if (bounds.right - _BorderSize() != windowBounds.right 205 || bounds.bottom - _BorderSize() != windowBounds.bottom) { 206 return; 207 } 208 209 if (fHorizontalScrollBar) 210 fHorizontalScrollBar->ResizeBy(-B_V_SCROLL_BAR_WIDTH, 0); 211 else if (fVerticalScrollBar) 212 fVerticalScrollBar->ResizeBy(0, -B_H_SCROLL_BAR_HEIGHT); 213 } 214 215 216 void 217 BScrollView::DetachedFromWindow() 218 { 219 BView::DetachedFromWindow(); 220 } 221 222 223 void 224 BScrollView::AllAttached() 225 { 226 BView::AllAttached(); 227 } 228 229 230 void 231 BScrollView::AllDetached() 232 { 233 BView::AllDetached(); 234 } 235 236 237 void 238 BScrollView::Draw(BRect updateRect) 239 { 240 uint32 flags = 0; 241 if (fHighlighted && Window()->IsActive()) 242 flags |= BControlLook::B_FOCUSED; 243 244 BRect rect(Bounds()); 245 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 246 247 BRect verticalScrollBarFrame(0, 0, -1, -1); 248 if (fVerticalScrollBar) 249 verticalScrollBarFrame = fVerticalScrollBar->Frame(); 250 251 BRect horizontalScrollBarFrame(0, 0, -1, -1); 252 if (fHorizontalScrollBar) 253 horizontalScrollBarFrame = fHorizontalScrollBar->Frame(); 254 255 be_control_look->DrawScrollViewFrame(this, rect, updateRect, 256 verticalScrollBarFrame, horizontalScrollBarFrame, base, fBorder, 257 flags); 258 } 259 260 261 void 262 BScrollView::FrameMoved(BPoint newPosition) 263 { 264 BView::FrameMoved(newPosition); 265 } 266 267 268 void 269 BScrollView::FrameResized(float newWidth, float newHeight) 270 { 271 BView::FrameResized(newWidth, newHeight); 272 273 if (fBorder == B_NO_BORDER) 274 return; 275 276 BRect bounds = Bounds(); 277 float border = _BorderSize() - 1; 278 279 if (be_control_look && fHorizontalScrollBar && fVerticalScrollBar) { 280 BRect scrollCorner(bounds); 281 scrollCorner.left = min_c( 282 fPreviousWidth - fVerticalScrollBar->Frame().Height(), 283 fHorizontalScrollBar->Frame().right + 1); 284 scrollCorner.top = min_c( 285 fPreviousHeight - fHorizontalScrollBar->Frame().Width(), 286 fVerticalScrollBar->Frame().bottom + 1); 287 Invalidate(scrollCorner); 288 } 289 290 // changes in newWidth 291 292 if (bounds.Width() > fPreviousWidth) { 293 // invalidate the region between the old and the new right border 294 BRect rect = bounds; 295 rect.left += fPreviousWidth - border; 296 rect.right--; 297 Invalidate(rect); 298 } else if (bounds.Width() < fPreviousWidth) { 299 // invalidate the region of the new right border 300 BRect rect = bounds; 301 rect.left = rect.right - border; 302 Invalidate(rect); 303 } 304 305 // changes in newHeight 306 307 if (bounds.Height() > fPreviousHeight) { 308 // invalidate the region between the old and the new bottom border 309 BRect rect = bounds; 310 rect.top += fPreviousHeight - border; 311 rect.bottom--; 312 Invalidate(rect); 313 } else if (bounds.Height() < fPreviousHeight) { 314 // invalidate the region of the new bottom border 315 BRect rect = bounds; 316 rect.top = rect.bottom - border; 317 Invalidate(rect); 318 } 319 320 fPreviousWidth = uint16(bounds.Width()); 321 fPreviousHeight = uint16(bounds.Height()); 322 } 323 324 325 void 326 BScrollView::MessageReceived(BMessage* message) 327 { 328 BView::MessageReceived(message); 329 } 330 331 332 void 333 BScrollView::MouseDown(BPoint where) 334 { 335 BView::MouseDown(where); 336 } 337 338 339 void 340 BScrollView::MouseMoved(BPoint where, uint32 code, 341 const BMessage* dragMessage) 342 { 343 BView::MouseMoved(where, code, dragMessage); 344 } 345 346 347 void 348 BScrollView::MouseUp(BPoint where) 349 { 350 BView::MouseUp(where); 351 } 352 353 354 void 355 BScrollView::WindowActivated(bool active) 356 { 357 if (fHighlighted) 358 Invalidate(); 359 360 BView::WindowActivated(active); 361 } 362 363 364 // #pragma mark - Size methods 365 366 367 void 368 BScrollView::GetPreferredSize(float* _width, float* _height) 369 { 370 BSize size = PreferredSize(); 371 372 if (_width) 373 *_width = size.width; 374 375 if (_height) 376 *_height = size.height; 377 } 378 379 380 void 381 BScrollView::ResizeToPreferred() 382 { 383 if (Window() == NULL) 384 return; 385 BView::ResizeToPreferred(); 386 } 387 388 389 void 390 BScrollView::MakeFocus(bool focus) 391 { 392 BView::MakeFocus(focus); 393 } 394 395 396 BSize 397 BScrollView::MinSize() 398 { 399 BSize size = _ComputeSize(fTarget != NULL ? fTarget->MinSize() 400 : BSize(16, 16)); 401 402 return BLayoutUtils::ComposeSize(ExplicitMinSize(), size); 403 } 404 405 406 BSize 407 BScrollView::MaxSize() 408 { 409 BSize size = _ComputeSize(fTarget != NULL ? fTarget->MaxSize() 410 : BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); 411 412 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), size); 413 } 414 415 416 BSize 417 BScrollView::PreferredSize() 418 { 419 BSize size = _ComputeSize(fTarget != NULL ? fTarget->PreferredSize() 420 : BSize(32, 32)); 421 422 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), size); 423 } 424 425 426 // #pragma mark - BScrollView methods 427 428 429 BScrollBar* 430 BScrollView::ScrollBar(orientation direction) const 431 { 432 if (direction == B_HORIZONTAL) 433 return fHorizontalScrollBar; 434 435 return fVerticalScrollBar; 436 } 437 438 439 void 440 BScrollView::SetBorder(border_style border) 441 { 442 if (fBorder == border) 443 return; 444 445 if (Flags() & B_SUPPORTS_LAYOUT) { 446 fBorder = border; 447 SetFlags(_ModifyFlags(Flags(), border)); 448 449 DoLayout(); 450 451 BRect bounds(Bounds()); 452 Invalidate(BRect(bounds.LeftTop(), bounds.RightBottom())); 453 Invalidate(BRect(bounds.LeftBottom(), bounds.RightBottom())); 454 return; 455 } 456 457 float offset = _BorderSize() - _BorderSize(border); 458 float resize = 2 * offset; 459 460 float horizontalGap = 0, verticalGap = 0; 461 float change = 0; 462 if (border == B_NO_BORDER || fBorder == B_NO_BORDER) { 463 if (fHorizontalScrollBar != NULL) 464 verticalGap = border != B_NO_BORDER ? 1 : -1; 465 if (fVerticalScrollBar != NULL) 466 horizontalGap = border != B_NO_BORDER ? 1 : -1; 467 468 change = border != B_NO_BORDER ? -1 : 1; 469 if (fHorizontalScrollBar == NULL || fVerticalScrollBar == NULL) 470 change *= 2; 471 } 472 473 fBorder = border; 474 475 int32 savedResizingMode = 0; 476 if (fTarget != NULL) { 477 savedResizingMode = fTarget->ResizingMode(); 478 fTarget->SetResizingMode(B_FOLLOW_NONE); 479 } 480 481 MoveBy(offset, offset); 482 ResizeBy(-resize - horizontalGap, -resize - verticalGap); 483 484 if (fTarget != NULL) { 485 fTarget->MoveBy(-offset, -offset); 486 fTarget->SetResizingMode(savedResizingMode); 487 } 488 489 if (fHorizontalScrollBar != NULL) { 490 fHorizontalScrollBar->MoveBy(-offset - verticalGap, offset + verticalGap); 491 fHorizontalScrollBar->ResizeBy(resize + horizontalGap - change, 0); 492 } 493 if (fVerticalScrollBar != NULL) { 494 fVerticalScrollBar->MoveBy(offset + horizontalGap, -offset - horizontalGap); 495 fVerticalScrollBar->ResizeBy(0, resize + verticalGap - change); 496 } 497 498 SetFlags(_ModifyFlags(Flags(), border)); 499 } 500 501 502 border_style 503 BScrollView::Border() const 504 { 505 return fBorder; 506 } 507 508 509 status_t 510 BScrollView::SetBorderHighlighted(bool highlight) 511 { 512 if (fHighlighted == highlight) 513 return B_OK; 514 515 if (fBorder != B_FANCY_BORDER) 516 // highlighting only works for B_FANCY_BORDER 517 return B_ERROR; 518 519 fHighlighted = highlight; 520 521 if (fHorizontalScrollBar != NULL) 522 fHorizontalScrollBar->SetBorderHighlighted(highlight); 523 if (fVerticalScrollBar != NULL) 524 fVerticalScrollBar->SetBorderHighlighted(highlight); 525 526 BRect bounds = Bounds(); 527 if (be_control_look != NULL) 528 bounds.InsetBy(1, 1); 529 530 Invalidate(BRect(bounds.left, bounds.top, bounds.right, bounds.top)); 531 Invalidate(BRect(bounds.left, bounds.top + 1, bounds.left, 532 bounds.bottom - 1)); 533 Invalidate(BRect(bounds.right, bounds.top + 1, bounds.right, 534 bounds.bottom - 1)); 535 Invalidate(BRect(bounds.left, bounds.bottom, bounds.right, bounds.bottom)); 536 537 return B_OK; 538 } 539 540 541 bool 542 BScrollView::IsBorderHighlighted() const 543 { 544 return fHighlighted; 545 } 546 547 548 void 549 BScrollView::SetTarget(BView* target) 550 { 551 if (fTarget == target) 552 return; 553 554 if (fTarget != NULL) { 555 fTarget->TargetedByScrollView(NULL); 556 RemoveChild(fTarget); 557 558 // we are not supposed to delete the view 559 } 560 561 fTarget = target; 562 if (fHorizontalScrollBar != NULL) 563 fHorizontalScrollBar->SetTarget(target); 564 if (fVerticalScrollBar != NULL) 565 fVerticalScrollBar->SetTarget(target); 566 567 if (target != NULL) { 568 target->MoveTo(_BorderSize(), _BorderSize()); 569 BRect innerFrame = _InnerFrame(); 570 target->ResizeTo(innerFrame.Width() - 1, innerFrame.Height() - 1); 571 target->TargetedByScrollView(this); 572 573 AddChild(target, ChildAt(0)); 574 // This way, we are making sure that the target will 575 // be added top most in the list (which is important 576 // for unarchiving) 577 } 578 } 579 580 581 BView* 582 BScrollView::Target() const 583 { 584 return fTarget; 585 } 586 587 588 // #pragma mark - Scripting methods 589 590 591 592 BHandler* 593 BScrollView::ResolveSpecifier(BMessage* message, int32 index, 594 BMessage* specifier, int32 what, const char* property) 595 { 596 return BView::ResolveSpecifier(message, index, specifier, what, property); 597 } 598 599 600 status_t 601 BScrollView::GetSupportedSuites(BMessage* message) 602 { 603 return BView::GetSupportedSuites(message); 604 } 605 606 607 // #pragma mark - Perform 608 609 610 status_t 611 BScrollView::Perform(perform_code code, void* _data) 612 { 613 switch (code) { 614 case PERFORM_CODE_MIN_SIZE: 615 ((perform_data_min_size*)_data)->return_value 616 = BScrollView::MinSize(); 617 return B_OK; 618 619 case PERFORM_CODE_MAX_SIZE: 620 ((perform_data_max_size*)_data)->return_value 621 = BScrollView::MaxSize(); 622 return B_OK; 623 624 case PERFORM_CODE_PREFERRED_SIZE: 625 ((perform_data_preferred_size*)_data)->return_value 626 = BScrollView::PreferredSize(); 627 return B_OK; 628 629 case PERFORM_CODE_LAYOUT_ALIGNMENT: 630 ((perform_data_layout_alignment*)_data)->return_value 631 = BScrollView::LayoutAlignment(); 632 return B_OK; 633 634 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 635 ((perform_data_has_height_for_width*)_data)->return_value 636 = BScrollView::HasHeightForWidth(); 637 return B_OK; 638 639 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 640 { 641 perform_data_get_height_for_width* data 642 = (perform_data_get_height_for_width*)_data; 643 BScrollView::GetHeightForWidth(data->width, &data->min, &data->max, 644 &data->preferred); 645 return B_OK; 646 } 647 648 case PERFORM_CODE_SET_LAYOUT: 649 { 650 perform_data_set_layout* data = (perform_data_set_layout*)_data; 651 BScrollView::SetLayout(data->layout); 652 return B_OK; 653 } 654 655 case PERFORM_CODE_LAYOUT_INVALIDATED: 656 { 657 perform_data_layout_invalidated* data 658 = (perform_data_layout_invalidated*)_data; 659 BScrollView::LayoutInvalidated(data->descendants); 660 return B_OK; 661 } 662 663 case PERFORM_CODE_DO_LAYOUT: 664 { 665 BScrollView::DoLayout(); 666 return B_OK; 667 } 668 } 669 670 return BView::Perform(code, _data); 671 } 672 673 674 // #pragma mark - Protected methods 675 676 677 void 678 BScrollView::LayoutInvalidated(bool descendants) 679 { 680 } 681 682 683 void 684 BScrollView::DoLayout() 685 { 686 if ((Flags() & B_SUPPORTS_LAYOUT) == 0) 687 return; 688 689 // If the user set a layout, we let the base class version call its hook. 690 if (GetLayout() != NULL) { 691 BView::DoLayout(); 692 return; 693 } 694 695 BRect innerFrame = _InnerFrame(); 696 697 if (fTarget != NULL) { 698 fTarget->MoveTo(innerFrame.left, innerFrame.top); 699 fTarget->ResizeTo(innerFrame.Width(), innerFrame.Height()); 700 701 //BLayoutUtils::AlignInFrame(fTarget, fTarget->Bounds()); 702 } 703 704 _AlignScrollBars(fHorizontalScrollBar != NULL, fVerticalScrollBar != NULL, 705 innerFrame); 706 } 707 708 709 // #pragma mark - Private methods 710 711 712 void 713 BScrollView::_Init(bool horizontal, bool vertical) 714 { 715 fHorizontalScrollBar = NULL; 716 fVerticalScrollBar = NULL; 717 fHighlighted = false; 718 719 if (be_control_look != NULL) 720 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 721 722 if (horizontal) { 723 fHorizontalScrollBar = new BScrollBar(BRect(0, 0, 14, 14), "_HSB_", 724 fTarget, 0, 1000, B_HORIZONTAL); 725 AddChild(fHorizontalScrollBar); 726 } 727 728 if (vertical) { 729 fVerticalScrollBar = new BScrollBar(BRect(0, 0, 14, 14), "_VSB_", 730 fTarget, 0, 1000, B_VERTICAL); 731 AddChild(fVerticalScrollBar); 732 } 733 734 BRect targetFrame; 735 if (fTarget) { 736 // layout target and add it 737 fTarget->TargetedByScrollView(this); 738 fTarget->MoveTo(B_ORIGIN); 739 740 if (fBorder != B_NO_BORDER) 741 fTarget->MoveBy(_BorderSize(), _BorderSize()); 742 743 AddChild(fTarget); 744 targetFrame = fTarget->Frame(); 745 } else { 746 // no target specified 747 targetFrame = Bounds(); 748 if (horizontal) 749 targetFrame.bottom -= B_H_SCROLL_BAR_HEIGHT + 1; 750 if (vertical) 751 targetFrame.right -= B_V_SCROLL_BAR_WIDTH + 1; 752 if (fBorder == B_FANCY_BORDER) { 753 targetFrame.bottom--; 754 targetFrame.right--; 755 } 756 } 757 758 _AlignScrollBars(horizontal, vertical, targetFrame); 759 760 fPreviousWidth = uint16(Bounds().Width()); 761 fPreviousHeight = uint16(Bounds().Height()); 762 } 763 764 765 float 766 BScrollView::_BorderSize() const 767 { 768 return _BorderSize(fBorder); 769 } 770 771 772 BRect 773 BScrollView::_InnerFrame() const 774 { 775 BRect frame = Bounds(); 776 777 float borderSize = _BorderSize(); 778 frame.InsetBy(borderSize, borderSize); 779 780 if (fHorizontalScrollBar != NULL) { 781 frame.bottom -= B_H_SCROLL_BAR_HEIGHT; 782 if (borderSize == 0) 783 frame.bottom--; 784 } 785 if (fVerticalScrollBar != NULL) { 786 frame.right -= B_V_SCROLL_BAR_WIDTH; 787 if (borderSize == 0) 788 frame.right--; 789 } 790 791 return frame; 792 } 793 794 795 BSize 796 BScrollView::_ComputeSize(BSize targetSize) const 797 { 798 BRect frame = _ComputeFrame( 799 BRect(0, 0, targetSize.width, targetSize.height)); 800 801 return BSize(frame.Width(), frame.Height()); 802 } 803 804 805 BRect 806 BScrollView::_ComputeFrame(BRect targetRect) const 807 { 808 return _ComputeFrame(targetRect, fHorizontalScrollBar != NULL, 809 fVerticalScrollBar != NULL, fBorder); 810 } 811 812 813 void 814 BScrollView::_AlignScrollBars(bool horizontal, bool vertical, BRect targetFrame) 815 { 816 if (horizontal) { 817 BRect rect = targetFrame; 818 rect.top = rect.bottom + 1; 819 rect.bottom = rect.top + B_H_SCROLL_BAR_HEIGHT; 820 if (fBorder != B_NO_BORDER || vertical) { 821 // extend scrollbar so that it overlaps one pixel with vertical 822 // scrollbar 823 rect.right++; 824 } 825 826 if (fBorder != B_NO_BORDER) { 827 // the scrollbar draws part of the surrounding frame on the left 828 rect.left--; 829 } 830 831 fHorizontalScrollBar->MoveTo(rect.left, rect.top); 832 fHorizontalScrollBar->ResizeTo(rect.Width(), rect.Height()); 833 } 834 835 if (vertical) { 836 BRect rect = targetFrame; 837 rect.left = rect.right + 1; 838 rect.right = rect.left + B_V_SCROLL_BAR_WIDTH; 839 if (fBorder != B_NO_BORDER || horizontal) { 840 // extend scrollbar so that it overlaps one pixel with vertical 841 // scrollbar 842 rect.bottom++; 843 } 844 845 if (fBorder != B_NO_BORDER) { 846 // the scrollbar draws part of the surrounding frame on the left 847 rect.top--; 848 } 849 850 fVerticalScrollBar->MoveTo(rect.left, rect.top); 851 fVerticalScrollBar->ResizeTo(rect.Width(), rect.Height()); 852 } 853 } 854 855 856 /*! This static method is used to calculate the frame that the 857 ScrollView will cover depending on the frame of its target 858 and which border style is used. 859 It is used in the constructor and at other places. 860 */ 861 /*static*/ BRect 862 BScrollView::_ComputeFrame(BRect frame, bool horizontal, bool vertical, 863 border_style border) 864 { 865 if (vertical) 866 frame.right += B_V_SCROLL_BAR_WIDTH; 867 if (horizontal) 868 frame.bottom += B_H_SCROLL_BAR_HEIGHT; 869 870 float borderSize = _BorderSize(border); 871 frame.InsetBy(-borderSize, -borderSize); 872 873 if (borderSize == 0) { 874 if (vertical) 875 frame.right++; 876 if (horizontal) 877 frame.bottom++; 878 } 879 880 return frame; 881 } 882 883 884 /*static*/ BRect 885 BScrollView::_ComputeFrame(BView *target, bool horizontal, bool vertical, 886 border_style border) 887 { 888 return _ComputeFrame(target != NULL ? target->Frame() 889 : BRect(0, 0, 16, 16), horizontal, vertical, border); 890 } 891 892 893 /*! This method returns the size of the specified border. 894 */ 895 /*static*/ float 896 BScrollView::_BorderSize(border_style border) 897 { 898 if (border == B_FANCY_BORDER) 899 return kFancyBorderSize; 900 if (border == B_PLAIN_BORDER) 901 return kPlainBorderSize; 902 903 return 0; 904 } 905 906 907 /*! This method changes the "flags" argument as passed on to 908 the BView constructor. 909 */ 910 /*static*/ int32 911 BScrollView::_ModifyFlags(int32 flags, border_style border) 912 { 913 // We either need B_FULL_UPDATE_ON_RESIZE or 914 // B_FRAME_EVENTS if we have to draw a border 915 if (border != B_NO_BORDER) 916 return flags | B_WILL_DRAW | (flags & B_FULL_UPDATE_ON_RESIZE ? 0 : B_FRAME_EVENTS); 917 918 return flags & ~(B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE); 919 } 920 921 922 // #pragma mark - FBC and forbidden 923 924 925 BScrollView& 926 BScrollView::operator=(const BScrollView &) 927 { 928 return *this; 929 } 930 931 932 void BScrollView::_ReservedScrollView1() {} 933 void BScrollView::_ReservedScrollView2() {} 934 void BScrollView::_ReservedScrollView3() {} 935 void BScrollView::_ReservedScrollView4() {} 936 937 938 extern "C" void 939 B_IF_GCC_2(InvalidateLayout__11BScrollViewb, 940 _ZN11BScrollView16InvalidateLayoutEb)(BScrollView* view, bool descendants) 941 { 942 perform_data_layout_invalidated data; 943 data.descendants = descendants; 944 945 view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data); 946 } 947