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