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