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