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 if (be_control_look != NULL) 545 bounds.InsetBy(1, 1); 546 547 Invalidate(BRect(bounds.left, bounds.top, bounds.right, bounds.top)); 548 Invalidate(BRect(bounds.left, bounds.top + 1, bounds.left, 549 bounds.bottom - 1)); 550 Invalidate(BRect(bounds.right, bounds.top + 1, bounds.right, 551 bounds.bottom - 1)); 552 Invalidate(BRect(bounds.left, bounds.bottom, bounds.right, bounds.bottom)); 553 554 return B_OK; 555 } 556 557 558 bool 559 BScrollView::IsBorderHighlighted() const 560 { 561 return fHighlighted; 562 } 563 564 565 void 566 BScrollView::SetTarget(BView* target) 567 { 568 if (fTarget == target) 569 return; 570 571 if (fTarget != NULL) { 572 fTarget->TargetedByScrollView(NULL); 573 RemoveChild(fTarget); 574 575 // we are not supposed to delete the view 576 } 577 578 fTarget = target; 579 if (fHorizontalScrollBar != NULL) 580 fHorizontalScrollBar->SetTarget(target); 581 if (fVerticalScrollBar != NULL) 582 fVerticalScrollBar->SetTarget(target); 583 584 if (target != NULL) { 585 float borderSize = _BorderSize(); 586 target->MoveTo((fBorders & BControlLook::B_LEFT_BORDER) != 0 587 ? borderSize : 0, (fBorders & BControlLook::B_TOP_BORDER) != 0 588 ? borderSize : 0); 589 BRect innerFrame = _InnerFrame(); 590 target->ResizeTo(innerFrame.Width() - 1, innerFrame.Height() - 1); 591 target->TargetedByScrollView(this); 592 593 AddChild(target, ChildAt(0)); 594 // This way, we are making sure that the target will 595 // be added top most in the list (which is important 596 // for unarchiving) 597 } 598 } 599 600 601 BView* 602 BScrollView::Target() const 603 { 604 return fTarget; 605 } 606 607 608 // #pragma mark - Scripting methods 609 610 611 612 BHandler* 613 BScrollView::ResolveSpecifier(BMessage* message, int32 index, 614 BMessage* specifier, int32 what, const char* property) 615 { 616 return BView::ResolveSpecifier(message, index, specifier, what, property); 617 } 618 619 620 status_t 621 BScrollView::GetSupportedSuites(BMessage* message) 622 { 623 return BView::GetSupportedSuites(message); 624 } 625 626 627 // #pragma mark - Perform 628 629 630 status_t 631 BScrollView::Perform(perform_code code, void* _data) 632 { 633 switch (code) { 634 case PERFORM_CODE_MIN_SIZE: 635 ((perform_data_min_size*)_data)->return_value 636 = BScrollView::MinSize(); 637 return B_OK; 638 639 case PERFORM_CODE_MAX_SIZE: 640 ((perform_data_max_size*)_data)->return_value 641 = BScrollView::MaxSize(); 642 return B_OK; 643 644 case PERFORM_CODE_PREFERRED_SIZE: 645 ((perform_data_preferred_size*)_data)->return_value 646 = BScrollView::PreferredSize(); 647 return B_OK; 648 649 case PERFORM_CODE_LAYOUT_ALIGNMENT: 650 ((perform_data_layout_alignment*)_data)->return_value 651 = BScrollView::LayoutAlignment(); 652 return B_OK; 653 654 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 655 ((perform_data_has_height_for_width*)_data)->return_value 656 = BScrollView::HasHeightForWidth(); 657 return B_OK; 658 659 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 660 { 661 perform_data_get_height_for_width* data 662 = (perform_data_get_height_for_width*)_data; 663 BScrollView::GetHeightForWidth(data->width, &data->min, &data->max, 664 &data->preferred); 665 return B_OK; 666 } 667 668 case PERFORM_CODE_SET_LAYOUT: 669 { 670 perform_data_set_layout* data = (perform_data_set_layout*)_data; 671 BScrollView::SetLayout(data->layout); 672 return B_OK; 673 } 674 675 case PERFORM_CODE_LAYOUT_INVALIDATED: 676 { 677 perform_data_layout_invalidated* data 678 = (perform_data_layout_invalidated*)_data; 679 BScrollView::LayoutInvalidated(data->descendants); 680 return B_OK; 681 } 682 683 case PERFORM_CODE_DO_LAYOUT: 684 { 685 BScrollView::DoLayout(); 686 return B_OK; 687 } 688 } 689 690 return BView::Perform(code, _data); 691 } 692 693 694 // #pragma mark - Protected methods 695 696 697 void 698 BScrollView::LayoutInvalidated(bool descendants) 699 { 700 } 701 702 703 void 704 BScrollView::DoLayout() 705 { 706 if ((Flags() & B_SUPPORTS_LAYOUT) == 0) 707 return; 708 709 // If the user set a layout, we let the base class version call its hook. 710 if (GetLayout() != NULL) { 711 BView::DoLayout(); 712 return; 713 } 714 715 BRect innerFrame = _InnerFrame(); 716 717 if (fTarget != NULL) { 718 fTarget->MoveTo(innerFrame.left, innerFrame.top); 719 fTarget->ResizeTo(innerFrame.Width(), innerFrame.Height()); 720 721 //BLayoutUtils::AlignInFrame(fTarget, fTarget->Bounds()); 722 } 723 724 _AlignScrollBars(fHorizontalScrollBar != NULL, fVerticalScrollBar != NULL, 725 innerFrame); 726 } 727 728 729 // #pragma mark - Private methods 730 731 732 void 733 BScrollView::_Init(bool horizontal, bool vertical) 734 { 735 fHorizontalScrollBar = NULL; 736 fVerticalScrollBar = NULL; 737 fHighlighted = false; 738 fBorders = BControlLook::B_ALL_BORDERS; 739 740 if (be_control_look != NULL) 741 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 742 743 if (horizontal) { 744 fHorizontalScrollBar = new BScrollBar(BRect(0, 0, 14, 14), "_HSB_", 745 fTarget, 0, 1000, B_HORIZONTAL); 746 AddChild(fHorizontalScrollBar); 747 } 748 749 if (vertical) { 750 fVerticalScrollBar = new BScrollBar(BRect(0, 0, 14, 14), "_VSB_", 751 fTarget, 0, 1000, B_VERTICAL); 752 AddChild(fVerticalScrollBar); 753 } 754 755 BRect targetFrame; 756 if (fTarget) { 757 // layout target and add it 758 fTarget->TargetedByScrollView(this); 759 fTarget->MoveTo(B_ORIGIN); 760 761 if (fBorder != B_NO_BORDER) 762 fTarget->MoveBy(_BorderSize(), _BorderSize()); 763 764 AddChild(fTarget); 765 targetFrame = fTarget->Frame(); 766 } else { 767 // no target specified 768 targetFrame = Bounds(); 769 if (horizontal) 770 targetFrame.bottom -= B_H_SCROLL_BAR_HEIGHT + 1; 771 if (vertical) 772 targetFrame.right -= B_V_SCROLL_BAR_WIDTH + 1; 773 if (fBorder == B_FANCY_BORDER) { 774 targetFrame.bottom--; 775 targetFrame.right--; 776 } 777 } 778 779 _AlignScrollBars(horizontal, vertical, targetFrame); 780 781 fPreviousWidth = uint16(Bounds().Width()); 782 fPreviousHeight = uint16(Bounds().Height()); 783 } 784 785 786 float 787 BScrollView::_BorderSize() const 788 { 789 return _BorderSize(fBorder); 790 } 791 792 793 BRect 794 BScrollView::_InnerFrame() const 795 { 796 BRect frame = Bounds(); 797 _InsetBorders(frame, fBorder, fBorders); 798 799 float borderSize = _BorderSize(); 800 801 if (fHorizontalScrollBar != NULL) { 802 frame.bottom -= B_H_SCROLL_BAR_HEIGHT; 803 if (borderSize == 0) 804 frame.bottom--; 805 } 806 if (fVerticalScrollBar != NULL) { 807 frame.right -= B_V_SCROLL_BAR_WIDTH; 808 if (borderSize == 0) 809 frame.right--; 810 } 811 812 return frame; 813 } 814 815 816 BSize 817 BScrollView::_ComputeSize(BSize targetSize) const 818 { 819 BRect frame = _ComputeFrame( 820 BRect(0, 0, targetSize.width, targetSize.height)); 821 822 return BSize(frame.Width(), frame.Height()); 823 } 824 825 826 BRect 827 BScrollView::_ComputeFrame(BRect targetRect) const 828 { 829 return _ComputeFrame(targetRect, fHorizontalScrollBar != NULL, 830 fVerticalScrollBar != NULL, fBorder, fBorders); 831 } 832 833 834 void 835 BScrollView::_AlignScrollBars(bool horizontal, bool vertical, BRect targetFrame) 836 { 837 if (horizontal) { 838 BRect rect = targetFrame; 839 rect.top = rect.bottom + 1; 840 rect.bottom = rect.top + B_H_SCROLL_BAR_HEIGHT; 841 if (fBorder != B_NO_BORDER || vertical) { 842 // extend scrollbar so that it overlaps one pixel with vertical 843 // scrollbar 844 rect.right++; 845 } 846 847 if (fBorder != B_NO_BORDER) { 848 // the scrollbar draws part of the surrounding frame on the left 849 rect.left--; 850 } 851 852 fHorizontalScrollBar->MoveTo(rect.left, rect.top); 853 fHorizontalScrollBar->ResizeTo(rect.Width(), rect.Height()); 854 } 855 856 if (vertical) { 857 BRect rect = targetFrame; 858 rect.left = rect.right + 1; 859 rect.right = rect.left + B_V_SCROLL_BAR_WIDTH; 860 if (fBorder != B_NO_BORDER || horizontal) { 861 // extend scrollbar so that it overlaps one pixel with vertical 862 // scrollbar 863 rect.bottom++; 864 } 865 866 if (fBorder != B_NO_BORDER) { 867 // the scrollbar draws part of the surrounding frame on the left 868 rect.top--; 869 } 870 871 fVerticalScrollBar->MoveTo(rect.left, rect.top); 872 fVerticalScrollBar->ResizeTo(rect.Width(), rect.Height()); 873 } 874 } 875 876 877 /*! This static method is used to calculate the frame that the 878 ScrollView will cover depending on the frame of its target 879 and which border style is used. 880 It is used in the constructor and at other places. 881 */ 882 /*static*/ BRect 883 BScrollView::_ComputeFrame(BRect frame, bool horizontal, bool vertical, 884 border_style border, uint32 borders) 885 { 886 if (vertical) 887 frame.right += B_V_SCROLL_BAR_WIDTH; 888 if (horizontal) 889 frame.bottom += B_H_SCROLL_BAR_HEIGHT; 890 891 _InsetBorders(frame, border, borders, true); 892 893 if (_BorderSize(border) == 0) { 894 if (vertical) 895 frame.right++; 896 if (horizontal) 897 frame.bottom++; 898 } 899 900 return frame; 901 } 902 903 904 /*static*/ BRect 905 BScrollView::_ComputeFrame(BView *target, bool horizontal, bool vertical, 906 border_style border, uint32 borders) 907 { 908 return _ComputeFrame(target != NULL ? target->Frame() 909 : BRect(0, 0, 16, 16), horizontal, vertical, border, borders); 910 } 911 912 913 /*! This method returns the size of the specified border. 914 */ 915 /*static*/ float 916 BScrollView::_BorderSize(border_style border) 917 { 918 if (border == B_FANCY_BORDER) 919 return kFancyBorderSize; 920 if (border == B_PLAIN_BORDER) 921 return kPlainBorderSize; 922 923 return 0; 924 } 925 926 927 /*! This method changes the "flags" argument as passed on to 928 the BView constructor. 929 */ 930 /*static*/ int32 931 BScrollView::_ModifyFlags(int32 flags, border_style border) 932 { 933 // We either need B_FULL_UPDATE_ON_RESIZE or 934 // B_FRAME_EVENTS if we have to draw a border 935 if (border != B_NO_BORDER) 936 return flags | B_WILL_DRAW | (flags & B_FULL_UPDATE_ON_RESIZE ? 0 : B_FRAME_EVENTS); 937 938 return flags & ~(B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE); 939 } 940 941 942 /*static*/ void 943 BScrollView::_InsetBorders(BRect& frame, border_style border, uint32 borders, bool expand) 944 { 945 float borderSize = _BorderSize(border); 946 if (expand) 947 borderSize = -borderSize; 948 if ((borders & BControlLook::B_LEFT_BORDER) != 0) 949 frame.left += borderSize; 950 if ((borders & BControlLook::B_TOP_BORDER) != 0) 951 frame.top += borderSize; 952 if ((borders & BControlLook::B_RIGHT_BORDER) != 0) 953 frame.right -= borderSize; 954 if ((borders & BControlLook::B_BOTTOM_BORDER) != 0) 955 frame.bottom -= borderSize; 956 } 957 958 959 // #pragma mark - FBC and forbidden 960 961 962 BScrollView& 963 BScrollView::operator=(const BScrollView &) 964 { 965 return *this; 966 } 967 968 969 void BScrollView::_ReservedScrollView1() {} 970 void BScrollView::_ReservedScrollView2() {} 971 void BScrollView::_ReservedScrollView3() {} 972 void BScrollView::_ReservedScrollView4() {} 973 974 975 extern "C" void 976 B_IF_GCC_2(InvalidateLayout__11BScrollViewb, 977 _ZN11BScrollView16InvalidateLayoutEb)(BScrollView* view, bool descendants) 978 { 979 perform_data_layout_invalidated data; 980 data.descendants = descendants; 981 982 view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data); 983 } 984