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