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