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