1 /* 2 * Copyright (c) 2001-2009, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Marc Flerackers (mflerackers@androme.be) 7 * Stephan Aßmus <superstippi@gmx.de> 8 * DarkWyrm <bpmagic@columbus.rr.com> 9 * Axel Dörfler, axeld@pinc-software.de 10 */ 11 12 13 #include <Box.h> 14 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 19 #include <ControlLook.h> 20 #include <Layout.h> 21 #include <LayoutUtils.h> 22 #include <Message.h> 23 #include <Region.h> 24 25 #include <binary_compatibility/Interface.h> 26 27 28 struct BBox::LayoutData { 29 LayoutData() 30 : valid(false) 31 { 32 } 33 34 BRect label_box; // label box (label string or label view); in case 35 // of a label string not including descent 36 BRect insets; // insets induced by border and label 37 BSize min; 38 BSize max; 39 BSize preferred; 40 bool valid; // validity the other fields 41 }; 42 43 44 BBox::BBox(BRect frame, const char *name, uint32 resizingMode, uint32 flags, 45 border_style border) 46 : BView(frame, name, resizingMode, flags | B_WILL_DRAW | B_FRAME_EVENTS), 47 fStyle(border) 48 { 49 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 50 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 51 52 _InitObject(); 53 } 54 55 56 BBox::BBox(const char* name, uint32 flags, border_style border, BView* child) 57 : BView(name, flags | B_WILL_DRAW | B_FRAME_EVENTS), 58 fStyle(border) 59 { 60 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 61 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 62 63 _InitObject(); 64 65 if (child) 66 AddChild(child); 67 } 68 69 70 BBox::BBox(border_style border, BView* child) 71 : BView(NULL, B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP), 72 fStyle(border) 73 { 74 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 75 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 76 77 _InitObject(); 78 79 if (child) 80 AddChild(child); 81 } 82 83 84 BBox::BBox(BMessage *archive) 85 : BView(archive), 86 fStyle(B_FANCY_BORDER) 87 { 88 _InitObject(archive); 89 } 90 91 92 BBox::~BBox() 93 { 94 _ClearLabel(); 95 96 delete fLayoutData; 97 } 98 99 100 BArchivable * 101 BBox::Instantiate(BMessage *archive) 102 { 103 if (validate_instantiation(archive, "BBox")) 104 return new BBox(archive); 105 106 return NULL; 107 } 108 109 110 status_t 111 BBox::Archive(BMessage *archive, bool deep) const 112 { 113 status_t ret = BView::Archive(archive, deep); 114 115 if (fLabel && ret == B_OK) 116 ret = archive->AddString("_label", fLabel); 117 118 if (fLabelView && ret == B_OK) 119 ret = archive->AddBool("_lblview", true); 120 121 if (fStyle != B_FANCY_BORDER && ret == B_OK) 122 ret = archive->AddInt32("_style", fStyle); 123 124 return ret; 125 } 126 127 128 void 129 BBox::SetBorder(border_style border) 130 { 131 if (border == fStyle) 132 return; 133 134 fStyle = border; 135 136 InvalidateLayout(); 137 138 if (Window() != NULL && LockLooper()) { 139 Invalidate(); 140 UnlockLooper(); 141 } 142 } 143 144 145 border_style 146 BBox::Border() const 147 { 148 return fStyle; 149 } 150 151 152 //! This function is not part of the R5 API and is not yet finalized yet 153 float 154 BBox::TopBorderOffset() 155 { 156 _ValidateLayoutData(); 157 158 if (fLabel != NULL || fLabelView != NULL) 159 return fLayoutData->label_box.Height() / 2; 160 161 return 0; 162 } 163 164 165 //! This function is not part of the R5 API and is not yet finalized yet 166 BRect 167 BBox::InnerFrame() 168 { 169 _ValidateLayoutData(); 170 171 BRect frame(Bounds()); 172 frame.left += fLayoutData->insets.left; 173 frame.top += fLayoutData->insets.top; 174 frame.right -= fLayoutData->insets.right; 175 frame.bottom -= fLayoutData->insets.bottom; 176 177 return frame; 178 } 179 180 181 void 182 BBox::SetLabel(const char *string) 183 { 184 _ClearLabel(); 185 186 if (string) 187 fLabel = strdup(string); 188 189 InvalidateLayout(); 190 191 if (Window()) 192 Invalidate(); 193 } 194 195 196 status_t 197 BBox::SetLabel(BView *viewLabel) 198 { 199 _ClearLabel(); 200 201 if (viewLabel) { 202 fLabelView = viewLabel; 203 fLabelView->MoveTo(10.0f, 0.0f); 204 AddChild(fLabelView, ChildAt(0)); 205 } 206 207 InvalidateLayout(); 208 209 if (Window()) 210 Invalidate(); 211 212 return B_OK; 213 } 214 215 216 const char * 217 BBox::Label() const 218 { 219 return fLabel; 220 } 221 222 223 BView * 224 BBox::LabelView() const 225 { 226 return fLabelView; 227 } 228 229 230 void 231 BBox::Draw(BRect updateRect) 232 { 233 _ValidateLayoutData(); 234 235 PushState(); 236 237 BRect labelBox = BRect(0, 0, 0, 0); 238 if (fLabel != NULL) { 239 labelBox = fLayoutData->label_box; 240 BRegion update(updateRect); 241 update.Exclude(labelBox); 242 243 ConstrainClippingRegion(&update); 244 } else if (fLabelView != NULL) 245 labelBox = fLabelView->Bounds(); 246 247 switch (fStyle) { 248 case B_FANCY_BORDER: 249 _DrawFancy(labelBox); 250 break; 251 252 case B_PLAIN_BORDER: 253 _DrawPlain(labelBox); 254 break; 255 256 default: 257 break; 258 } 259 260 if (fLabel) { 261 ConstrainClippingRegion(NULL); 262 263 font_height fontHeight; 264 GetFontHeight(&fontHeight); 265 266 SetHighColor(0, 0, 0); 267 DrawString(fLabel, BPoint(10.0f, ceilf(fontHeight.ascent))); 268 } 269 270 PopState(); 271 } 272 273 274 void 275 BBox::AttachedToWindow() 276 { 277 BView* parent = Parent(); 278 if (parent != NULL) { 279 // inherit the color from parent 280 rgb_color color = parent->ViewColor(); 281 if (color == B_TRANSPARENT_COLOR) 282 color = ui_color(B_PANEL_BACKGROUND_COLOR); 283 284 SetViewColor(color); 285 SetLowColor(color); 286 } 287 288 // The box could have been resized in the mean time 289 fBounds = Bounds(); 290 } 291 292 293 void 294 BBox::DetachedFromWindow() 295 { 296 BView::DetachedFromWindow(); 297 } 298 299 300 void 301 BBox::AllAttached() 302 { 303 BView::AllAttached(); 304 } 305 306 307 void 308 BBox::AllDetached() 309 { 310 BView::AllDetached(); 311 } 312 313 314 void 315 BBox::FrameResized(float width, float height) 316 { 317 BRect bounds(Bounds()); 318 319 // invalidate the regions that the app_server did not 320 // (for removing the previous or drawing the new border) 321 if (fStyle != B_NO_BORDER) { 322 // TODO: this must be made part of the be_control_look stuff! 323 int32 borderSize = fStyle == B_PLAIN_BORDER ? 0 : 2; 324 325 BRect invalid(bounds); 326 if (fBounds.right < bounds.right) { 327 // enlarging 328 invalid.left = fBounds.right - borderSize; 329 invalid.right = fBounds.right; 330 331 Invalidate(invalid); 332 } else if (fBounds.right > bounds.right) { 333 // shrinking 334 invalid.left = bounds.right - borderSize; 335 336 Invalidate(invalid); 337 } 338 339 invalid = bounds; 340 if (fBounds.bottom < bounds.bottom) { 341 // enlarging 342 invalid.top = fBounds.bottom - borderSize; 343 invalid.bottom = fBounds.bottom; 344 345 Invalidate(invalid); 346 } else if (fBounds.bottom > bounds.bottom) { 347 // shrinking 348 invalid.top = bounds.bottom - borderSize; 349 350 Invalidate(invalid); 351 } 352 } 353 354 fBounds.right = bounds.right; 355 fBounds.bottom = bounds.bottom; 356 } 357 358 359 void 360 BBox::MessageReceived(BMessage *message) 361 { 362 BView::MessageReceived(message); 363 } 364 365 366 void 367 BBox::MouseDown(BPoint point) 368 { 369 BView::MouseDown(point); 370 } 371 372 373 void 374 BBox::MouseUp(BPoint point) 375 { 376 BView::MouseUp(point); 377 } 378 379 380 void 381 BBox::WindowActivated(bool active) 382 { 383 BView::WindowActivated(active); 384 } 385 386 387 void 388 BBox::MouseMoved(BPoint point, uint32 transit, const BMessage *message) 389 { 390 BView::MouseMoved(point, transit, message); 391 } 392 393 394 void 395 BBox::FrameMoved(BPoint newLocation) 396 { 397 BView::FrameMoved(newLocation); 398 } 399 400 401 BHandler * 402 BBox::ResolveSpecifier(BMessage *message, int32 index, 403 BMessage *specifier, int32 what, 404 const char *property) 405 { 406 return BView::ResolveSpecifier(message, index, specifier, what, property); 407 } 408 409 410 void 411 BBox::ResizeToPreferred() 412 { 413 float width, height; 414 GetPreferredSize(&width, &height); 415 416 // make sure the box don't get smaller than it already is 417 if (width < Bounds().Width()) 418 width = Bounds().Width(); 419 if (height < Bounds().Height()) 420 height = Bounds().Height(); 421 422 BView::ResizeTo(width, height); 423 } 424 425 426 void 427 BBox::GetPreferredSize(float *_width, float *_height) 428 { 429 _ValidateLayoutData(); 430 431 if (_width) 432 *_width = fLayoutData->preferred.width; 433 if (_height) 434 *_height = fLayoutData->preferred.height; 435 } 436 437 438 void 439 BBox::MakeFocus(bool focused) 440 { 441 BView::MakeFocus(focused); 442 } 443 444 445 status_t 446 BBox::GetSupportedSuites(BMessage *message) 447 { 448 return BView::GetSupportedSuites(message); 449 } 450 451 452 status_t 453 BBox::Perform(perform_code code, void* _data) 454 { 455 switch (code) { 456 case PERFORM_CODE_MIN_SIZE: 457 ((perform_data_min_size*)_data)->return_value 458 = BBox::MinSize(); 459 return B_OK; 460 case PERFORM_CODE_MAX_SIZE: 461 ((perform_data_max_size*)_data)->return_value 462 = BBox::MaxSize(); 463 return B_OK; 464 case PERFORM_CODE_PREFERRED_SIZE: 465 ((perform_data_preferred_size*)_data)->return_value 466 = BBox::PreferredSize(); 467 return B_OK; 468 case PERFORM_CODE_LAYOUT_ALIGNMENT: 469 ((perform_data_layout_alignment*)_data)->return_value 470 = BBox::LayoutAlignment(); 471 return B_OK; 472 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 473 ((perform_data_has_height_for_width*)_data)->return_value 474 = BBox::HasHeightForWidth(); 475 return B_OK; 476 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 477 { 478 perform_data_get_height_for_width* data 479 = (perform_data_get_height_for_width*)_data; 480 BBox::GetHeightForWidth(data->width, &data->min, &data->max, 481 &data->preferred); 482 return B_OK; 483 } 484 case PERFORM_CODE_SET_LAYOUT: 485 { 486 perform_data_set_layout* data = (perform_data_set_layout*)_data; 487 BBox::SetLayout(data->layout); 488 return B_OK; 489 } 490 case PERFORM_CODE_LAYOUT_INVALIDATED: 491 { 492 perform_data_layout_invalidated* data 493 = (perform_data_layout_invalidated*)_data; 494 BBox::LayoutInvalidated(data->descendants); 495 return B_OK; 496 } 497 case PERFORM_CODE_DO_LAYOUT: 498 { 499 BBox::DoLayout(); 500 return B_OK; 501 } 502 } 503 504 return BView::Perform(code, _data); 505 } 506 507 508 BSize 509 BBox::MinSize() 510 { 511 _ValidateLayoutData(); 512 513 BSize size = (GetLayout() ? GetLayout()->MinSize() : fLayoutData->min); 514 return BLayoutUtils::ComposeSize(ExplicitMinSize(), size); 515 } 516 517 518 BSize 519 BBox::MaxSize() 520 { 521 _ValidateLayoutData(); 522 523 BSize size = (GetLayout() ? GetLayout()->MaxSize() : fLayoutData->max); 524 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), size); 525 } 526 527 528 BSize 529 BBox::PreferredSize() 530 { 531 _ValidateLayoutData(); 532 533 BSize size = (GetLayout() ? GetLayout()->PreferredSize() 534 : fLayoutData->preferred); 535 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), size); 536 } 537 538 539 void 540 BBox::LayoutInvalidated(bool descendants) 541 { 542 fLayoutData->valid = false; 543 } 544 545 546 void 547 BBox::DoLayout() 548 { 549 // Bail out, if we shan't do layout. 550 if (!(Flags() & B_SUPPORTS_LAYOUT)) 551 return; 552 553 BLayout* layout = GetLayout(); 554 555 // If the user set a layout, let the base class version call its 556 // hook. In case when we have BView as a label, remove it from child list 557 // so it won't be layouted with the rest of views and add it again 558 // after that. 559 if (layout != NULL) { 560 if (fLabelView) 561 RemoveChild(fLabelView); 562 563 BView::DoLayout(); 564 565 if (fLabelView != NULL) { 566 DisableLayoutInvalidation(); 567 // don't trigger a relayout 568 AddChild(fLabelView, ChildAt(0)); 569 EnableLayoutInvalidation(); 570 } else 571 return; 572 } 573 574 _ValidateLayoutData(); 575 576 // Even if the user set a layout, restore label view to it's 577 // desired position. 578 579 // layout the label view 580 if (fLabelView != NULL) { 581 fLabelView->MoveTo(fLayoutData->label_box.LeftTop()); 582 fLabelView->ResizeTo(fLayoutData->label_box.Size()); 583 } 584 585 // If we have layout return here and do not layout the child 586 if (layout != NULL) 587 return; 588 589 // layout the child 590 if (BView* child = _Child()) { 591 BRect frame(Bounds()); 592 frame.left += fLayoutData->insets.left; 593 frame.top += fLayoutData->insets.top; 594 frame.right -= fLayoutData->insets.right; 595 frame.bottom -= fLayoutData->insets.bottom; 596 597 BLayoutUtils::AlignInFrame(child, frame); 598 } 599 } 600 601 602 void BBox::_ReservedBox1() {} 603 void BBox::_ReservedBox2() {} 604 605 606 BBox & 607 BBox::operator=(const BBox &) 608 { 609 return *this; 610 } 611 612 613 void 614 BBox::_InitObject(BMessage* archive) 615 { 616 fBounds = Bounds(); 617 618 fLabel = NULL; 619 fLabelView = NULL; 620 fLayoutData = new LayoutData; 621 622 int32 flags = 0; 623 624 BFont font(be_bold_font); 625 626 if (!archive || !archive->HasString("_fname")) 627 flags = B_FONT_FAMILY_AND_STYLE; 628 629 if (!archive || !archive->HasFloat("_fflt")) 630 flags |= B_FONT_SIZE; 631 632 if (flags != 0) 633 SetFont(&font, flags); 634 635 if (archive != NULL) { 636 const char *string; 637 if (archive->FindString("_label", &string) == B_OK) 638 SetLabel(string); 639 640 bool fancy; 641 int32 style; 642 643 if (archive->FindBool("_style", &fancy) == B_OK) 644 fStyle = fancy ? B_FANCY_BORDER : B_PLAIN_BORDER; 645 else if (archive->FindInt32("_style", &style) == B_OK) 646 fStyle = (border_style)style; 647 648 bool hasLabelView; 649 if (archive->FindBool("_lblview", &hasLabelView) == B_OK) 650 fLabelView = ChildAt(0); 651 } 652 } 653 654 655 void 656 BBox::_DrawPlain(BRect labelBox) 657 { 658 BRect rect = Bounds(); 659 rect.top += TopBorderOffset(); 660 661 float lightTint; 662 float shadowTint; 663 if (be_control_look != NULL) { 664 lightTint = B_LIGHTEN_1_TINT; 665 shadowTint = B_DARKEN_1_TINT; 666 } else { 667 lightTint = B_LIGHTEN_MAX_TINT; 668 shadowTint = B_DARKEN_3_TINT; 669 } 670 671 if (rect.Height() == 0.0 || rect.Width() == 0.0) { 672 // used as separator 673 rgb_color shadow = tint_color(ViewColor(), B_DARKEN_2_TINT); 674 675 SetHighColor(shadow); 676 StrokeLine(rect.LeftTop(),rect.RightBottom()); 677 } else { 678 // used as box 679 rgb_color light = tint_color(ViewColor(), lightTint); 680 rgb_color shadow = tint_color(ViewColor(), shadowTint); 681 682 BeginLineArray(4); 683 AddLine(BPoint(rect.left, rect.bottom), 684 BPoint(rect.left, rect.top), light); 685 AddLine(BPoint(rect.left + 1.0f, rect.top), 686 BPoint(rect.right, rect.top), light); 687 AddLine(BPoint(rect.left + 1.0f, rect.bottom), 688 BPoint(rect.right, rect.bottom), shadow); 689 AddLine(BPoint(rect.right, rect.bottom - 1.0f), 690 BPoint(rect.right, rect.top + 1.0f), shadow); 691 EndLineArray(); 692 } 693 } 694 695 696 void 697 BBox::_DrawFancy(BRect labelBox) 698 { 699 BRect rect = Bounds(); 700 rect.top += TopBorderOffset(); 701 702 if (be_control_look != NULL) { 703 rgb_color base = ViewColor(); 704 if (rect.Height() == 1.0) { 705 // used as horizontal separator 706 be_control_look->DrawGroupFrame(this, rect, rect, base, 707 BControlLook::B_TOP_BORDER); 708 } else if (rect.Width() == 1.0) { 709 // used as vertical separator 710 be_control_look->DrawGroupFrame(this, rect, rect, base, 711 BControlLook::B_LEFT_BORDER); 712 } else { 713 // used as box 714 be_control_look->DrawGroupFrame(this, rect, rect, base); 715 } 716 return; 717 } 718 719 rgb_color light = tint_color(ViewColor(), B_LIGHTEN_MAX_TINT); 720 rgb_color shadow = tint_color(ViewColor(), B_DARKEN_3_TINT); 721 722 if (rect.Height() == 1.0) { 723 // used as horizontal separator 724 BeginLineArray(2); 725 AddLine(BPoint(rect.left, rect.top), 726 BPoint(rect.right, rect.top), shadow); 727 AddLine(BPoint(rect.left, rect.bottom), 728 BPoint(rect.right, rect.bottom), light); 729 EndLineArray(); 730 } else if (rect.Width() == 1.0) { 731 // used as vertical separator 732 BeginLineArray(2); 733 AddLine(BPoint(rect.left, rect.top), 734 BPoint(rect.left, rect.bottom), shadow); 735 AddLine(BPoint(rect.right, rect.top), 736 BPoint(rect.right, rect.bottom), light); 737 EndLineArray(); 738 } else { 739 // used as box 740 BeginLineArray(8); 741 AddLine(BPoint(rect.left, rect.bottom - 1.0), 742 BPoint(rect.left, rect.top), shadow); 743 AddLine(BPoint(rect.left + 1.0, rect.top), 744 BPoint(rect.right - 1.0, rect.top), shadow); 745 AddLine(BPoint(rect.left, rect.bottom), 746 BPoint(rect.right, rect.bottom), light); 747 AddLine(BPoint(rect.right, rect.bottom - 1.0), 748 BPoint(rect.right, rect.top), light); 749 750 rect.InsetBy(1.0, 1.0); 751 752 AddLine(BPoint(rect.left, rect.bottom - 1.0), 753 BPoint(rect.left, rect.top), light); 754 AddLine(BPoint(rect.left + 1.0, rect.top), 755 BPoint(rect.right - 1.0, rect.top), light); 756 AddLine(BPoint(rect.left, rect.bottom), 757 BPoint(rect.right, rect.bottom), shadow); 758 AddLine(BPoint(rect.right, rect.bottom - 1.0), 759 BPoint(rect.right, rect.top), shadow); 760 EndLineArray(); 761 } 762 } 763 764 765 void 766 BBox::_ClearLabel() 767 { 768 fBounds.top = 0; 769 770 if (fLabel) { 771 free(fLabel); 772 fLabel = NULL; 773 } else if (fLabelView) { 774 fLabelView->RemoveSelf(); 775 delete fLabelView; 776 fLabelView = NULL; 777 } 778 } 779 780 781 BView* 782 BBox::_Child() const 783 { 784 for (int32 i = 0; BView* view = ChildAt(i); i++) { 785 if (view != fLabelView) 786 return view; 787 } 788 789 return NULL; 790 } 791 792 793 void 794 BBox::_ValidateLayoutData() 795 { 796 if (fLayoutData->valid) 797 return; 798 799 // compute the label box, width and height 800 bool label = true; 801 float labelHeight = 0; // height of the label (pixel count) 802 if (fLabel) { 803 // leave 6 pixels of the frame, and have a gap of 4 pixels between 804 // the frame and the text on either side 805 font_height fontHeight; 806 GetFontHeight(&fontHeight); 807 fLayoutData->label_box.Set(6.0f, 0, 14.0f + StringWidth(fLabel), 808 ceilf(fontHeight.ascent)); 809 labelHeight = ceilf(fontHeight.ascent + fontHeight.descent) + 1; 810 } else if (fLabelView) { 811 // the label view is placed at (0, 10) at its preferred size 812 BSize size = fLabelView->PreferredSize(); 813 fLayoutData->label_box.Set(10, 0, 10 + size.width, size.height); 814 labelHeight = size.height + 1; 815 } else { 816 label = false; 817 } 818 819 // border 820 switch (fStyle) { 821 case B_PLAIN_BORDER: 822 fLayoutData->insets.Set(1, 1, 1, 1); 823 break; 824 case B_FANCY_BORDER: 825 fLayoutData->insets.Set(3, 3, 3, 3); 826 break; 827 case B_NO_BORDER: 828 default: 829 fLayoutData->insets.Set(0, 0, 0, 0); 830 break; 831 } 832 833 // if there's a label, the top inset will be dictated by the label 834 if (label && labelHeight > fLayoutData->insets.top) 835 fLayoutData->insets.top = labelHeight; 836 837 // total number of pixel the border adds 838 float addWidth = fLayoutData->insets.left + fLayoutData->insets.right; 839 float addHeight = fLayoutData->insets.top + fLayoutData->insets.bottom; 840 841 // compute the minimal width induced by the label 842 float minWidth; 843 if (label) 844 minWidth = fLayoutData->label_box.right + fLayoutData->insets.right; 845 else 846 minWidth = addWidth - 1; 847 848 // finally consider the child constraints, if we shall support layout 849 BView* child = _Child(); 850 if (child && (Flags() & B_SUPPORTS_LAYOUT)) { 851 BSize min = child->MinSize(); 852 BSize max = child->MaxSize(); 853 BSize preferred = child->PreferredSize(); 854 855 min.width += addWidth; 856 min.height += addHeight; 857 preferred.width += addWidth; 858 preferred.height += addHeight; 859 max.width = BLayoutUtils::AddDistances(max.width, addWidth - 1); 860 max.height = BLayoutUtils::AddDistances(max.height, addHeight - 1); 861 862 if (min.width < minWidth) 863 min.width = minWidth; 864 BLayoutUtils::FixSizeConstraints(min, max, preferred); 865 866 fLayoutData->min = min; 867 fLayoutData->max = max; 868 fLayoutData->preferred = preferred; 869 } else { 870 fLayoutData->min.Set(minWidth, addHeight - 1); 871 fLayoutData->max.Set(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED); 872 fLayoutData->preferred = fLayoutData->min; 873 } 874 875 fLayoutData->valid = true; 876 ResetLayoutInvalidation(); 877 } 878 879 880 extern "C" void 881 B_IF_GCC_2(InvalidateLayout__4BBoxb, _ZN4BBox16InvalidateLayoutEb)( 882 BBox* box, bool descendants) 883 { 884 perform_data_layout_invalidated data; 885 data.descendants = descendants; 886 887 box->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data); 888 } 889 890