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