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