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