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