Make UEFI boot-platform build again
[haiku.git] / src / libs / alm / ALMLayout.cpp
bloba294f0143bc874c56e321a588913e7c930701648
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 */
9 #include "ALMLayout.h"
12 #include <stdio.h>
13 #include <vector>
15 #include <AutoDeleter.h>
16 #include <ControlLook.h>
18 #include "RowColumnManager.h"
19 #include "SharedSolver.h"
20 #include "ViewLayoutItem.h"
23 using BPrivate::AutoDeleter;
24 using namespace LinearProgramming;
27 const BSize kUnsetSize(B_SIZE_UNSET, B_SIZE_UNSET);
30 namespace {
32 const char* kSolverField = "BALMLayout:solver";
33 const char* kBadLayoutPolicyField = "BALMLayout:policy";
34 const char* kXTabsField = "BALMLayout:xtabs";
35 const char* kYTabsField = "BALMLayout:ytabs";
36 const char* kMyTabsField = "BALMLayout:tabs";
37 const char* kInsetsField = "BALMLayout:insets";
38 const char* kSpacingField = "BALMLayout:spacing";
40 const char* kTabsField = "BALMLayout:item:tabs";
41 const char* kItemAspectRatio = "BALMLayout:item:aspect";
42 const char* kItemPenalties = "BALMLayout:item:penalties";
43 const char* kItemInsets = "BALMLayout:item:insets";
45 int CompareXTabFunc(const XTab* tab1, const XTab* tab2);
46 int CompareYTabFunc(const YTab* tab1, const YTab* tab2);
51 namespace BALM {
54 template <class T>
55 struct BALMLayout::TabAddTransaction {
56 ~TabAddTransaction()
58 if (fTab)
59 fLayout->_RemoveSelfFromTab(fTab);
60 if (fIndex > 0)
61 _TabList()->RemoveItemAt(fIndex);
64 TabAddTransaction(BALMLayout* layout)
66 fTab(NULL),
67 fLayout(layout),
68 fIndex(-1)
72 bool AttempAdd(T* tab)
74 if (fLayout->_HasTabInLayout(tab))
75 return true;
76 if (!fLayout->_AddedTab(tab))
77 return false;
78 fTab = tab;
80 BObjectList<T>* tabList = _TabList();
81 int32 index = tabList->CountItems();
82 if (!tabList->AddItem(tab, index))
83 return false;
84 fIndex = index;
85 return true;
88 void Commit()
90 fTab = NULL;
91 fIndex = -1;
94 private:
95 BObjectList<T>* _TabList();
97 T* fTab;
98 BALMLayout* fLayout;
99 int32 fIndex;
103 template <>
104 BObjectList<XTab>*
105 BALMLayout::TabAddTransaction<XTab>::_TabList()
107 return &fLayout->fXTabList;
111 template <>
112 BObjectList<YTab>*
113 BALMLayout::TabAddTransaction<YTab>::_TabList()
115 return &fLayout->fYTabList;
119 }; // end namespace BALM
122 BALM::BALMLayout::BadLayoutPolicy::BadLayoutPolicy()
127 BALM::BALMLayout::BadLayoutPolicy::BadLayoutPolicy(BMessage* archive)
129 BArchivable(archive)
134 BALM::BALMLayout::BadLayoutPolicy::~BadLayoutPolicy()
139 BALM::BALMLayout::DefaultPolicy::DefaultPolicy()
144 BALM::BALMLayout::DefaultPolicy::DefaultPolicy(BMessage* archive)
146 BadLayoutPolicy(archive)
151 BALM::BALMLayout::DefaultPolicy::~DefaultPolicy()
156 bool
157 BALM::BALMLayout::DefaultPolicy::OnBadLayout(BALMLayout* layout,
158 ResultType result, BLayoutContext* context)
160 if (!context)
161 return true;
163 if (result == kInfeasible) {
164 printf("BALMLayout failed to solve your layout!\n");
165 return false;
166 } else
167 return true;
171 status_t
172 BALM::BALMLayout::DefaultPolicy::Archive(BMessage* archive, bool deep) const
174 return BadLayoutPolicy::Archive(archive, deep);
178 BArchivable*
179 BALM::BALMLayout::DefaultPolicy::Instantiate(BMessage* archive)
181 if (validate_instantiation(archive, "BALM::BALMLayout::DefaultPolicy"))
182 return new DefaultPolicy(archive);
183 return NULL;
187 class BALMLayout::BALMLayoutSpecListener
188 : public LinearProgramming::SpecificationListener {
189 public:
190 BALMLayoutSpecListener(BALMLayout* layout)
192 fLayout(layout)
196 void ConstraintRemoved(Constraint* constraint)
198 fLayout->fConstraints.RemoveItem(constraint);
201 private:
202 BALMLayout* fLayout;
207 * Constructor.
208 * Creates new layout engine.
210 * If friendLayout is not NULL the solver of the friend layout is used.
212 BALMLayout::BALMLayout(float hSpacing, float vSpacing, BALMLayout* friendLayout)
214 fLeftInset(0),
215 fRightInset(0),
216 fTopInset(0),
217 fBottomInset(0),
218 fHSpacing(BControlLook::ComposeSpacing(hSpacing)),
219 fVSpacing(BControlLook::ComposeSpacing(vSpacing)),
220 fXTabsSorted(false),
221 fYTabsSorted(false),
222 fBadLayoutPolicy(new DefaultPolicy())
224 _SetSolver(friendLayout ? friendLayout->fSolver : new SharedSolver());
226 fSpecListener = new BALMLayoutSpecListener(this);
227 Solver()->AddListener(fSpecListener);
229 fLeft = AddXTab();
230 fRight = AddXTab();
231 fTop = AddYTab();
232 fBottom = AddYTab();
234 // the Left tab is always at x-position 0, and the Top tab is always at
235 // y-position 0
236 fLeft->SetRange(0, 0);
237 fTop->SetRange(0, 0);
239 // cached layout values
240 // need to be invalidated whenever the layout specification is changed
241 fMinSize = kUnsetSize;
242 fMaxSize = kUnsetSize;
243 fPreferredSize = kUnsetSize;
247 BALMLayout::BALMLayout(BMessage* archive)
249 BAbstractLayout(BUnarchiver::PrepareArchive(archive)),
250 fSolver(NULL),
251 fLeft(NULL),
252 fRight(NULL),
253 fTop(NULL),
254 fBottom(NULL),
255 fMinSize(kUnsetSize),
256 fMaxSize(kUnsetSize),
257 fPreferredSize(kUnsetSize),
258 fXTabsSorted(false),
259 fYTabsSorted(false),
260 fBadLayoutPolicy(new DefaultPolicy())
262 BUnarchiver unarchiver(archive);
264 BRect insets;
265 status_t err = archive->FindRect(kInsetsField, &insets);
266 if (err != B_OK) {
267 unarchiver.Finish(err);
268 return;
271 fLeftInset = insets.left;
272 fRightInset = insets.right;
273 fTopInset = insets.top;
274 fBottomInset = insets.bottom;
277 BSize spacing;
278 err = archive->FindSize(kSpacingField, &spacing);
279 if (err != B_OK) {
280 unarchiver.Finish(err);
281 return;
284 fHSpacing = spacing.width;
285 fVSpacing = spacing.height;
287 int32 tabCount = 0;
288 archive->GetInfo(kXTabsField, NULL, &tabCount);
289 for (int32 i = 0; i < tabCount && err == B_OK; i++)
290 err = unarchiver.EnsureUnarchived(kXTabsField, i);
292 archive->GetInfo(kYTabsField, NULL, &tabCount);
293 for (int32 i = 0; i < tabCount && err == B_OK; i++)
294 err = unarchiver.EnsureUnarchived(kYTabsField, i);
296 if (err == B_OK && archive->GetInfo(kBadLayoutPolicyField, NULL) == B_OK)
297 err = unarchiver.EnsureUnarchived(kBadLayoutPolicyField);
299 if (err == B_OK)
300 err = unarchiver.EnsureUnarchived(kSolverField);
302 unarchiver.Finish(err);
304 fSpecListener = new BALMLayoutSpecListener(this);
305 Solver()->AddListener(fSpecListener);
309 BALMLayout::~BALMLayout()
311 Solver()->RemoveListener(fSpecListener);
312 delete fSpecListener;
314 delete fRowColumnManager;
315 delete fBadLayoutPolicy;
317 for (int32 i = 0; i < fConstraints.CountItems(); i++)
318 Solver()->RemoveConstraint(fConstraints.ItemAt(i), true);
320 if (fSolver) {
321 fSolver->LayoutLeaving(this);
322 fSolver->ReleaseReference();
328 * Adds a new x-tab to the specification.
330 * @return the new x-tab
332 BReference<XTab>
333 BALMLayout::AddXTab()
335 BReference<XTab> tab(new(std::nothrow) XTab(this), true);
336 if (!tab)
337 return NULL;
338 if (!Solver()->AddVariable(tab))
339 return NULL;
341 fXTabList.AddItem(tab);
342 if (!tab->AddedToLayout(this)) {
343 fXTabList.RemoveItem(tab);
344 return NULL;
346 fXTabsSorted = false;
347 return tab;
351 void
352 BALMLayout::AddXTabs(BReference<XTab>* tabs, uint32 count)
354 for (uint32 i = 0; i < count; i++)
355 tabs[i] = AddXTab();
359 void
360 BALMLayout::AddYTabs(BReference<YTab>* tabs, uint32 count)
362 for (uint32 i = 0; i < count; i++)
363 tabs[i] = AddYTab();
368 * Adds a new y-tab to the specification.
370 * @return the new y-tab
372 BReference<YTab>
373 BALMLayout::AddYTab()
375 BReference<YTab> tab(new(std::nothrow) YTab(this), true);
376 if (tab.Get() == NULL)
377 return NULL;
378 if (!Solver()->AddVariable(tab))
379 return NULL;
381 fYTabList.AddItem(tab);
382 if (!tab->AddedToLayout(this)) {
383 fYTabList.RemoveItem(tab);
384 return NULL;
386 fYTabsSorted = false;
387 return tab;
391 int32
392 BALMLayout::CountXTabs() const
394 return fXTabList.CountItems();
398 int32
399 BALMLayout::CountYTabs() const
401 return fYTabList.CountItems();
405 XTab*
406 BALMLayout::XTabAt(int32 index, bool ordered)
408 if (ordered && !fXTabsSorted) {
409 Layout();
410 fXTabList.SortItems(CompareXTabFunc);
411 fXTabsSorted = true;
413 return fXTabList.ItemAt(index);
417 XTab*
418 BALMLayout::XTabAt(int32 index) const
420 return fXTabList.ItemAt(index);
424 YTab*
425 BALMLayout::YTabAt(int32 index, bool ordered)
427 if (ordered && !fYTabsSorted) {
428 Layout();
429 fYTabList.SortItems(CompareYTabFunc);
430 fYTabsSorted = true;
432 return fYTabList.ItemAt(index);
436 YTab*
437 BALMLayout::YTabAt(int32 index) const
439 return fYTabList.ItemAt(index);
443 const XTabList
444 BALMLayout::GetXTabs() const
446 return fXTabList;
450 const YTabList
451 BALMLayout::GetYTabs() const
453 return fYTabList;
457 int32
458 BALMLayout::IndexOf(XTab* tab, bool ordered)
460 if (ordered && !fXTabsSorted) {
461 Layout();
462 fXTabList.SortItems(CompareXTabFunc);
463 fXTabsSorted = true;
465 return fXTabList.IndexOf(tab);
469 int32
470 BALMLayout::IndexOf(YTab* tab, bool ordered)
472 if (ordered && !fYTabsSorted) {
473 Layout();
474 fYTabList.SortItems(CompareYTabFunc);
475 fYTabsSorted = true;
477 return fYTabList.IndexOf(tab);
481 int32
482 BALMLayout::CountConstraints() const
484 return fConstraints.CountItems();
488 Constraint*
489 BALMLayout::ConstraintAt(int32 index) const
491 return fConstraints.ItemAt(index);
495 bool
496 BALMLayout::AddConstraint(Constraint* constraint)
498 fConstraints.AddItem(constraint);
499 return Solver()->AddConstraint(constraint);
503 bool
504 BALMLayout::RemoveConstraint(Constraint* constraint,
505 bool deleteConstraint)
507 if (!fConstraints.RemoveItem(constraint))
508 return false;
509 return Solver()->RemoveConstraint(constraint, deleteConstraint);
513 Constraint*
514 BALMLayout::AddConstraint(double coeff1, Variable* var1, OperatorType op,
515 double rightSide, double penaltyNeg, double penaltyPos)
517 Constraint* constraint = Solver()->AddConstraint(coeff1, var1, op,
518 rightSide, penaltyNeg, penaltyPos);
519 fConstraints.AddItem(constraint);
520 return constraint;
524 Constraint*
525 BALMLayout::AddConstraint(double coeff1, Variable* var1, double coeff2,
526 Variable* var2, OperatorType op, double rightSide, double penaltyNeg,
527 double penaltyPos)
529 Constraint* constraint = Solver()->AddConstraint(coeff1, var1, coeff2, var2,
530 op, rightSide, penaltyNeg, penaltyPos);
531 fConstraints.AddItem(constraint);
532 return constraint;
535 Constraint*
536 BALMLayout::AddConstraint(double coeff1, Variable* var1, double coeff2,
537 Variable* var2, double coeff3, Variable* var3, OperatorType op,
538 double rightSide, double penaltyNeg, double penaltyPos)
540 Constraint* constraint = Solver()->AddConstraint(coeff1, var1, coeff2, var2,
541 coeff3, var3, op, rightSide, penaltyNeg, penaltyPos);
542 fConstraints.AddItem(constraint);
543 return constraint;
547 Constraint*
548 BALMLayout::AddConstraint(double coeff1, Variable* var1, double coeff2,
549 Variable* var2, double coeff3, Variable* var3, double coeff4,
550 Variable* var4, OperatorType op, double rightSide, double penaltyNeg,
551 double penaltyPos)
553 Constraint* constraint = Solver()->AddConstraint(coeff1, var1, coeff2, var2,
554 coeff3, var3, coeff4, var4, op, rightSide, penaltyNeg, penaltyPos);
555 fConstraints.AddItem(constraint);
556 return constraint;
560 namespace {
564 CompareXTabFunc(const XTab* tab1, const XTab* tab2)
566 if (tab1->Value() < tab2->Value())
567 return -1;
568 else if (tab1->Value() == tab2->Value())
569 return 0;
570 return 1;
575 CompareYTabFunc(const YTab* tab1, const YTab* tab2)
577 if (tab1->Value() < tab2->Value())
578 return -1;
579 else if (tab1->Value() == tab2->Value())
580 return 0;
581 return 1;
585 }; // end anonymous namespace
589 * Adds a new row to the specification that is glued to the given y-tabs.
591 * @param top
592 * @param bottom
593 * @return the new row
595 Row*
596 BALMLayout::AddRow(YTab* _top, YTab* _bottom)
598 BReference<YTab> top = _top;
599 BReference<YTab> bottom = _bottom;
600 if (_top == NULL)
601 top = AddYTab();
602 if (_bottom == NULL)
603 bottom = AddYTab();
604 return new(std::nothrow) Row(Solver(), top, bottom);
609 * Adds a new column to the specification that is glued to the given x-tabs.
611 * @param left
612 * @param right
613 * @return the new column
615 Column*
616 BALMLayout::AddColumn(XTab* _left, XTab* _right)
618 BReference<XTab> left = _left;
619 BReference<XTab> right = _right;
620 if (_left == NULL)
621 left = AddXTab();
622 if (_right == NULL)
623 right = AddXTab();
624 return new(std::nothrow) Column(Solver(), left, right);
628 Area*
629 BALMLayout::AreaFor(int32 id) const
631 int32 areaCount = CountAreas();
632 for (int32 i = 0; i < areaCount; i++) {
633 Area* area = AreaAt(i);
634 if (area->ID() == id)
635 return area;
637 return NULL;
642 * Finds the area that contains the given control.
644 * @param control the control to look for
645 * @return the area that contains the control
647 Area*
648 BALMLayout::AreaFor(const BView* control) const
650 return AreaFor(ItemAt(IndexOfView(const_cast<BView*>(control))));
654 Area*
655 BALMLayout::AreaFor(const BLayoutItem* item) const
657 if (!item)
658 return NULL;
659 return static_cast<Area*>(item->LayoutData());
663 int32
664 BALMLayout::CountAreas() const
666 return CountItems();
670 Area*
671 BALMLayout::AreaAt(int32 index) const
673 return AreaFor(ItemAt(index));
677 XTab*
678 BALMLayout::LeftOf(const BView* view) const
680 Area* area = AreaFor(view);
681 if (!area)
682 return NULL;
683 return area->Left();
687 XTab*
688 BALMLayout::LeftOf(const BLayoutItem* item) const
690 Area* area = AreaFor(item);
691 if (!area)
692 return NULL;
693 return area->Left();
697 XTab*
698 BALMLayout::RightOf(const BView* view) const
700 Area* area = AreaFor(view);
701 if (!area)
702 return NULL;
703 return area->Right();
707 XTab*
708 BALMLayout::RightOf(const BLayoutItem* item) const
710 Area* area = AreaFor(item);
711 if (!area)
712 return NULL;
713 return area->Right();
717 YTab*
718 BALMLayout::TopOf(const BView* view) const
720 Area* area = AreaFor(view);
721 if (!area)
722 return NULL;
723 return area->Top();
727 YTab*
728 BALMLayout::TopOf(const BLayoutItem* item) const
730 Area* area = AreaFor(item);
731 if (!area)
732 return NULL;
733 return area->Top();
737 YTab*
738 BALMLayout::BottomOf(const BView* view) const
740 Area* area = AreaFor(view);
741 if (!area)
742 return NULL;
743 return area->Bottom();
747 YTab*
748 BALMLayout::BottomOf(const BLayoutItem* item) const
750 Area* area = AreaFor(item);
751 if (!area)
752 return NULL;
753 return area->Bottom();
757 BLayoutItem*
758 BALMLayout::AddView(BView* child)
760 return AddView(-1, child);
764 BLayoutItem*
765 BALMLayout::AddView(int32 index, BView* child)
767 return BAbstractLayout::AddView(index, child);
772 * Adds a new area to the specification, automatically setting preferred size constraints.
774 * @param left left border
775 * @param top top border
776 * @param right right border
777 * @param bottom bottom border
778 * @param content the control which is the area content
779 * @return the new area
781 Area*
782 BALMLayout::AddView(BView* view, XTab* left, YTab* top, XTab* right,
783 YTab* bottom)
785 BLayoutItem* item = _LayoutItemToAdd(view);
786 Area* area = AddItem(item, left, top, right, bottom);
787 if (!area) {
788 if (item != view->GetLayout())
789 delete item;
790 return NULL;
792 return area;
797 * Adds a new area to the specification, automatically setting preferred size constraints.
799 * @param row the row that defines the top and bottom border
800 * @param column the column that defines the left and right border
801 * @param content the control which is the area content
802 * @return the new area
804 Area*
805 BALMLayout::AddView(BView* view, Row* row, Column* column)
807 BLayoutItem* item = _LayoutItemToAdd(view);
808 Area* area = AddItem(item, row, column);
809 if (!area) {
810 if (item != view->GetLayout())
811 delete item;
812 return NULL;
814 return area;
818 bool
819 BALMLayout::AddItem(BLayoutItem* item)
821 return AddItem(-1, item);
825 bool
826 BALMLayout::AddItem(int32 index, BLayoutItem* item)
828 if (!item)
829 return false;
831 // simply add the item at the upper right corner of the previous item
832 // TODO maybe find a more elegant solution
833 XTab* left = Left();
834 YTab* top = Top();
836 // check range
837 if (index < 0 || index > CountItems())
838 index = CountItems();
840 // for index = 0 we already have set the right tabs
841 if (index != 0) {
842 BLayoutItem* prevItem = ItemAt(index - 1);
843 Area* area = AreaFor(prevItem);
844 if (area) {
845 left = area->Right();
846 top = area->Top();
849 Area* area = AddItem(item, left, top);
850 return area ? true : false;
854 Area*
855 BALMLayout::AddItem(BLayoutItem* item, XTab* _left, YTab* _top, XTab* _right,
856 YTab* _bottom)
858 if ((_left && !_left->IsSuitableFor(this))
859 || (_top && !_top->IsSuitableFor(this))
860 || (_right && !_right->IsSuitableFor(this))
861 || (_bottom && !_bottom->IsSuitableFor(this)))
862 debugger("Tab added to unfriendly layout!");
864 BReference<XTab> right = _right;
865 if (right.Get() == NULL)
866 right = AddXTab();
867 BReference<YTab> bottom = _bottom;
868 if (bottom.Get() == NULL)
869 bottom = AddYTab();
870 BReference<XTab> left = _left;
871 if (left.Get() == NULL)
872 left = AddXTab();
873 BReference<YTab> top = _top;
874 if (top.Get() == NULL)
875 top = AddYTab();
877 TabAddTransaction<XTab> leftTabAdd(this);
878 if (!leftTabAdd.AttempAdd(left))
879 return NULL;
881 TabAddTransaction<YTab> topTabAdd(this);
882 if (!topTabAdd.AttempAdd(top))
883 return NULL;
885 TabAddTransaction<XTab> rightTabAdd(this);
886 if (!rightTabAdd.AttempAdd(right))
887 return NULL;
889 TabAddTransaction<YTab> bottomTabAdd(this);
890 if (!bottomTabAdd.AttempAdd(bottom))
891 return NULL;
893 // Area is added in ItemAdded
894 if (!BAbstractLayout::AddItem(-1, item))
895 return NULL;
896 Area* area = AreaFor(item);
897 if (!area) {
898 RemoveItem(item);
899 return NULL;
902 fSolver->Invalidate(true);
903 area->_Init(Solver(), left, top, right, bottom, fRowColumnManager);
904 fRowColumnManager->AddArea(area);
906 leftTabAdd.Commit();
907 topTabAdd.Commit();
908 rightTabAdd.Commit();
909 bottomTabAdd.Commit();
910 return area;
914 Area*
915 BALMLayout::AddItem(BLayoutItem* item, Row* row, Column* column)
917 if (!BAbstractLayout::AddItem(-1, item))
918 return NULL;
919 Area* area = AreaFor(item);
920 if (!area)
921 return NULL;
923 fSolver->Invalidate(true);
924 area->_Init(Solver(), row, column, fRowColumnManager);
926 fRowColumnManager->AddArea(area);
927 return area;
932 * Gets the left variable.
934 XTab*
935 BALMLayout::Left() const
937 return fLeft;
942 * Gets the right variable.
944 XTab*
945 BALMLayout::Right() const
947 return fRight;
952 * Gets the top variable.
954 YTab*
955 BALMLayout::Top() const
957 return fTop;
962 * Gets the bottom variable.
964 YTab*
965 BALMLayout::Bottom() const
967 return fBottom;
971 void
972 BALMLayout::SetBadLayoutPolicy(BadLayoutPolicy* policy)
974 if (fBadLayoutPolicy != policy)
975 delete fBadLayoutPolicy;
976 if (policy == NULL)
977 policy = new DefaultPolicy();
978 fBadLayoutPolicy = policy;
982 struct BALMLayout::BadLayoutPolicy*
983 BALMLayout::GetBadLayoutPolicy() const
985 return fBadLayoutPolicy;
990 * Gets minimum size.
992 BSize
993 BALMLayout::BaseMinSize()
995 ResultType result = fSolver->ValidateMinSize();
996 if (result != kOptimal && result != kUnbounded)
997 fBadLayoutPolicy->OnBadLayout(this, result, NULL);
998 return fMinSize;
1003 * Gets maximum size.
1005 BSize
1006 BALMLayout::BaseMaxSize()
1008 ResultType result = fSolver->ValidateMaxSize();
1009 if (result != kOptimal && result != kUnbounded)
1010 fBadLayoutPolicy->OnBadLayout(this, result, NULL);
1011 return fMaxSize;
1016 * Gets preferred size.
1018 BSize
1019 BALMLayout::BasePreferredSize()
1021 ResultType result = fSolver->ValidatePreferredSize();
1022 if (result != kOptimal)
1023 fBadLayoutPolicy->OnBadLayout(this, result, NULL);
1025 return fPreferredSize;
1030 * Gets the alignment.
1032 BAlignment
1033 BALMLayout::BaseAlignment()
1035 BAlignment alignment;
1036 alignment.SetHorizontal(B_ALIGN_HORIZONTAL_CENTER);
1037 alignment.SetVertical(B_ALIGN_VERTICAL_CENTER);
1038 return alignment;
1042 status_t
1043 BALMLayout::Archive(BMessage* into, bool deep) const
1045 BArchiver archiver(into);
1046 status_t err = BAbstractLayout::Archive(into, deep);
1047 if (err != B_OK)
1048 return archiver.Finish(err);
1050 BRect insets(fLeftInset, fTopInset, fRightInset, fBottomInset);
1051 err = into->AddRect(kInsetsField, insets);
1052 if (err != B_OK)
1053 return archiver.Finish(err);
1055 BSize spacing(fHSpacing, fVSpacing);
1056 err = into->AddSize(kSpacingField, spacing);
1057 if (err != B_OK)
1058 return archiver.Finish(err);
1060 if (deep) {
1061 for (int32 i = CountXTabs() - 1; i >= 0 && err == B_OK; i--)
1062 err = archiver.AddArchivable(kXTabsField, XTabAt(i));
1064 for (int32 i = CountYTabs() - 1; i >= 0 && err == B_OK; i--)
1065 err = archiver.AddArchivable(kYTabsField, YTabAt(i));
1067 err = archiver.AddArchivable(kBadLayoutPolicyField, fBadLayoutPolicy);
1070 if (err == B_OK)
1071 err = archiver.AddArchivable(kSolverField, fSolver);
1073 if (err == B_OK)
1074 err = archiver.AddArchivable(kMyTabsField, fLeft);
1075 if (err == B_OK)
1076 err = archiver.AddArchivable(kMyTabsField, fTop);
1077 if (err == B_OK)
1078 err = archiver.AddArchivable(kMyTabsField, fRight);
1079 if (err == B_OK)
1080 err = archiver.AddArchivable(kMyTabsField, fBottom);
1082 return archiver.Finish(err);
1086 BArchivable*
1087 BALMLayout::Instantiate(BMessage* from)
1089 if (validate_instantiation(from, "BALM::BALMLayout"))
1090 return new BALMLayout(from);
1091 return NULL;
1095 status_t
1096 BALMLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const
1098 BArchiver archiver(into);
1099 status_t err = BAbstractLayout::ItemArchived(into, item, index);
1100 if (err != B_OK)
1101 return err;
1103 Area* area = AreaFor(item);
1104 err = into->AddSize(kItemPenalties, area->fShrinkPenalties);
1105 if (err == B_OK)
1106 err = into->AddSize(kItemPenalties, area->fGrowPenalties);
1107 if (err == B_OK)
1108 err = into->AddSize(kItemInsets, area->fLeftTopInset);
1109 if (err == B_OK)
1110 err = into->AddSize(kItemInsets, area->fRightBottomInset);
1111 if (err == B_OK)
1112 err = into->AddDouble(kItemAspectRatio, area->fContentAspectRatio);
1114 err = archiver.AddArchivable(kTabsField, area->Left());
1115 if (err == B_OK)
1116 archiver.AddArchivable(kTabsField, area->Top());
1117 if (err == B_OK)
1118 archiver.AddArchivable(kTabsField, area->Right());
1119 if (err == B_OK)
1120 archiver.AddArchivable(kTabsField, area->Bottom());
1122 return err;
1126 status_t
1127 BALMLayout::ItemUnarchived(const BMessage* from, BLayoutItem* item,
1128 int32 index)
1130 BUnarchiver unarchiver(from);
1131 status_t err = BAbstractLayout::ItemUnarchived(from, item, index);
1132 if (err != B_OK)
1133 return err;
1135 Area* area = AreaFor(item);
1136 XTab* left;
1137 XTab* right;
1138 YTab* bottom;
1139 YTab* top;
1140 err = unarchiver.FindObject(kTabsField, index * 4, left);
1141 if (err == B_OK)
1142 err = unarchiver.FindObject(kTabsField, index * 4 + 1, top);
1143 if (err == B_OK)
1144 err = unarchiver.FindObject(kTabsField, index * 4 + 2, right);
1145 if (err == B_OK)
1146 err = unarchiver.FindObject(kTabsField, index * 4 + 3, bottom);
1148 if (err != B_OK)
1149 return err;
1151 area->_Init(Solver(), left, top, right, bottom, fRowColumnManager);
1152 fRowColumnManager->AddArea(area);
1154 err = from->FindSize(kItemPenalties, index * 2, &area->fShrinkPenalties);
1155 if (err != B_OK)
1156 return err;
1158 err = from->FindSize(kItemPenalties, index * 2 + 1, &area->fGrowPenalties);
1159 if (err != B_OK)
1160 return err;
1162 err = from->FindSize(kItemInsets, index * 2, &area->fLeftTopInset);
1163 if (err != B_OK)
1164 return err;
1166 err = from->FindSize(kItemInsets, index * 2 + 1, &area->fRightBottomInset);
1168 if (err == B_OK) {
1169 double contentAspectRatio;
1170 err = from->FindDouble(kItemAspectRatio, index, &contentAspectRatio);
1171 if (err == B_OK)
1172 area->SetContentAspectRatio(contentAspectRatio);
1175 return err;
1179 status_t
1180 BALMLayout::AllUnarchived(const BMessage* archive)
1182 BUnarchiver unarchiver(archive);
1184 SharedSolver* solver;
1185 status_t err = unarchiver.FindObject(kSolverField, solver);
1187 if (err != B_OK)
1188 return err;
1190 _SetSolver(solver);
1192 if (archive->GetInfo(kBadLayoutPolicyField, NULL) == B_OK) {
1193 BadLayoutPolicy* policy;
1194 err = unarchiver.FindObject(kBadLayoutPolicyField, policy);
1195 if (err == B_OK)
1196 SetBadLayoutPolicy(policy);
1199 LinearSpec* spec = Solver();
1200 int32 tabCount = 0;
1201 archive->GetInfo(kXTabsField, NULL, &tabCount);
1202 for (int32 i = 0; i < tabCount && err == B_OK; i++) {
1203 XTab* tab;
1204 err = unarchiver.FindObject(kXTabsField, i,
1205 BUnarchiver::B_DONT_ASSUME_OWNERSHIP, tab);
1206 spec->AddVariable(tab);
1207 TabAddTransaction<XTab> adder(this);
1208 if (adder.AttempAdd(tab))
1209 adder.Commit();
1210 else
1211 err = B_NO_MEMORY;
1214 archive->GetInfo(kYTabsField, NULL, &tabCount);
1215 for (int32 i = 0; i < tabCount; i++) {
1216 YTab* tab;
1217 unarchiver.FindObject(kYTabsField, i,
1218 BUnarchiver::B_DONT_ASSUME_OWNERSHIP, tab);
1219 spec->AddVariable(tab);
1220 TabAddTransaction<YTab> adder(this);
1221 if (adder.AttempAdd(tab))
1222 adder.Commit();
1223 else
1224 err = B_NO_MEMORY;
1228 if (err == B_OK) {
1229 XTab* leftTab = NULL;
1230 err = unarchiver.FindObject(kMyTabsField, 0, leftTab);
1231 fLeft = leftTab;
1234 if (err == B_OK) {
1235 YTab* topTab = NULL;
1236 err = unarchiver.FindObject(kMyTabsField, 1, topTab);
1237 fTop = topTab;
1240 if (err == B_OK) {
1241 XTab* rightTab = NULL;
1242 err = unarchiver.FindObject(kMyTabsField, 2, rightTab);
1243 fRight = rightTab;
1246 if (err == B_OK) {
1247 YTab* bottomTab = NULL;
1248 err = unarchiver.FindObject(kMyTabsField, 3, bottomTab);
1249 fBottom = bottomTab;
1252 if (err == B_OK) {
1253 fLeft->SetRange(0, 0);
1254 fTop->SetRange(0, 0);
1256 err = BAbstractLayout::AllUnarchived(archive);
1258 return err;
1262 status_t
1263 BALMLayout::AllArchived(BMessage* archive) const
1265 status_t err = BAbstractLayout::AllArchived(archive);
1267 return err;
1272 * Invalidates the layout.
1273 * Resets minimum/maximum/preferred size.
1275 void
1276 BALMLayout::LayoutInvalidated(bool children)
1278 fMinSize = kUnsetSize;
1279 fMaxSize = kUnsetSize;
1280 fPreferredSize = kUnsetSize;
1281 fXTabsSorted = false;
1282 fYTabsSorted = false;
1284 if (fSolver)
1285 fSolver->Invalidate(children);
1289 bool
1290 BALMLayout::ItemAdded(BLayoutItem* item, int32 atIndex)
1292 item->SetLayoutData(new(std::nothrow) Area(item));
1293 return item->LayoutData() != NULL;
1297 void
1298 BALMLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex)
1300 if (Area* area = AreaFor(item)) {
1301 fRowColumnManager->RemoveArea(area);
1302 item->SetLayoutData(NULL);
1303 delete area;
1309 * Calculate and set the layout.
1310 * If no layout specification is given, a specification is reverse engineered automatically.
1312 void
1313 BALMLayout::DoLayout()
1315 BLayoutContext* context = LayoutContext();
1316 ResultType result = fSolver->ValidateLayout(context);
1317 if (result != kOptimal
1318 && !fBadLayoutPolicy->OnBadLayout(this, result, context)) {
1319 return;
1322 // set the calculated positions and sizes for every area
1323 for (int32 i = 0; i < CountItems(); i++)
1324 AreaFor(ItemAt(i))->_DoLayout(LayoutArea().LeftTop());
1326 fXTabsSorted = false;
1327 fYTabsSorted = false;
1331 LinearSpec*
1332 BALMLayout::Solver() const
1334 return fSolver->Solver();
1338 ResultType
1339 BALMLayout::ValidateLayout()
1341 // we explicitly recaluclate the layout so set the invalidate flag first
1342 fSolver->Invalidate(true);
1344 BLayoutContext* context = LayoutContext();
1345 return fSolver->ValidateLayout(context);
1349 void
1350 BALMLayout::SetInsets(float left, float top, float right,
1351 float bottom)
1353 fLeftInset = BControlLook::ComposeSpacing(left);
1354 fTopInset = BControlLook::ComposeSpacing(top);
1355 fRightInset = BControlLook::ComposeSpacing(right);
1356 fBottomInset = BControlLook::ComposeSpacing(bottom);
1358 InvalidateLayout();
1362 void
1363 BALMLayout::SetInsets(float horizontal, float vertical)
1365 fLeftInset = BControlLook::ComposeSpacing(horizontal);
1366 fRightInset = fLeftInset;
1368 fTopInset = BControlLook::ComposeSpacing(vertical);
1369 fBottomInset = fTopInset;
1371 InvalidateLayout();
1375 void
1376 BALMLayout::SetInsets(float insets)
1378 fLeftInset = BControlLook::ComposeSpacing(insets);
1379 fRightInset = fLeftInset;
1380 fTopInset = fLeftInset;
1381 fBottomInset = fLeftInset;
1383 InvalidateLayout();
1387 void
1388 BALMLayout::GetInsets(float* left, float* top, float* right,
1389 float* bottom) const
1391 if (left)
1392 *left = fLeftInset;
1393 if (top)
1394 *top = fTopInset;
1395 if (right)
1396 *right = fRightInset;
1397 if (bottom)
1398 *bottom = fBottomInset;
1402 void
1403 BALMLayout::SetSpacing(float hSpacing, float vSpacing)
1405 fHSpacing = BControlLook::ComposeSpacing(hSpacing);
1406 fVSpacing = BControlLook::ComposeSpacing(vSpacing);
1410 void
1411 BALMLayout::GetSpacing(float *_hSpacing, float *_vSpacing) const
1413 if (_hSpacing)
1414 *_hSpacing = fHSpacing;
1415 if (_vSpacing)
1416 *_vSpacing = fVSpacing;
1420 float
1421 BALMLayout::InsetForTab(XTab* tab) const
1423 if (tab == fLeft.Get())
1424 return fLeftInset;
1425 if (tab == fRight.Get())
1426 return fRightInset;
1427 return fHSpacing / 2;
1431 float
1432 BALMLayout::InsetForTab(YTab* tab) const
1434 if (tab == fTop.Get())
1435 return fTopInset;
1436 if (tab == fBottom.Get())
1437 return fBottomInset;
1438 return fVSpacing / 2;
1442 void
1443 BALMLayout::UpdateConstraints(BLayoutContext* context)
1445 for (int i = 0; i < CountItems(); i++)
1446 AreaFor(ItemAt(i))->InvalidateSizeConstraints();
1447 fRowColumnManager->UpdateConstraints();
1451 void BALMLayout::_RemoveSelfFromTab(XTab* tab) { tab->LayoutLeaving(this); }
1452 void BALMLayout::_RemoveSelfFromTab(YTab* tab) { tab->LayoutLeaving(this); }
1454 bool BALMLayout::_HasTabInLayout(XTab* tab) { return tab->IsInLayout(this); }
1455 bool BALMLayout::_HasTabInLayout(YTab* tab) { return tab->IsInLayout(this); }
1457 bool BALMLayout::_AddedTab(XTab* tab) { return tab->AddedToLayout(this); }
1458 bool BALMLayout::_AddedTab(YTab* tab) { return tab->AddedToLayout(this); }
1461 BLayoutItem*
1462 BALMLayout::_LayoutItemToAdd(BView* view)
1464 if (view->GetLayout())
1465 return view->GetLayout();
1466 return new(std::nothrow) BViewLayoutItem(view);
1470 void
1471 BALMLayout::_SetSolver(SharedSolver* solver)
1473 fSolver = solver;
1474 fSolver->AcquireReference();
1475 fSolver->RegisterLayout(this);
1476 fRowColumnManager = new RowColumnManager(Solver());
1480 status_t
1481 BALMLayout::Perform(perform_code d, void* arg)
1483 return BAbstractLayout::Perform(d, arg);
1487 void BALMLayout::_ReservedALMLayout1() {}
1488 void BALMLayout::_ReservedALMLayout2() {}
1489 void BALMLayout::_ReservedALMLayout3() {}
1490 void BALMLayout::_ReservedALMLayout4() {}
1491 void BALMLayout::_ReservedALMLayout5() {}
1492 void BALMLayout::_ReservedALMLayout6() {}
1493 void BALMLayout::_ReservedALMLayout7() {}
1494 void BALMLayout::_ReservedALMLayout8() {}
1495 void BALMLayout::_ReservedALMLayout9() {}
1496 void BALMLayout::_ReservedALMLayout10() {}