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