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