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