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, target, 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, target, 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 const BRect bounds = Bounds(); 275 276 if (fTarget != NULL && (fTarget->Flags() & B_SUPPORTS_LAYOUT) != 0 277 && (fTarget->Flags() & B_SCROLL_VIEW_AWARE) == 0) { 278 BSize size = fTarget->PreferredSize(); 279 if (fHorizontalScrollBar != NULL) { 280 float delta = size.Width() - bounds.Width(), 281 proportion = bounds.Width() / size.Width(); 282 if (delta < 0) 283 delta = 0; 284 285 fHorizontalScrollBar->SetRange(0, delta); 286 fHorizontalScrollBar->SetSteps(be_plain_font->Size() * 1.33, 287 bounds.Width()); 288 fHorizontalScrollBar->SetProportion(proportion); 289 } 290 if (fVerticalScrollBar != NULL) { 291 float delta = size.Height() - bounds.Height(), 292 proportion = bounds.Height() / size.Height(); 293 if (delta < 0) 294 delta = 0; 295 296 fVerticalScrollBar->SetRange(0, delta); 297 fVerticalScrollBar->SetSteps(be_plain_font->Size() * 1.33, 298 bounds.Height()); 299 fVerticalScrollBar->SetProportion(proportion); 300 } 301 } 302 303 if (fBorder == B_NO_BORDER) 304 return; 305 306 float border = _BorderSize() - 1; 307 308 if (fHorizontalScrollBar != NULL && fVerticalScrollBar != NULL) { 309 BRect scrollCorner(bounds); 310 scrollCorner.left = min_c( 311 fPreviousWidth - fVerticalScrollBar->Frame().Height(), 312 fHorizontalScrollBar->Frame().right + 1); 313 scrollCorner.top = min_c( 314 fPreviousHeight - fHorizontalScrollBar->Frame().Width(), 315 fVerticalScrollBar->Frame().bottom + 1); 316 Invalidate(scrollCorner); 317 } 318 319 // changes in newWidth 320 321 if (bounds.Width() > fPreviousWidth) { 322 // invalidate the region between the old and the new right border 323 BRect rect = bounds; 324 rect.left += fPreviousWidth - border; 325 rect.right--; 326 Invalidate(rect); 327 } else if (bounds.Width() < fPreviousWidth) { 328 // invalidate the region of the new right border 329 BRect rect = bounds; 330 rect.left = rect.right - border; 331 Invalidate(rect); 332 } 333 334 // changes in newHeight 335 336 if (bounds.Height() > fPreviousHeight) { 337 // invalidate the region between the old and the new bottom border 338 BRect rect = bounds; 339 rect.top += fPreviousHeight - border; 340 rect.bottom--; 341 Invalidate(rect); 342 } else if (bounds.Height() < fPreviousHeight) { 343 // invalidate the region of the new bottom border 344 BRect rect = bounds; 345 rect.top = rect.bottom - border; 346 Invalidate(rect); 347 } 348 349 fPreviousWidth = uint16(bounds.Width()); 350 fPreviousHeight = uint16(bounds.Height()); 351 } 352 353 354 void 355 BScrollView::MessageReceived(BMessage* message) 356 { 357 BView::MessageReceived(message); 358 } 359 360 361 void 362 BScrollView::MouseDown(BPoint where) 363 { 364 BView::MouseDown(where); 365 } 366 367 368 void 369 BScrollView::MouseMoved(BPoint where, uint32 code, 370 const BMessage* dragMessage) 371 { 372 BView::MouseMoved(where, code, dragMessage); 373 } 374 375 376 void 377 BScrollView::MouseUp(BPoint where) 378 { 379 BView::MouseUp(where); 380 } 381 382 383 void 384 BScrollView::WindowActivated(bool active) 385 { 386 if (fHighlighted) 387 Invalidate(); 388 389 BView::WindowActivated(active); 390 } 391 392 393 // #pragma mark - Size methods 394 395 396 void 397 BScrollView::GetPreferredSize(float* _width, float* _height) 398 { 399 BSize size = PreferredSize(); 400 401 if (_width) 402 *_width = size.width; 403 404 if (_height) 405 *_height = size.height; 406 } 407 408 409 void 410 BScrollView::ResizeToPreferred() 411 { 412 if (Window() == NULL) 413 return; 414 BView::ResizeToPreferred(); 415 } 416 417 418 void 419 BScrollView::MakeFocus(bool focus) 420 { 421 BView::MakeFocus(focus); 422 } 423 424 425 BSize 426 BScrollView::MinSize() 427 { 428 BSize size = _ComputeSize(fTarget != NULL ? fTarget->MinSize() 429 : BSize(16, 16)); 430 431 return BLayoutUtils::ComposeSize(ExplicitMinSize(), size); 432 } 433 434 435 BSize 436 BScrollView::MaxSize() 437 { 438 BSize size = _ComputeSize(fTarget != NULL ? fTarget->MaxSize() 439 : BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); 440 441 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), size); 442 } 443 444 445 BSize 446 BScrollView::PreferredSize() 447 { 448 BSize size = _ComputeSize(fTarget != NULL ? fTarget->PreferredSize() 449 : BSize(32, 32)); 450 451 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), size); 452 } 453 454 455 // #pragma mark - BScrollView methods 456 457 458 BScrollBar* 459 BScrollView::ScrollBar(orientation direction) const 460 { 461 if (direction == B_HORIZONTAL) 462 return fHorizontalScrollBar; 463 464 return fVerticalScrollBar; 465 } 466 467 468 void 469 BScrollView::SetBorder(border_style border) 470 { 471 if (fBorder == border) 472 return; 473 474 if ((Flags() & B_SUPPORTS_LAYOUT) != 0) { 475 fBorder = border; 476 SetFlags(_ModifyFlags(Flags(), fTarget, border)); 477 478 DoLayout(); 479 Invalidate(); 480 return; 481 } 482 483 float offset = _BorderSize() - _BorderSize(border); 484 float resize = 2 * offset; 485 486 float horizontalGap = 0, verticalGap = 0; 487 float change = 0; 488 if (border == B_NO_BORDER || fBorder == B_NO_BORDER) { 489 if (fHorizontalScrollBar != NULL) 490 verticalGap = border != B_NO_BORDER ? 1 : -1; 491 if (fVerticalScrollBar != NULL) 492 horizontalGap = border != B_NO_BORDER ? 1 : -1; 493 494 change = border != B_NO_BORDER ? -1 : 1; 495 if (fHorizontalScrollBar == NULL || fVerticalScrollBar == NULL) 496 change *= 2; 497 } 498 499 fBorder = border; 500 501 int32 savedResizingMode = 0; 502 if (fTarget != NULL) { 503 savedResizingMode = fTarget->ResizingMode(); 504 fTarget->SetResizingMode(B_FOLLOW_NONE); 505 } 506 507 MoveBy(offset, offset); 508 ResizeBy(-resize - horizontalGap, -resize - verticalGap); 509 510 if (fTarget != NULL) { 511 fTarget->MoveBy(-offset, -offset); 512 fTarget->SetResizingMode(savedResizingMode); 513 } 514 515 if (fHorizontalScrollBar != NULL) { 516 fHorizontalScrollBar->MoveBy(-offset - verticalGap, offset + verticalGap); 517 fHorizontalScrollBar->ResizeBy(resize + horizontalGap - change, 0); 518 } 519 if (fVerticalScrollBar != NULL) { 520 fVerticalScrollBar->MoveBy(offset + horizontalGap, -offset - horizontalGap); 521 fVerticalScrollBar->ResizeBy(0, resize + verticalGap - change); 522 } 523 524 SetFlags(_ModifyFlags(Flags(), fTarget, border)); 525 } 526 527 528 border_style 529 BScrollView::Border() const 530 { 531 return fBorder; 532 } 533 534 535 void 536 BScrollView::SetBorders(uint32 borders) 537 { 538 if (fBorders == borders || (Flags() & B_SUPPORTS_LAYOUT) == 0) 539 return; 540 541 fBorders = borders; 542 DoLayout(); 543 Invalidate(); 544 } 545 546 547 uint32 548 BScrollView::Borders() const 549 { 550 return fBorders; 551 } 552 553 554 status_t 555 BScrollView::SetBorderHighlighted(bool highlight) 556 { 557 if (fHighlighted == highlight) 558 return B_OK; 559 560 if (fBorder != B_FANCY_BORDER) 561 // highlighting only works for B_FANCY_BORDER 562 return B_ERROR; 563 564 fHighlighted = highlight; 565 566 if (fHorizontalScrollBar != NULL) 567 fHorizontalScrollBar->SetBorderHighlighted(highlight); 568 if (fVerticalScrollBar != NULL) 569 fVerticalScrollBar->SetBorderHighlighted(highlight); 570 571 BRect bounds = Bounds(); 572 bounds.InsetBy(1, 1); 573 574 Invalidate(BRect(bounds.left, bounds.top, bounds.right, bounds.top)); 575 Invalidate(BRect(bounds.left, bounds.top + 1, bounds.left, 576 bounds.bottom - 1)); 577 Invalidate(BRect(bounds.right, bounds.top + 1, bounds.right, 578 bounds.bottom - 1)); 579 Invalidate(BRect(bounds.left, bounds.bottom, bounds.right, bounds.bottom)); 580 581 return B_OK; 582 } 583 584 585 bool 586 BScrollView::IsBorderHighlighted() const 587 { 588 return fHighlighted; 589 } 590 591 592 void 593 BScrollView::SetTarget(BView* target) 594 { 595 if (fTarget == target) 596 return; 597 598 if (fTarget != NULL) { 599 fTarget->TargetedByScrollView(NULL); 600 RemoveChild(fTarget); 601 602 // we are not supposed to delete the view 603 } 604 605 fTarget = target; 606 if (fHorizontalScrollBar != NULL) 607 fHorizontalScrollBar->SetTarget(target); 608 if (fVerticalScrollBar != NULL) 609 fVerticalScrollBar->SetTarget(target); 610 611 if (target != NULL) { 612 float borderSize = _BorderSize(); 613 target->MoveTo((fBorders & BControlLook::B_LEFT_BORDER) != 0 614 ? borderSize : 0, (fBorders & BControlLook::B_TOP_BORDER) != 0 615 ? borderSize : 0); 616 BRect innerFrame = _InnerFrame(); 617 target->ResizeTo(innerFrame.Width() - 1, innerFrame.Height() - 1); 618 target->TargetedByScrollView(this); 619 620 AddChild(target, ChildAt(0)); 621 // This way, we are making sure that the target will 622 // be added top most in the list (which is important 623 // for unarchiving) 624 } 625 626 SetFlags(_ModifyFlags(Flags(), fTarget, fBorder)); 627 } 628 629 630 BView* 631 BScrollView::Target() const 632 { 633 return fTarget; 634 } 635 636 637 // #pragma mark - Scripting methods 638 639 640 641 BHandler* 642 BScrollView::ResolveSpecifier(BMessage* message, int32 index, 643 BMessage* specifier, int32 what, const char* property) 644 { 645 return BView::ResolveSpecifier(message, index, specifier, what, property); 646 } 647 648 649 status_t 650 BScrollView::GetSupportedSuites(BMessage* message) 651 { 652 return BView::GetSupportedSuites(message); 653 } 654 655 656 // #pragma mark - Perform 657 658 659 status_t 660 BScrollView::Perform(perform_code code, void* _data) 661 { 662 switch (code) { 663 case PERFORM_CODE_MIN_SIZE: 664 ((perform_data_min_size*)_data)->return_value 665 = BScrollView::MinSize(); 666 return B_OK; 667 668 case PERFORM_CODE_MAX_SIZE: 669 ((perform_data_max_size*)_data)->return_value 670 = BScrollView::MaxSize(); 671 return B_OK; 672 673 case PERFORM_CODE_PREFERRED_SIZE: 674 ((perform_data_preferred_size*)_data)->return_value 675 = BScrollView::PreferredSize(); 676 return B_OK; 677 678 case PERFORM_CODE_LAYOUT_ALIGNMENT: 679 ((perform_data_layout_alignment*)_data)->return_value 680 = BScrollView::LayoutAlignment(); 681 return B_OK; 682 683 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 684 ((perform_data_has_height_for_width*)_data)->return_value 685 = BScrollView::HasHeightForWidth(); 686 return B_OK; 687 688 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 689 { 690 perform_data_get_height_for_width* data 691 = (perform_data_get_height_for_width*)_data; 692 BScrollView::GetHeightForWidth(data->width, &data->min, &data->max, 693 &data->preferred); 694 return B_OK; 695 } 696 697 case PERFORM_CODE_SET_LAYOUT: 698 { 699 perform_data_set_layout* data = (perform_data_set_layout*)_data; 700 BScrollView::SetLayout(data->layout); 701 return B_OK; 702 } 703 704 case PERFORM_CODE_LAYOUT_INVALIDATED: 705 { 706 perform_data_layout_invalidated* data 707 = (perform_data_layout_invalidated*)_data; 708 BScrollView::LayoutInvalidated(data->descendants); 709 return B_OK; 710 } 711 712 case PERFORM_CODE_DO_LAYOUT: 713 { 714 BScrollView::DoLayout(); 715 return B_OK; 716 } 717 } 718 719 return BView::Perform(code, _data); 720 } 721 722 723 // #pragma mark - Protected methods 724 725 726 void 727 BScrollView::LayoutInvalidated(bool descendants) 728 { 729 } 730 731 732 void 733 BScrollView::DoLayout() 734 { 735 if ((Flags() & B_SUPPORTS_LAYOUT) == 0) 736 return; 737 738 // If the user set a layout, we let the base class version call its hook. 739 if (GetLayout() != NULL) { 740 BView::DoLayout(); 741 return; 742 } 743 744 BRect innerFrame = _InnerFrame(); 745 746 if (fTarget != NULL) { 747 fTarget->MoveTo(innerFrame.left, innerFrame.top); 748 fTarget->ResizeTo(innerFrame.Width(), innerFrame.Height()); 749 750 //BLayoutUtils::AlignInFrame(fTarget, fTarget->Bounds()); 751 } 752 753 _AlignScrollBars(fHorizontalScrollBar != NULL, fVerticalScrollBar != NULL, 754 innerFrame); 755 } 756 757 758 // #pragma mark - Private methods 759 760 761 void 762 BScrollView::_Init(bool horizontal, bool vertical) 763 { 764 fHorizontalScrollBar = NULL; 765 fVerticalScrollBar = NULL; 766 fHighlighted = false; 767 fBorders = BControlLook::B_ALL_BORDERS; 768 769 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 770 771 if (horizontal) { 772 fHorizontalScrollBar = new BScrollBar(BRect(0, 0, 14, 14), "_HSB_", 773 fTarget, 0, 1000, B_HORIZONTAL); 774 AddChild(fHorizontalScrollBar); 775 } 776 777 if (vertical) { 778 fVerticalScrollBar = new BScrollBar(BRect(0, 0, 14, 14), "_VSB_", 779 fTarget, 0, 1000, B_VERTICAL); 780 AddChild(fVerticalScrollBar); 781 } 782 783 BRect targetFrame; 784 if (fTarget) { 785 // layout target and add it 786 fTarget->TargetedByScrollView(this); 787 fTarget->MoveTo(B_ORIGIN); 788 789 if (fBorder != B_NO_BORDER) 790 fTarget->MoveBy(_BorderSize(), _BorderSize()); 791 792 AddChild(fTarget); 793 targetFrame = fTarget->Frame(); 794 } else { 795 // no target specified 796 targetFrame = Bounds(); 797 if (horizontal) 798 targetFrame.bottom -= B_H_SCROLL_BAR_HEIGHT + 1; 799 if (vertical) 800 targetFrame.right -= B_V_SCROLL_BAR_WIDTH + 1; 801 if (fBorder == B_FANCY_BORDER) { 802 targetFrame.bottom--; 803 targetFrame.right--; 804 } 805 } 806 807 _AlignScrollBars(horizontal, vertical, targetFrame); 808 809 fPreviousWidth = uint16(Bounds().Width()); 810 fPreviousHeight = uint16(Bounds().Height()); 811 } 812 813 814 float 815 BScrollView::_BorderSize() const 816 { 817 return _BorderSize(fBorder); 818 } 819 820 821 BRect 822 BScrollView::_InnerFrame() const 823 { 824 BRect frame = Bounds(); 825 _InsetBorders(frame, fBorder, fBorders); 826 827 float borderSize = _BorderSize(); 828 829 if (fHorizontalScrollBar != NULL) { 830 frame.bottom -= B_H_SCROLL_BAR_HEIGHT; 831 if (borderSize == 0) 832 frame.bottom--; 833 } 834 if (fVerticalScrollBar != NULL) { 835 frame.right -= B_V_SCROLL_BAR_WIDTH; 836 if (borderSize == 0) 837 frame.right--; 838 } 839 840 return frame; 841 } 842 843 844 BSize 845 BScrollView::_ComputeSize(BSize targetSize) const 846 { 847 BRect frame = _ComputeFrame( 848 BRect(0, 0, targetSize.width, targetSize.height)); 849 850 return BSize(frame.Width(), frame.Height()); 851 } 852 853 854 BRect 855 BScrollView::_ComputeFrame(BRect targetRect) const 856 { 857 return _ComputeFrame(targetRect, fHorizontalScrollBar != NULL, 858 fVerticalScrollBar != NULL, fBorder, fBorders); 859 } 860 861 862 void 863 BScrollView::_AlignScrollBars(bool horizontal, bool vertical, BRect targetFrame) 864 { 865 if (horizontal) { 866 BRect rect = targetFrame; 867 rect.top = rect.bottom + 1; 868 rect.bottom = rect.top + B_H_SCROLL_BAR_HEIGHT; 869 if (fBorder != B_NO_BORDER || vertical) { 870 // extend scrollbar so that it overlaps one pixel with vertical 871 // scrollbar 872 rect.right++; 873 } 874 875 if (fBorder != B_NO_BORDER) { 876 // the scrollbar draws part of the surrounding frame on the left 877 rect.left--; 878 } 879 880 fHorizontalScrollBar->MoveTo(rect.left, rect.top); 881 fHorizontalScrollBar->ResizeTo(rect.Width(), rect.Height()); 882 } 883 884 if (vertical) { 885 BRect rect = targetFrame; 886 rect.left = rect.right + 1; 887 rect.right = rect.left + B_V_SCROLL_BAR_WIDTH; 888 if (fBorder != B_NO_BORDER || horizontal) { 889 // extend scrollbar so that it overlaps one pixel with vertical 890 // scrollbar 891 rect.bottom++; 892 } 893 894 if (fBorder != B_NO_BORDER) { 895 // the scrollbar draws part of the surrounding frame on the left 896 rect.top--; 897 } 898 899 fVerticalScrollBar->MoveTo(rect.left, rect.top); 900 fVerticalScrollBar->ResizeTo(rect.Width(), rect.Height()); 901 } 902 } 903 904 905 /*! This static method is used to calculate the frame that the 906 ScrollView will cover depending on the frame of its target 907 and which border style is used. 908 It is used in the constructor and at other places. 909 */ 910 /*static*/ BRect 911 BScrollView::_ComputeFrame(BRect frame, bool horizontal, bool vertical, 912 border_style border, uint32 borders) 913 { 914 if (vertical) 915 frame.right += B_V_SCROLL_BAR_WIDTH; 916 if (horizontal) 917 frame.bottom += B_H_SCROLL_BAR_HEIGHT; 918 919 _InsetBorders(frame, border, borders, true); 920 921 if (_BorderSize(border) == 0) { 922 if (vertical) 923 frame.right++; 924 if (horizontal) 925 frame.bottom++; 926 } 927 928 return frame; 929 } 930 931 932 /*static*/ BRect 933 BScrollView::_ComputeFrame(BView *target, bool horizontal, bool vertical, 934 border_style border, uint32 borders) 935 { 936 return _ComputeFrame(target != NULL ? target->Frame() 937 : BRect(0, 0, 16, 16), horizontal, vertical, border, borders); 938 } 939 940 941 /*! This method returns the size of the specified border. 942 */ 943 /*static*/ float 944 BScrollView::_BorderSize(border_style border) 945 { 946 if (border == B_FANCY_BORDER) 947 return kFancyBorderSize; 948 if (border == B_PLAIN_BORDER) 949 return kPlainBorderSize; 950 951 return 0; 952 } 953 954 955 /*! This method changes the "flags" argument as passed on to 956 the BView constructor. 957 */ 958 /*static*/ uint32 959 BScrollView::_ModifyFlags(uint32 flags, BView* target, border_style border) 960 { 961 if (target != NULL && (target->Flags() & B_SUPPORTS_LAYOUT) != 0 962 && (target->Flags() & B_SCROLL_VIEW_AWARE) == 0) 963 flags |= B_FRAME_EVENTS; 964 965 // We either need B_FULL_UPDATE_ON_RESIZE or B_FRAME_EVENTS if we have 966 // to draw a border. 967 if (border != B_NO_BORDER) { 968 flags |= B_WILL_DRAW | ((flags & B_FULL_UPDATE_ON_RESIZE) != 0 ? 969 0 : B_FRAME_EVENTS); 970 } 971 972 return flags; 973 } 974 975 976 /*static*/ void 977 BScrollView::_InsetBorders(BRect& frame, border_style border, uint32 borders, bool expand) 978 { 979 float borderSize = _BorderSize(border); 980 if (expand) 981 borderSize = -borderSize; 982 if ((borders & BControlLook::B_LEFT_BORDER) != 0) 983 frame.left += borderSize; 984 if ((borders & BControlLook::B_TOP_BORDER) != 0) 985 frame.top += borderSize; 986 if ((borders & BControlLook::B_RIGHT_BORDER) != 0) 987 frame.right -= borderSize; 988 if ((borders & BControlLook::B_BOTTOM_BORDER) != 0) 989 frame.bottom -= borderSize; 990 } 991 992 993 // #pragma mark - FBC and forbidden 994 995 996 BScrollView& 997 BScrollView::operator=(const BScrollView &) 998 { 999 return *this; 1000 } 1001 1002 1003 void BScrollView::_ReservedScrollView1() {} 1004 void BScrollView::_ReservedScrollView2() {} 1005 void BScrollView::_ReservedScrollView3() {} 1006 void BScrollView::_ReservedScrollView4() {} 1007 1008 1009 extern "C" void 1010 B_IF_GCC_2(InvalidateLayout__11BScrollViewb, 1011 _ZN11BScrollView16InvalidateLayoutEb)(BScrollView* view, bool descendants) 1012 { 1013 perform_data_layout_invalidated data; 1014 data.descendants = descendants; 1015 1016 view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data); 1017 } 1018