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