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