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