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