1 /* 2 * Copyright 2007-2008, Christof Lutteroth, lutteroth@cs.auckland.ac.nz 3 * Copyright 2007-2008, James Kim, jkim202@ec.auckland.ac.nz 4 * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de> 5 * Distributed under the terms of the MIT License. 6 */ 7 #include "ALMLayout.h" 8 9 #include <math.h> // for floor 10 #include <new> 11 #include <iostream> 12 #include <vector> 13 14 #include <ControlLook.h> 15 16 #include "RowColumnManager.h" 17 #include "ViewLayoutItem.h" 18 19 20 using namespace LinearProgramming; 21 22 23 const BSize kUnsetSize(B_SIZE_UNSET, B_SIZE_UNSET); 24 25 26 /*! 27 * Constructor. 28 * Creates new layout engine. 29 * 30 * If friendLayout is not NULL the solver of the friend layout is used. 31 */ 32 BALMLayout::BALMLayout(float hSpacing, float vSpacing, BALMLayout* friendLayout) 33 : 34 fLeftInset(0), 35 fRightInset(0), 36 fTopInset(0), 37 fBottomInset(0), 38 fHSpacing(hSpacing), 39 fVSpacing(vSpacing) 40 { 41 fSolver = friendLayout ? friendLayout->Solver() : &fOwnSolver; 42 fRowColumnManager = new RowColumnManager(fSolver); 43 44 fLeft = AddXTab(); 45 fRight = AddXTab(); 46 fTop = AddYTab(); 47 fBottom = AddYTab(); 48 49 // the Left tab is always at x-position 0, and the Top tab is always at 50 // y-position 0 51 fLeft->SetRange(0, 0); 52 fTop->SetRange(0, 0); 53 54 // cached layout values 55 // need to be invalidated whenever the layout specification is changed 56 fMinSize = kUnsetSize; 57 fMaxSize = kUnsetSize; 58 fPreferredSize = kUnsetSize; 59 } 60 61 62 BALMLayout::~BALMLayout() 63 { 64 delete fRowColumnManager; 65 } 66 67 68 /** 69 * Adds a new x-tab to the specification. 70 * 71 * @return the new x-tab 72 */ 73 BReference<XTab> 74 BALMLayout::AddXTab() 75 { 76 BReference<XTab> tab(new(std::nothrow) XTab(this), true); 77 if (!tab) 78 return NULL; 79 if (!fSolver->AddVariable(tab)) 80 return NULL; 81 82 fXTabList.AddItem(tab); 83 return tab; 84 } 85 86 87 void 88 BALMLayout::AddXTabs(BReference<XTab>* tabs, uint32 count) 89 { 90 for (uint32 i = 0; i < count; i++) 91 tabs[i] = AddXTab(); 92 } 93 94 95 void 96 BALMLayout::AddYTabs(BReference<YTab>* tabs, uint32 count) 97 { 98 for (uint32 i = 0; i < count; i++) 99 tabs[i] = AddYTab(); 100 } 101 102 103 /** 104 * Adds a new y-tab to the specification. 105 * 106 * @return the new y-tab 107 */ 108 BReference<YTab> 109 BALMLayout::AddYTab() 110 { 111 BReference<YTab> tab(new(std::nothrow) YTab(this), true); 112 if (tab.Get() == NULL) 113 return NULL; 114 if (!fSolver->AddVariable(tab)) 115 return NULL; 116 117 fYTabList.AddItem(tab); 118 return tab; 119 } 120 121 122 int32 123 BALMLayout::CountXTabs() const 124 { 125 return fXTabList.CountItems(); 126 } 127 128 129 int32 130 BALMLayout::CountYTabs() const 131 { 132 return fYTabList.CountItems(); 133 } 134 135 136 XTab* 137 BALMLayout::XTabAt(int32 index) const 138 { 139 return fXTabList.ItemAt(index); 140 } 141 142 143 YTab* 144 BALMLayout::YTabAt(int32 index) const 145 { 146 return fYTabList.ItemAt(index); 147 } 148 149 150 static int 151 compare_x_tab_func(const XTab* tab1, const XTab* tab2) 152 { 153 if (tab1->Value() < tab2->Value()) 154 return -1; 155 else if (tab1->Value() == tab2->Value()) 156 return 0; 157 return 1; 158 } 159 160 161 static int 162 compare_y_tab_func(const YTab* tab1, const YTab* tab2) 163 { 164 if (tab1->Value() < tab2->Value()) 165 return -1; 166 else if (tab1->Value() == tab2->Value()) 167 return 0; 168 return 1; 169 } 170 171 172 const XTabList& 173 BALMLayout::OrderedXTabs() 174 { 175 fXTabList.SortItems(compare_x_tab_func); 176 return fXTabList; 177 } 178 179 180 const YTabList& 181 BALMLayout::OrderedYTabs() 182 { 183 fYTabList.SortItems(compare_y_tab_func); 184 return fYTabList; 185 } 186 187 188 /** 189 * Adds a new row to the specification that is glued to the given y-tabs. 190 * 191 * @param top 192 * @param bottom 193 * @return the new row 194 */ 195 Row* 196 BALMLayout::AddRow(YTab* _top, YTab* _bottom) 197 { 198 BReference<YTab> top = _top; 199 BReference<YTab> bottom = _bottom; 200 if (_top == NULL) 201 top = AddYTab(); 202 if (_bottom == NULL) 203 bottom = AddYTab(); 204 return new(std::nothrow) Row(fSolver, top, bottom); 205 } 206 207 208 /** 209 * Adds a new column to the specification that is glued to the given x-tabs. 210 * 211 * @param left 212 * @param right 213 * @return the new column 214 */ 215 Column* 216 BALMLayout::AddColumn(XTab* _left, XTab* _right) 217 { 218 BReference<XTab> left = _left; 219 BReference<XTab> right = _right; 220 if (_left == NULL) 221 left = AddXTab(); 222 if (_right == NULL) 223 right = AddXTab(); 224 return new(std::nothrow) Column(fSolver, left, right); 225 } 226 227 228 Area* 229 BALMLayout::AreaFor(int32 id) const 230 { 231 int32 areaCount = CountAreas(); 232 for (int32 i = 0; i < areaCount; i++) { 233 Area* area = AreaAt(i); 234 if (area->ID() == id) 235 return area; 236 } 237 return NULL; 238 } 239 240 241 /** 242 * Finds the area that contains the given control. 243 * 244 * @param control the control to look for 245 * @return the area that contains the control 246 */ 247 Area* 248 BALMLayout::AreaFor(const BView* control) const 249 { 250 return AreaFor(ItemAt(IndexOfView(const_cast<BView*>(control)))); 251 } 252 253 254 Area* 255 BALMLayout::AreaFor(const BLayoutItem* item) const 256 { 257 if (!item) 258 return NULL; 259 return static_cast<Area*>(item->LayoutData()); 260 } 261 262 263 int32 264 BALMLayout::CountAreas() const 265 { 266 return CountItems(); 267 } 268 269 270 Area* 271 BALMLayout::AreaAt(int32 index) const 272 { 273 return AreaFor(ItemAt(index)); 274 } 275 276 277 XTab* 278 BALMLayout::LeftOf(const BView* view) const 279 { 280 Area* area = AreaFor(view); 281 if (!area) 282 return NULL; 283 return area->Left(); 284 } 285 286 287 XTab* 288 BALMLayout::LeftOf(const BLayoutItem* item) const 289 { 290 Area* area = AreaFor(item); 291 if (!area) 292 return NULL; 293 return area->Left(); 294 } 295 296 297 XTab* 298 BALMLayout::RightOf(const BView* view) const 299 { 300 Area* area = AreaFor(view); 301 if (!area) 302 return NULL; 303 return area->Right(); 304 } 305 306 307 XTab* 308 BALMLayout::RightOf(const BLayoutItem* item) const 309 { 310 Area* area = AreaFor(item); 311 if (!area) 312 return NULL; 313 return area->Right(); 314 } 315 316 317 YTab* 318 BALMLayout::TopOf(const BView* view) const 319 { 320 Area* area = AreaFor(view); 321 if (!area) 322 return NULL; 323 return area->Top(); 324 } 325 326 327 YTab* 328 BALMLayout::TopOf(const BLayoutItem* item) const 329 { 330 Area* area = AreaFor(item); 331 if (!area) 332 return NULL; 333 return area->Top(); 334 } 335 336 337 YTab* 338 BALMLayout::BottomOf(const BView* view) const 339 { 340 Area* area = AreaFor(view); 341 if (!area) 342 return NULL; 343 return area->Bottom(); 344 } 345 346 347 YTab* 348 BALMLayout::BottomOf(const BLayoutItem* item) const 349 { 350 Area* area = AreaFor(item); 351 if (!area) 352 return NULL; 353 return area->Bottom(); 354 } 355 356 357 void 358 BALMLayout::BuildLayout(GroupItem& item, XTab* left, YTab* top, XTab* right, 359 YTab* bottom) 360 { 361 if (left == NULL) 362 left = Left(); 363 if (top == NULL) 364 top = Top(); 365 if (right == NULL) 366 right = Right(); 367 if (bottom == NULL) 368 bottom = Bottom(); 369 370 _ParseGroupItem(item, left, top, right, bottom); 371 } 372 373 374 void 375 BALMLayout::_ParseGroupItem(GroupItem& item, BReference<XTab> left, 376 BReference<YTab> top, BReference<XTab> right, BReference<YTab> bottom) 377 { 378 if (item.LayoutItem()) 379 AddItem(item.LayoutItem(), left, top, right, bottom); 380 else if (item.View()) { 381 AddView(item.View(), left, top, right, bottom); 382 } 383 else { 384 for (unsigned int i = 0; i < item.GroupItems().size(); i++) { 385 GroupItem& current = const_cast<GroupItem&>( 386 item.GroupItems()[i]); 387 if (item.Orientation() == B_HORIZONTAL) { 388 BReference<XTab> r = (i == item.GroupItems().size() - 1) ? right 389 : AddXTab(); 390 _ParseGroupItem(current, left, top, r, bottom); 391 left = r; 392 } 393 else { 394 BReference<YTab> b = (i == item.GroupItems().size() - 1) 395 ? bottom : AddYTab(); 396 _ParseGroupItem(current, left, top, right, b); 397 top = b; 398 } 399 } 400 } 401 } 402 403 404 BLayoutItem* 405 BALMLayout::AddView(BView* child) 406 { 407 return AddView(-1, child); 408 } 409 410 411 BLayoutItem* 412 BALMLayout::AddView(int32 index, BView* child) 413 { 414 return BAbstractLayout::AddView(index, child); 415 } 416 417 418 /** 419 * Adds a new area to the specification, automatically setting preferred size constraints. 420 * 421 * @param left left border 422 * @param top top border 423 * @param right right border 424 * @param bottom bottom border 425 * @param content the control which is the area content 426 * @return the new area 427 */ 428 Area* 429 BALMLayout::AddView(BView* view, XTab* left, YTab* top, XTab* right, 430 YTab* bottom) 431 { 432 BLayoutItem* item = _LayoutItemToAdd(view); 433 Area* area = AddItem(item, left, top, right, bottom); 434 if (!area) { 435 if (item != view->GetLayout()) 436 delete item; 437 return NULL; 438 } 439 return area; 440 } 441 442 443 /** 444 * Adds a new area to the specification, automatically setting preferred size constraints. 445 * 446 * @param row the row that defines the top and bottom border 447 * @param column the column that defines the left and right border 448 * @param content the control which is the area content 449 * @return the new area 450 */ 451 Area* 452 BALMLayout::AddView(BView* view, Row* row, Column* column) 453 { 454 BLayoutItem* item = _LayoutItemToAdd(view); 455 Area* area = AddItem(item, row, column); 456 if (!area) { 457 if (item != view->GetLayout()) 458 delete item; 459 return NULL; 460 } 461 return area; 462 } 463 464 465 bool 466 BALMLayout::AddItem(BLayoutItem* item) 467 { 468 return AddItem(-1, item); 469 } 470 471 472 bool 473 BALMLayout::AddItem(int32 index, BLayoutItem* item) 474 { 475 if (!item) 476 return false; 477 478 // simply add the item at the upper right corner of the previous item 479 // TODO maybe find a more elegant solution 480 XTab* left = Left(); 481 YTab* top = Top(); 482 483 // check range 484 if (index < 0 || index > CountItems()) 485 index = CountItems(); 486 487 // for index = 0 we already have set the right tabs 488 if (index != 0) { 489 BLayoutItem* prevItem = ItemAt(index - 1); 490 Area* area = AreaFor(prevItem); 491 if (area) { 492 left = area->Right(); 493 top = area->Top(); 494 } 495 } 496 Area* area = AddItem(item, left, top); 497 return area ? true : false; 498 } 499 500 501 Area* 502 BALMLayout::AddItem(BLayoutItem* item, XTab* left, YTab* top, XTab* _right, 503 YTab* _bottom) 504 { 505 BReference<XTab> right = _right; 506 if (right.Get() == NULL) 507 right = AddXTab(); 508 BReference<YTab> bottom = _bottom; 509 if (bottom.Get() == NULL) 510 bottom = AddYTab(); 511 512 // Area is added int ItemAdded 513 if (!BAbstractLayout::AddItem(-1, item)) 514 return NULL; 515 Area* area = AreaFor(item); 516 if (!area) 517 return NULL; 518 519 area->_Init(fSolver, left, top, right, bottom, fRowColumnManager); 520 521 fRowColumnManager->AddArea(area); 522 return area; 523 } 524 525 526 Area* 527 BALMLayout::AddItem(BLayoutItem* item, Row* row, Column* column) 528 { 529 if (!BAbstractLayout::AddItem(-1, item)) 530 return NULL; 531 Area* area = AreaFor(item); 532 if (!area) 533 return NULL; 534 535 area->_Init(fSolver, row, column, fRowColumnManager); 536 537 fRowColumnManager->AddArea(area); 538 return area; 539 } 540 541 542 enum { 543 kLeftBorderIndex = -2, 544 kTopBorderIndex = -3, 545 kRightBorderIndex = -4, 546 kBottomBorderIndex = -5, 547 }; 548 549 550 bool 551 BALMLayout::SaveLayout(BMessage* archive) const 552 { 553 archive->MakeEmpty(); 554 555 archive->AddInt32("nXTabs", CountXTabs()); 556 archive->AddInt32("nYTabs", CountYTabs()); 557 558 XTabList xTabs = fXTabList; 559 xTabs.RemoveItem(fLeft); 560 xTabs.RemoveItem(fRight); 561 YTabList yTabs = fYTabList; 562 yTabs.RemoveItem(fTop); 563 yTabs.RemoveItem(fBottom); 564 565 int32 nAreas = CountAreas(); 566 for (int32 i = 0; i < nAreas; i++) { 567 Area* area = AreaAt(i); 568 if (area->Left() == fLeft) 569 archive->AddInt32("left", kLeftBorderIndex); 570 else 571 archive->AddInt32("left", xTabs.IndexOf(area->Left())); 572 if (area->Top() == fTop) 573 archive->AddInt32("top", kTopBorderIndex); 574 else 575 archive->AddInt32("top", yTabs.IndexOf(area->Top())); 576 if (area->Right() == fRight) 577 archive->AddInt32("right", kRightBorderIndex); 578 else 579 archive->AddInt32("right", xTabs.IndexOf(area->Right())); 580 if (area->Bottom() == fBottom) 581 archive->AddInt32("bottom", kBottomBorderIndex); 582 else 583 archive->AddInt32("bottom", yTabs.IndexOf(area->Bottom())); 584 } 585 return true; 586 } 587 588 589 bool 590 BALMLayout::RestoreLayout(const BMessage* archive) 591 { 592 int32 neededXTabs; 593 int32 neededYTabs; 594 if (archive->FindInt32("nXTabs", &neededXTabs) != B_OK) 595 return false; 596 if (archive->FindInt32("nYTabs", &neededYTabs) != B_OK) 597 return false; 598 // First store a reference to all needed tabs otherwise they might get lost 599 // while editing the layout 600 std::vector<BReference<XTab> > newXTabs; 601 std::vector<BReference<YTab> > newYTabs; 602 int32 existingXTabs = fXTabList.CountItems(); 603 for (int32 i = 0; i < neededXTabs; i++) { 604 if (i < existingXTabs) 605 newXTabs.push_back(BReference<XTab>(fXTabList.ItemAt(i))); 606 else 607 newXTabs.push_back(AddXTab()); 608 } 609 int32 existingYTabs = fYTabList.CountItems(); 610 for (int32 i = 0; i < neededYTabs; i++) { 611 if (i < existingYTabs) 612 newYTabs.push_back(BReference<YTab>(fYTabList.ItemAt(i))); 613 else 614 newYTabs.push_back(AddYTab()); 615 } 616 617 XTabList xTabs = fXTabList; 618 xTabs.RemoveItem(fLeft); 619 xTabs.RemoveItem(fRight); 620 YTabList yTabs = fYTabList; 621 yTabs.RemoveItem(fTop); 622 yTabs.RemoveItem(fBottom); 623 624 int32 nAreas = CountAreas(); 625 for (int32 i = 0; i < nAreas; i++) { 626 Area* area = AreaAt(i); 627 if (area == NULL) 628 return false; 629 int32 left = -1; 630 if (archive->FindInt32("left", i, &left) != B_OK) 631 break; 632 int32 top = archive->FindInt32("top", i); 633 int32 right = archive->FindInt32("right", i); 634 int32 bottom = archive->FindInt32("bottom", i); 635 636 XTab* leftTab = NULL; 637 YTab* topTab = NULL; 638 XTab* rightTab = NULL; 639 YTab* bottomTab = NULL; 640 641 if (left == kLeftBorderIndex) 642 leftTab = fLeft; 643 else 644 leftTab = xTabs.ItemAt(left); 645 if (top == kTopBorderIndex) 646 topTab = fTop; 647 else 648 topTab = yTabs.ItemAt(top); 649 if (right == kRightBorderIndex) 650 rightTab = fRight; 651 else 652 rightTab = xTabs.ItemAt(right); 653 if (bottom == kBottomBorderIndex) 654 bottomTab = fBottom; 655 else 656 bottomTab = yTabs.ItemAt(bottom); 657 if (leftTab == NULL || topTab == NULL || rightTab == NULL 658 || bottomTab == NULL) 659 return false; 660 661 area->SetLeft(leftTab); 662 area->SetTop(topTab); 663 area->SetRight(rightTab); 664 area->SetBottom(bottomTab); 665 } 666 return true; 667 } 668 669 670 /** 671 * Gets the left variable. 672 */ 673 XTab* 674 BALMLayout::Left() const 675 { 676 return fLeft; 677 } 678 679 680 /** 681 * Gets the right variable. 682 */ 683 XTab* 684 BALMLayout::Right() const 685 { 686 return fRight; 687 } 688 689 690 /** 691 * Gets the top variable. 692 */ 693 YTab* 694 BALMLayout::Top() const 695 { 696 return fTop; 697 } 698 699 700 /** 701 * Gets the bottom variable. 702 */ 703 YTab* 704 BALMLayout::Bottom() const 705 { 706 return fBottom; 707 } 708 709 710 /** 711 * Gets minimum size. 712 */ 713 BSize 714 BALMLayout::BaseMinSize() { 715 if (fMinSize == kUnsetSize) 716 fMinSize = _CalculateMinSize(); 717 return fMinSize; 718 } 719 720 721 /** 722 * Gets maximum size. 723 */ 724 BSize 725 BALMLayout::BaseMaxSize() 726 { 727 if (fMaxSize == kUnsetSize) 728 fMaxSize = _CalculateMaxSize(); 729 return fMaxSize; 730 } 731 732 733 /** 734 * Gets preferred size. 735 */ 736 BSize 737 BALMLayout::BasePreferredSize() 738 { 739 if (fPreferredSize == kUnsetSize) 740 fPreferredSize = _CalculatePreferredSize(); 741 return fPreferredSize; 742 } 743 744 745 /** 746 * Gets the alignment. 747 */ 748 BAlignment 749 BALMLayout::BaseAlignment() 750 { 751 BAlignment alignment; 752 alignment.SetHorizontal(B_ALIGN_HORIZONTAL_CENTER); 753 alignment.SetVertical(B_ALIGN_VERTICAL_CENTER); 754 return alignment; 755 } 756 757 758 /** 759 * Invalidates the layout. 760 * Resets minimum/maximum/preferred size. 761 */ 762 void 763 BALMLayout::LayoutInvalidated(bool children) 764 { 765 fMinSize = kUnsetSize; 766 fMaxSize = kUnsetSize; 767 fPreferredSize = kUnsetSize; 768 } 769 770 771 bool 772 BALMLayout::ItemAdded(BLayoutItem* item, int32 atIndex) 773 { 774 item->SetLayoutData(new(std::nothrow) Area(item)); 775 return item->LayoutData() != NULL; 776 } 777 778 779 void 780 BALMLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex) 781 { 782 if (Area* area = AreaFor(item)) { 783 fRowColumnManager->RemoveArea(area); 784 item->SetLayoutData(NULL); 785 delete area; 786 } 787 } 788 789 790 /** 791 * Calculate and set the layout. 792 * If no layout specification is given, a specification is reverse engineered automatically. 793 */ 794 void 795 BALMLayout::DoLayout() 796 { 797 _UpdateAreaConstraints(); 798 799 // Enforced absolute positions of Right and Bottom 800 BRect area(LayoutArea()); 801 Right()->SetRange(area.right, area.right); 802 Bottom()->SetRange(area.bottom, area.bottom); 803 804 fSolver->Solve(); 805 806 // if new layout is infeasible, use previous layout 807 if (fSolver->Result() == kInfeasible) 808 return; 809 810 if (fSolver->Result() != kOptimal) { 811 fSolver->Save("failed-layout.txt"); 812 printf("Could not solve the layout specification (%d). ", 813 fSolver->Result()); 814 printf("Saved specification in file failed-layout.txt\n"); 815 } 816 817 // set the calculated positions and sizes for every area 818 for (int32 i = 0; i < CountItems(); i++) 819 AreaFor(ItemAt(i))->_DoLayout(); 820 } 821 822 823 LinearSpec* 824 BALMLayout::Solver() const 825 { 826 return const_cast<LinearSpec*>(fSolver); 827 } 828 829 830 void 831 BALMLayout::SetInsets(float left, float top, float right, 832 float bottom) 833 { 834 fLeftInset = BControlLook::ComposeSpacing(left); 835 fTopInset = BControlLook::ComposeSpacing(top); 836 fRightInset = BControlLook::ComposeSpacing(right); 837 fBottomInset = BControlLook::ComposeSpacing(bottom); 838 839 InvalidateLayout(); 840 } 841 842 843 void 844 BALMLayout::SetInsets(float horizontal, float vertical) 845 { 846 fLeftInset = BControlLook::ComposeSpacing(horizontal); 847 fRightInset = fLeftInset; 848 849 fTopInset = BControlLook::ComposeSpacing(vertical); 850 fBottomInset = fTopInset; 851 852 InvalidateLayout(); 853 } 854 855 856 void 857 BALMLayout::SetInsets(float insets) 858 { 859 fLeftInset = BControlLook::ComposeSpacing(insets); 860 fRightInset = fLeftInset; 861 fTopInset = fLeftInset; 862 fBottomInset = fLeftInset; 863 864 InvalidateLayout(); 865 } 866 867 868 void 869 BALMLayout::GetInsets(float* left, float* top, float* right, 870 float* bottom) const 871 { 872 if (left) 873 *left = fLeftInset; 874 if (top) 875 *top = fTopInset; 876 if (right) 877 *right = fRightInset; 878 if (bottom) 879 *bottom = fBottomInset; 880 } 881 882 883 void 884 BALMLayout::SetSpacing(float hSpacing, float vSpacing) 885 { 886 fHSpacing = BControlLook::ComposeSpacing(hSpacing); 887 fVSpacing = BControlLook::ComposeSpacing(vSpacing); 888 } 889 890 891 void 892 BALMLayout::GetSpacing(float *_hSpacing, float *_vSpacing) const 893 { 894 if (_hSpacing) 895 *_hSpacing = fHSpacing; 896 if (_vSpacing) 897 *_vSpacing = fVSpacing; 898 } 899 900 901 float 902 BALMLayout::InsetForTab(XTab* tab) 903 { 904 if (tab == fLeft.Get()) 905 return fLeftInset; 906 if (tab == fRight.Get()) 907 return fRightInset; 908 return fHSpacing / 2; 909 } 910 911 912 float 913 BALMLayout::InsetForTab(YTab* tab) 914 { 915 if (tab == fTop.Get()) 916 return fTopInset; 917 if (tab == fBottom.Get()) 918 return fBottomInset; 919 return fVSpacing / 2; 920 } 921 922 923 BLayoutItem* 924 BALMLayout::_LayoutItemToAdd(BView* view) 925 { 926 if (view->GetLayout()) 927 return view->GetLayout(); 928 return new(std::nothrow) BViewLayoutItem(view); 929 } 930 931 932 /** 933 * Caculates the miminum size. 934 */ 935 BSize 936 BALMLayout::_CalculateMinSize() 937 { 938 _UpdateAreaConstraints(); 939 940 Right()->SetRange(0, 20000); 941 Bottom()->SetRange(0, 20000); 942 943 return fSolver->MinSize(Right(), Bottom()); 944 } 945 946 947 /** 948 * Caculates the maximum size. 949 */ 950 BSize 951 BALMLayout::_CalculateMaxSize() 952 { 953 _UpdateAreaConstraints(); 954 955 Right()->SetRange(0, 20000); 956 Bottom()->SetRange(0, 20000); 957 958 return fSolver->MaxSize(Right(), Bottom()); 959 } 960 961 962 /** 963 * Caculates the preferred size. 964 */ 965 BSize 966 BALMLayout::_CalculatePreferredSize() 967 { 968 _UpdateAreaConstraints(); 969 970 Right()->SetRange(0, 20000); 971 Bottom()->SetRange(0, 20000); 972 973 fSolver->Solve(); 974 if (fSolver->Result() != kOptimal) { 975 fSolver->Save("failed-layout.txt"); 976 printf("Could not solve the layout specification (%d). " 977 "Saved specification in file failed-layout.txt", fSolver->Result()); 978 } 979 980 return BSize(Right()->Value() - Left()->Value(), 981 Bottom()->Value() - Top()->Value()); 982 } 983 984 985 void 986 BALMLayout::_UpdateAreaConstraints() 987 { 988 for (int i = 0; i < CountItems(); i++) 989 AreaFor(ItemAt(i))->InvalidateSizeConstraints(); 990 fRowColumnManager->UpdateConstraints(); 991 } 992