2 * Copyright 2006-2010, Ingo Weinhold <ingo_weinhold@gmx.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
7 #include <TwoDimensionalLayout.h>
11 #include <ControlLook.h>
12 #include <LayoutContext.h>
13 #include <LayoutItem.h>
14 #include <LayoutUtils.h>
19 #include <Referenceable.h>
21 #include "CollapsingLayouter.h"
24 // Some words of explanation:
26 // This class is the base class for BLayouts that organize their items
27 // on a grid, with each item covering one or more grid cells (always a
28 // rectangular area). The derived classes only need to implement the
29 // hooks reporting the constraints for the items and additional constraints
30 // for the rows and columns. This class does all the layouting.
32 // The basic idea of the layout process is simple. The horizontal and the
33 // vertical dimensions are laid out independently and the items are set to the
34 // resulting locations and sizes. The "height for width" feature makes the
35 // height depend on the width, which makes things a bit more complicated.
36 // The horizontal dimension must be laid out first and and the results are
37 // fed into the vertical layout process.
39 // The AlignLayoutWith() feature, which allows to align layouts for different
40 // views with each other, causes the need for the three inner *Layouter classes.
41 // For each set of layouts aligned with each other with respect to one
42 // dimension that dimension must be laid out together. The class responsible
43 // is CompoundLayouter; one instance exists per such set. The derived class
44 // VerticalCompoundLayouter is a specialization for the vertical dimension
45 // which additionally takes care of the "height for width" feature. Per layout
46 // a single LocalLayouter exists, which comprises the required glue layout
47 // code and serves as a proxy for the layout, providing service methods
48 // needed by the CompoundLayouter.
50 // TODO: Check for memory leaks!
52 //#define DEBUG_LAYOUT
55 class BTwoDimensionalLayout::CompoundLayouter
: public BReferenceable
{
57 CompoundLayouter(orientation orientation
);
58 virtual ~CompoundLayouter();
60 orientation
Orientation();
62 virtual Layouter
* GetLayouter(bool minMax
);
64 LayoutInfo
* GetLayoutInfo();
66 void AddLocalLayouter(LocalLayouter
* localLayouter
);
67 void RemoveLocalLayouter(
68 LocalLayouter
* localLayouter
);
70 status_t
AddAlignedLayoutsToArchive(BArchiver
* archiver
,
71 LocalLayouter
* requestedBy
);
73 void AbsorbCompoundLayouter(CompoundLayouter
* other
);
75 virtual void InvalidateLayout();
77 void ValidateMinMax();
78 void Layout(float size
, LocalLayouter
* localLayouter
,
79 BLayoutContext
* context
);
82 virtual void DoLayout(float size
,
83 LocalLayouter
* localLayouter
,
84 BLayoutContext
* context
);
87 LayoutInfo
* fLayoutInfo
;
88 orientation fOrientation
;
89 BList fLocalLayouters
;
90 BLayoutContext
* fLayoutContext
;
91 float fLastLayoutSize
;
95 int32
_CountElements();
96 bool _HasMultiElementItems();
98 void _AddConstraints(Layouter
* layouter
);
103 // VerticalCompoundLayouter
104 class BTwoDimensionalLayout::VerticalCompoundLayouter
105 : public CompoundLayouter
, private BLayoutContextListener
{
107 VerticalCompoundLayouter();
109 virtual Layouter
* GetLayouter(bool minMax
);
111 virtual void InvalidateLayout();
113 void InvalidateHeightForWidth();
115 void InternalGetHeightForWidth(
116 LocalLayouter
* localLayouter
,
117 BLayoutContext
* context
,
118 bool realLayout
, float* minHeight
,
119 float* maxHeight
, float* preferredHeight
);
122 virtual void DoLayout(float size
,
123 LocalLayouter
* localLayouter
,
124 BLayoutContext
* context
);
127 Layouter
* fHeightForWidthLayouter
;
128 float fCachedMinHeightForWidth
;
129 float fCachedMaxHeightForWidth
;
130 float fCachedPreferredHeightForWidth
;
131 BLayoutContext
* fHeightForWidthLayoutContext
;
133 bool _HasHeightForWidth();
135 bool _SetHeightForWidthLayoutContext(
136 BLayoutContext
* context
);
138 // BLayoutContextListener
139 virtual void LayoutContextLeft(BLayoutContext
* context
);
143 class BTwoDimensionalLayout::LocalLayouter
: private BLayoutContextListener
{
145 LocalLayouter(BTwoDimensionalLayout
* layout
);
148 // interface for the BTwoDimensionalLayout class
152 BSize
PreferredSize();
154 void InvalidateLayout();
155 void Layout(BSize size
);
157 BRect
ItemFrame(Dimensions itemDimensions
);
159 void ValidateMinMax();
161 void DoHorizontalLayout(float width
);
163 void InternalGetHeightForWidth(float width
,
164 float* minHeight
, float* maxHeight
,
165 float* preferredHeight
);
167 void AlignWith(LocalLayouter
* other
,
168 orientation orientation
);
171 status_t
AddAlignedLayoutsToArchive(BArchiver
* archiver
);
172 status_t
AddOwnerToArchive(BArchiver
* archiver
,
173 CompoundLayouter
* requestedBy
,
174 bool& _wasAvailable
);
175 status_t
AlignLayoutsFromArchive(BUnarchiver
* unarchiver
,
176 orientation posture
);
179 // interface for the compound layout context
182 CompoundLayouter
* compoundLayouter
);
184 CompoundLayouter
* compoundLayouter
);
185 bool HasMultiElementItems(
186 CompoundLayouter
* compoundLayouter
);
189 CompoundLayouter
* compoundLayouter
,
192 float Spacing(CompoundLayouter
* compoundLayouter
);
194 bool HasHeightForWidth();
196 bool AddHeightForWidthConstraints(
197 VerticalCompoundLayouter
* compoundLayouter
,
199 BLayoutContext
* context
);
200 void SetHeightForWidthConstraintsAdded(bool added
);
202 void SetCompoundLayouter(
203 CompoundLayouter
* compoundLayouter
,
204 orientation orientation
);
206 void InternalInvalidateLayout(
207 CompoundLayouter
* compoundLayouter
);
209 // implementation private
211 BTwoDimensionalLayout
* fLayout
;
212 CompoundLayouter
* fHLayouter
;
213 VerticalCompoundLayouter
* fVLayouter
;
214 BList fHeightForWidthItems
;
216 // active layout context when doing last horizontal layout
217 BLayoutContext
* fHorizontalLayoutContext
;
218 float fHorizontalLayoutWidth
;
219 bool fHeightForWidthConstraintsAdded
;
221 void _SetHorizontalLayoutContext(
222 BLayoutContext
* context
, float width
);
224 // BLayoutContextListener
225 virtual void LayoutContextLeft(BLayoutContext
* context
);
231 // archiving constants
233 const char* const kHAlignedLayoutField
= "BTwoDimensionalLayout:"
235 const char* const kVAlignedLayoutField
= "BTwoDimensionalLayout:"
237 const char* const kInsetsField
= "BTwoDimensionalLayout:insets";
238 const char* const kSpacingField
= "BTwoDimensionalLayout:spacing";
239 // kSpacingField = {fHSpacing, fVSpacing}
243 BTwoDimensionalLayout::BTwoDimensionalLayout()
251 fLocalLayouter(new LocalLayouter(this))
256 BTwoDimensionalLayout::BTwoDimensionalLayout(BMessage
* from
)
258 BAbstractLayout(from
),
265 fLocalLayouter(new LocalLayouter(this))
268 from
->FindRect(kInsetsField
, &insets
);
269 SetInsets(insets
.left
, insets
.top
, insets
.right
, insets
.bottom
);
271 from
->FindFloat(kSpacingField
, 0, &fHSpacing
);
272 from
->FindFloat(kSpacingField
, 1, &fVSpacing
);
276 BTwoDimensionalLayout::~BTwoDimensionalLayout()
278 delete fLocalLayouter
;
283 BTwoDimensionalLayout::SetInsets(float left
, float top
, float right
,
286 fLeftInset
= BControlLook::ComposeSpacing(left
);
287 fTopInset
= BControlLook::ComposeSpacing(top
);
288 fRightInset
= BControlLook::ComposeSpacing(right
);
289 fBottomInset
= BControlLook::ComposeSpacing(bottom
);
296 BTwoDimensionalLayout::SetInsets(float horizontal
, float vertical
)
298 fLeftInset
= BControlLook::ComposeSpacing(horizontal
);
299 fRightInset
= fLeftInset
;
301 fTopInset
= BControlLook::ComposeSpacing(vertical
);
302 fBottomInset
= fTopInset
;
309 BTwoDimensionalLayout::SetInsets(float insets
)
311 fLeftInset
= BControlLook::ComposeSpacing(insets
);
312 fRightInset
= fLeftInset
;
313 fTopInset
= fLeftInset
;
314 fBottomInset
= fLeftInset
;
321 BTwoDimensionalLayout::GetInsets(float* left
, float* top
, float* right
,
329 *right
= fRightInset
;
331 *bottom
= fBottomInset
;
336 BTwoDimensionalLayout::AlignLayoutWith(BTwoDimensionalLayout
* other
,
337 orientation orientation
)
339 if (!other
|| other
== this)
342 fLocalLayouter
->AlignWith(other
->fLocalLayouter
, orientation
);
349 BTwoDimensionalLayout::BaseMinSize()
352 return AddInsets(fLocalLayouter
->MinSize());
357 BTwoDimensionalLayout::BaseMaxSize()
360 return AddInsets(fLocalLayouter
->MaxSize());
365 BTwoDimensionalLayout::BasePreferredSize()
368 return AddInsets(fLocalLayouter
->PreferredSize());
373 BTwoDimensionalLayout::BaseAlignment()
375 return BAbstractLayout::BaseAlignment();
380 BTwoDimensionalLayout::HasHeightForWidth()
383 return fLocalLayouter
->HasHeightForWidth();
388 BTwoDimensionalLayout::GetHeightForWidth(float width
, float* min
, float* max
,
391 if (!HasHeightForWidth())
394 float outerSpacing
= fLeftInset
+ fRightInset
- 1;
395 fLocalLayouter
->InternalGetHeightForWidth(BLayoutUtils::SubtractDistances(
396 width
, outerSpacing
), min
, max
, preferred
);
397 AddInsets(min
, max
, preferred
);
402 BTwoDimensionalLayout::SetFrame(BRect frame
)
404 BAbstractLayout::SetFrame(frame
);
409 BTwoDimensionalLayout::Archive(BMessage
* into
, bool deep
) const
411 BArchiver
archiver(into
);
412 status_t err
= BAbstractLayout::Archive(into
, deep
);
415 BRect
insets(fLeftInset
, fTopInset
, fRightInset
, fBottomInset
);
416 err
= into
->AddRect(kInsetsField
, insets
);
420 err
= into
->AddFloat(kSpacingField
, fHSpacing
);
423 err
= into
->AddFloat(kSpacingField
, fVSpacing
);
425 return archiver
.Finish(err
);
430 BTwoDimensionalLayout::AllArchived(BMessage
* into
) const
432 BArchiver
archiver(into
);
434 status_t err
= BLayout::AllArchived(into
);
436 err
= fLocalLayouter
->AddAlignedLayoutsToArchive(&archiver
);
442 BTwoDimensionalLayout::AllUnarchived(const BMessage
* from
)
444 status_t err
= BLayout::AllUnarchived(from
);
448 BUnarchiver
unarchiver(from
);
449 err
= fLocalLayouter
->AlignLayoutsFromArchive(&unarchiver
, B_HORIZONTAL
);
451 err
= fLocalLayouter
->AlignLayoutsFromArchive(&unarchiver
, B_VERTICAL
);
458 BTwoDimensionalLayout::ItemArchived(BMessage
* into
, BLayoutItem
* item
,
461 return BAbstractLayout::ItemArchived(into
, item
, index
);
466 BTwoDimensionalLayout::ItemUnarchived(const BMessage
* from
, BLayoutItem
* item
,
469 return BAbstractLayout::ItemUnarchived(from
, item
, index
);
476 BTwoDimensionalLayout::LayoutInvalidated(bool children
)
478 fLocalLayouter
->InvalidateLayout();
483 BTwoDimensionalLayout::DoLayout()
487 // layout the horizontal/vertical elements
488 BSize
size(SubtractInsets(LayoutArea().Size()));
491 printf("BTwoDimensionalLayout::DerivedLayoutItems(): view: %p"
492 " size: (%.1f, %.1f)\n", View(), size
.Width(), size
.Height());
495 fLocalLayouter
->Layout(size
);
498 BPoint
itemOffset(LayoutArea().LeftTop());
499 int itemCount
= CountItems();
500 for (int i
= 0; i
< itemCount
; i
++) {
501 BLayoutItem
* item
= ItemAt(i
);
502 if (item
->IsVisible()) {
503 Dimensions itemDimensions
;
504 GetItemDimensions(item
, &itemDimensions
);
505 BRect frame
= fLocalLayouter
->ItemFrame(itemDimensions
);
506 frame
.left
+= fLeftInset
;
507 frame
.top
+= fTopInset
;
508 frame
.right
+= fLeftInset
;
509 frame
.bottom
+= fTopInset
;
510 frame
.OffsetBy(itemOffset
);
513 printf(" frame for item %2d (view: %p): ", i
, item
->View());
514 frame
.PrintToStream();
516 //BSize min(item->MinSize());
517 //BSize max(item->MaxSize());
518 //printf(" min: (%.1f, %.1f), max: (%.1f, %.1f)\n", min.width, min.height,
519 // max.width, max.height);
520 //if (item->HasHeightForWidth()) {
521 //float minHeight, maxHeight, preferredHeight;
522 //item->GetHeightForWidth(frame.Width(), &minHeight, &maxHeight,
523 // &preferredHeight);
524 //printf(" hfw: min: %.1f, max: %.1f, pref: %.1f\n", minHeight, maxHeight,
529 item
->AlignInFrame(frame
);
532 //printf(" item %2d not visible", i);
538 BTwoDimensionalLayout::AddInsets(BSize size
)
540 size
.width
= BLayoutUtils::AddDistances(size
.width
,
541 fLeftInset
+ fRightInset
- 1);
542 size
.height
= BLayoutUtils::AddDistances(size
.height
,
543 fTopInset
+ fBottomInset
- 1);
549 BTwoDimensionalLayout::AddInsets(float* minHeight
, float* maxHeight
,
550 float* preferredHeight
)
552 float insets
= fTopInset
+ fBottomInset
- 1;
554 *minHeight
= BLayoutUtils::AddDistances(*minHeight
, insets
);
556 *maxHeight
= BLayoutUtils::AddDistances(*maxHeight
, insets
);
558 *preferredHeight
= BLayoutUtils::AddDistances(*preferredHeight
, insets
);
563 BTwoDimensionalLayout::SubtractInsets(BSize size
)
565 size
.width
= BLayoutUtils::SubtractDistances(size
.width
,
566 fLeftInset
+ fRightInset
- 1);
567 size
.height
= BLayoutUtils::SubtractDistances(size
.height
,
568 fTopInset
+ fBottomInset
- 1);
574 BTwoDimensionalLayout::PrepareItems(orientation orientation
)
580 BTwoDimensionalLayout::HasMultiColumnItems()
587 BTwoDimensionalLayout::HasMultiRowItems()
594 BTwoDimensionalLayout::_ValidateMinMax()
596 fLocalLayouter
->ValidateMinMax();
600 // #pragma mark - CompoundLayouter
603 BTwoDimensionalLayout::CompoundLayouter::CompoundLayouter(
604 orientation orientation
)
608 fOrientation(orientation
),
610 fLayoutContext(NULL
),
616 BTwoDimensionalLayout::CompoundLayouter::~CompoundLayouter()
624 BTwoDimensionalLayout::CompoundLayouter::Orientation()
631 BTwoDimensionalLayout::CompoundLayouter::GetLayouter(bool minMax
)
638 BTwoDimensionalLayout::CompoundLayouter::GetLayoutInfo()
645 BTwoDimensionalLayout::CompoundLayouter::AddLocalLayouter(
646 LocalLayouter
* localLayouter
)
649 if (!fLocalLayouters
.HasItem(localLayouter
)) {
650 fLocalLayouters
.AddItem(localLayouter
);
658 BTwoDimensionalLayout::CompoundLayouter::RemoveLocalLayouter(
659 LocalLayouter
* localLayouter
)
661 if (fLocalLayouters
.RemoveItem(localLayouter
))
667 BTwoDimensionalLayout::CompoundLayouter::AddAlignedLayoutsToArchive(
668 BArchiver
* archiver
, LocalLayouter
* requestedBy
)
670 // The LocalLayouter* that really owns us is at index 0, layouts
671 // at other indices are aligned to this one.
672 if (requestedBy
!= fLocalLayouters
.ItemAt(0))
676 for (int32 i
= fLocalLayouters
.CountItems() - 1; i
> 0; i
--) {
677 LocalLayouter
* layouter
= (LocalLayouter
*)fLocalLayouters
.ItemAt(i
);
680 err
= layouter
->AddOwnerToArchive(archiver
, this, wasAvailable
);
681 if (err
!= B_OK
&& wasAvailable
)
689 BTwoDimensionalLayout::CompoundLayouter::AbsorbCompoundLayouter(
690 CompoundLayouter
* other
)
695 int32 count
= other
->fLocalLayouters
.CountItems();
696 for (int32 i
= count
- 1; i
>= 0; i
--) {
697 LocalLayouter
* layouter
698 = (LocalLayouter
*)other
->fLocalLayouters
.ItemAt(i
);
699 AddLocalLayouter(layouter
);
700 layouter
->SetCompoundLayouter(this, fOrientation
);
708 BTwoDimensionalLayout::CompoundLayouter::InvalidateLayout()
718 fLayoutContext
= NULL
;
720 // notify all local layouters to invalidate the respective views
721 int32 count
= fLocalLayouters
.CountItems();
722 for (int32 i
= 0; i
< count
; i
++) {
723 LocalLayouter
* layouter
= (LocalLayouter
*)fLocalLayouters
.ItemAt(i
);
724 layouter
->InternalInvalidateLayout(this);
730 BTwoDimensionalLayout::CompoundLayouter::IsMinMaxValid()
732 return (fLayouter
!= NULL
);
737 BTwoDimensionalLayout::CompoundLayouter::ValidateMinMax()
742 fLastLayoutSize
= -1;
744 // create the layouter
747 int elementCount
= _CountElements();
749 fLayouter
= new CollapsingLayouter(elementCount
, _Spacing());
751 // tell the layouter about our constraints
752 // TODO: We should probably ignore local layouters whose view is hidden.
753 // It's a bit tricky to find out, whether the view is hidden, though, since
754 // this doesn't necessarily mean only hidden relative to the parent, but
755 // hidden relative to a common parent.
756 _AddConstraints(fLayouter
);
758 fLayoutInfo
= fLayouter
->CreateLayoutInfo();
763 BTwoDimensionalLayout::CompoundLayouter::Layout(float size
,
764 LocalLayouter
* localLayouter
, BLayoutContext
* context
)
768 if (context
!= fLayoutContext
|| fLastLayoutSize
!= size
) {
769 DoLayout(size
, localLayouter
, context
);
770 fLayoutContext
= context
;
771 fLastLayoutSize
= size
;
777 BTwoDimensionalLayout::CompoundLayouter::DoLayout(float size
,
778 LocalLayouter
* localLayouter
, BLayoutContext
* context
)
780 fLayouter
->Layout(fLayoutInfo
, size
);
785 BTwoDimensionalLayout::CompoundLayouter::_PrepareItems()
787 int32 count
= fLocalLayouters
.CountItems();
788 for (int32 i
= 0; i
< count
; i
++) {
789 LocalLayouter
* layouter
= (LocalLayouter
*)fLocalLayouters
.ItemAt(i
);
790 layouter
->PrepareItems(this);
796 BTwoDimensionalLayout::CompoundLayouter::_CountElements()
798 int32 elementCount
= 0;
799 int32 count
= fLocalLayouters
.CountItems();
800 for (int32 i
= 0; i
< count
; i
++) {
801 LocalLayouter
* layouter
= (LocalLayouter
*)fLocalLayouters
.ItemAt(i
);
802 int32 layouterCount
= layouter
->CountElements(this);
803 elementCount
= max_c(elementCount
, layouterCount
);
811 BTwoDimensionalLayout::CompoundLayouter::_HasMultiElementItems()
813 int32 count
= fLocalLayouters
.CountItems();
814 for (int32 i
= 0; i
< count
; i
++) {
815 LocalLayouter
* layouter
= (LocalLayouter
*)fLocalLayouters
.ItemAt(i
);
816 if (layouter
->HasMultiElementItems(this))
825 BTwoDimensionalLayout::CompoundLayouter::_AddConstraints(Layouter
* layouter
)
827 int32 count
= fLocalLayouters
.CountItems();
828 for (int32 i
= 0; i
< count
; i
++) {
829 LocalLayouter
* localLayouter
= (LocalLayouter
*)fLocalLayouters
.ItemAt(i
);
830 localLayouter
->AddConstraints(this, layouter
);
836 BTwoDimensionalLayout::CompoundLayouter::_Spacing()
838 if (!fLocalLayouters
.IsEmpty())
839 return ((LocalLayouter
*)fLocalLayouters
.ItemAt(0))->Spacing(this);
844 // #pragma mark - VerticalCompoundLayouter
847 BTwoDimensionalLayout::VerticalCompoundLayouter::VerticalCompoundLayouter()
849 CompoundLayouter(B_VERTICAL
),
850 fHeightForWidthLayouter(NULL
),
851 fCachedMinHeightForWidth(0),
852 fCachedMaxHeightForWidth(0),
853 fCachedPreferredHeightForWidth(0),
854 fHeightForWidthLayoutContext(NULL
)
860 BTwoDimensionalLayout::VerticalCompoundLayouter::GetLayouter(bool minMax
)
862 return (minMax
|| !_HasHeightForWidth()
863 ? fLayouter
: fHeightForWidthLayouter
);
868 BTwoDimensionalLayout::VerticalCompoundLayouter::InvalidateLayout()
870 CompoundLayouter::InvalidateLayout();
872 InvalidateHeightForWidth();
877 BTwoDimensionalLayout::VerticalCompoundLayouter::InvalidateHeightForWidth()
879 if (fHeightForWidthLayouter
!= NULL
) {
880 delete fHeightForWidthLayouter
;
881 fHeightForWidthLayouter
= NULL
;
883 // also make sure we're not reusing the old layout info
884 fLastLayoutSize
= -1;
886 int32 count
= fLocalLayouters
.CountItems();
887 for (int32 i
= 0; i
< count
; i
++) {
888 LocalLayouter
* layouter
= (LocalLayouter
*)fLocalLayouters
.ItemAt(i
);
889 layouter
->SetHeightForWidthConstraintsAdded(false);
896 BTwoDimensionalLayout::VerticalCompoundLayouter::InternalGetHeightForWidth(
897 LocalLayouter
* localLayouter
, BLayoutContext
* context
, bool realLayout
,
898 float* minHeight
, float* maxHeight
, float* preferredHeight
)
900 bool updateCachedInfo
= false;
902 if (_SetHeightForWidthLayoutContext(context
)
903 || fHeightForWidthLayouter
== NULL
) {
904 // Either the layout context changed or we haven't initialized the
905 // height for width layouter yet. We create it and init it now.
907 // clone the vertical layouter
908 delete fHeightForWidthLayouter
;
910 fHeightForWidthLayouter
= fLayouter
->CloneLayouter();
911 fLayoutInfo
= fHeightForWidthLayouter
->CreateLayoutInfo();
913 // add the children's height for width constraints
914 int32 count
= fLocalLayouters
.CountItems();
915 for (int32 i
= 0; i
< count
; i
++) {
916 LocalLayouter
* layouter
= (LocalLayouter
*)fLocalLayouters
.ItemAt(i
);
917 if (layouter
->HasHeightForWidth()) {
918 layouter
->AddHeightForWidthConstraints(this,
919 fHeightForWidthLayouter
, context
);
923 updateCachedInfo
= true;
924 } else if (localLayouter
->HasHeightForWidth()) {
925 // There is a height for width layouter and it has been initialized
926 // in the current layout context. So we just add the height for width
927 // constraints of the calling local layouter, if they haven't been
929 updateCachedInfo
= localLayouter
->AddHeightForWidthConstraints(this,
930 fHeightForWidthLayouter
, context
);
933 // update cached height for width info, if something changed
934 if (updateCachedInfo
) {
935 // get the height for width info
936 fCachedMinHeightForWidth
= fHeightForWidthLayouter
->MinSize();
937 fCachedMaxHeightForWidth
= fHeightForWidthLayouter
->MaxSize();
938 fCachedPreferredHeightForWidth
939 = fHeightForWidthLayouter
->PreferredSize();
943 *minHeight
= fCachedMinHeightForWidth
;
945 *maxHeight
= fCachedMaxHeightForWidth
;
947 *preferredHeight
= fCachedPreferredHeightForWidth
;
952 BTwoDimensionalLayout::VerticalCompoundLayouter::DoLayout(float size
,
953 LocalLayouter
* localLayouter
, BLayoutContext
* context
)
956 if (_HasHeightForWidth()) {
957 float minHeight
, maxHeight
, preferredHeight
;
958 InternalGetHeightForWidth(localLayouter
, context
, true, &minHeight
,
959 &maxHeight
, &preferredHeight
);
960 size
= max_c(size
, minHeight
);
961 layouter
= fHeightForWidthLayouter
;
963 layouter
= fLayouter
;
965 layouter
->Layout(fLayoutInfo
, size
);
970 BTwoDimensionalLayout::VerticalCompoundLayouter::_HasHeightForWidth()
972 int32 count
= fLocalLayouters
.CountItems();
973 for (int32 i
= 0; i
< count
; i
++) {
974 LocalLayouter
* layouter
= (LocalLayouter
*)fLocalLayouters
.ItemAt(i
);
975 if (layouter
->HasHeightForWidth())
984 BTwoDimensionalLayout::VerticalCompoundLayouter
985 ::_SetHeightForWidthLayoutContext(BLayoutContext
* context
)
987 if (context
== fHeightForWidthLayoutContext
)
990 if (fHeightForWidthLayoutContext
!= NULL
) {
991 fHeightForWidthLayoutContext
->RemoveListener(this);
992 fHeightForWidthLayoutContext
= NULL
;
995 // We can ignore the whole context business, if we have no more than one
996 // local layouter. We use the layout context only to recognize when calls
997 // of different local layouters belong to the same context.
998 if (fLocalLayouters
.CountItems() <= 1)
1001 fHeightForWidthLayoutContext
= context
;
1003 if (fHeightForWidthLayoutContext
!= NULL
)
1004 fHeightForWidthLayoutContext
->AddListener(this);
1006 InvalidateHeightForWidth();
1013 BTwoDimensionalLayout::VerticalCompoundLayouter::LayoutContextLeft(
1014 BLayoutContext
* context
)
1016 fHeightForWidthLayoutContext
= NULL
;
1020 // #pragma mark - LocalLayouter
1023 BTwoDimensionalLayout::LocalLayouter::LocalLayouter(
1024 BTwoDimensionalLayout
* layout
)
1027 fHLayouter(new CompoundLayouter(B_HORIZONTAL
)),
1028 fVLayouter(new VerticalCompoundLayouter
),
1029 fHeightForWidthItems(),
1030 fHorizontalLayoutContext(NULL
),
1031 fHorizontalLayoutWidth(0),
1032 fHeightForWidthConstraintsAdded(false)
1034 fHLayouter
->AddLocalLayouter(this);
1035 fVLayouter
->AddLocalLayouter(this);
1039 BTwoDimensionalLayout::LocalLayouter::~LocalLayouter()
1041 if (fHLayouter
!= NULL
) {
1042 fHLayouter
->RemoveLocalLayouter(this);
1043 fHLayouter
->ReleaseReference();
1046 if (fVLayouter
!= NULL
) {
1047 fVLayouter
->RemoveLocalLayouter(this);
1048 fVLayouter
->ReleaseReference();
1054 BTwoDimensionalLayout::LocalLayouter::MinSize()
1056 return BSize(fHLayouter
->GetLayouter(true)->MinSize(),
1057 fVLayouter
->GetLayouter(true)->MinSize());
1062 BTwoDimensionalLayout::LocalLayouter::MaxSize()
1064 return BSize(fHLayouter
->GetLayouter(true)->MaxSize(),
1065 fVLayouter
->GetLayouter(true)->MaxSize());
1070 BTwoDimensionalLayout::LocalLayouter::PreferredSize()
1072 return BSize(fHLayouter
->GetLayouter(true)->PreferredSize(),
1073 fVLayouter
->GetLayouter(true)->PreferredSize());
1078 BTwoDimensionalLayout::LocalLayouter::InvalidateLayout()
1080 fHLayouter
->InvalidateLayout();
1081 fVLayouter
->InvalidateLayout();
1086 BTwoDimensionalLayout::LocalLayouter::Layout(BSize size
)
1088 DoHorizontalLayout(size
.width
);
1089 fVLayouter
->Layout(size
.height
, this, fLayout
->LayoutContext());
1094 BTwoDimensionalLayout::LocalLayouter::ItemFrame(Dimensions itemDimensions
)
1096 LayoutInfo
* hLayoutInfo
= fHLayouter
->GetLayoutInfo();
1097 LayoutInfo
* vLayoutInfo
= fVLayouter
->GetLayoutInfo();
1098 float x
= hLayoutInfo
->ElementLocation(itemDimensions
.x
);
1099 float y
= vLayoutInfo
->ElementLocation(itemDimensions
.y
);
1100 float width
= hLayoutInfo
->ElementRangeSize(itemDimensions
.x
,
1101 itemDimensions
.width
);
1102 float height
= vLayoutInfo
->ElementRangeSize(itemDimensions
.y
,
1103 itemDimensions
.height
);
1104 return BRect(x
, y
, x
+ width
, y
+ height
);
1109 BTwoDimensionalLayout::LocalLayouter::ValidateMinMax()
1111 if (fHLayouter
->IsMinMaxValid() && fVLayouter
->IsMinMaxValid())
1114 if (!fHLayouter
->IsMinMaxValid())
1115 fHeightForWidthItems
.MakeEmpty();
1117 _SetHorizontalLayoutContext(NULL
, -1);
1119 fHLayouter
->ValidateMinMax();
1120 fVLayouter
->ValidateMinMax();
1121 fLayout
->ResetLayoutInvalidation();
1126 BTwoDimensionalLayout::LocalLayouter::DoHorizontalLayout(float width
)
1128 BLayoutContext
* context
= fLayout
->LayoutContext();
1129 if (fHorizontalLayoutContext
!= context
1130 || width
!= fHorizontalLayoutWidth
) {
1131 _SetHorizontalLayoutContext(context
, width
);
1132 fHLayouter
->Layout(width
, this, context
);
1133 fVLayouter
->InvalidateHeightForWidth();
1139 BTwoDimensionalLayout::LocalLayouter::InternalGetHeightForWidth(float width
,
1140 float* minHeight
, float* maxHeight
, float* preferredHeight
)
1142 DoHorizontalLayout(width
);
1143 fVLayouter
->InternalGetHeightForWidth(this, fHorizontalLayoutContext
, false,
1144 minHeight
, maxHeight
, preferredHeight
);
1149 BTwoDimensionalLayout::LocalLayouter::AlignWith(LocalLayouter
* other
,
1150 orientation orientation
)
1152 if (orientation
== B_HORIZONTAL
)
1153 other
->fHLayouter
->AbsorbCompoundLayouter(fHLayouter
);
1155 other
->fVLayouter
->AbsorbCompoundLayouter(fVLayouter
);
1160 BTwoDimensionalLayout::LocalLayouter::AddAlignedLayoutsToArchive(
1161 BArchiver
* archiver
)
1163 status_t err
= fHLayouter
->AddAlignedLayoutsToArchive(archiver
, this);
1166 err
= fVLayouter
->AddAlignedLayoutsToArchive(archiver
, this);
1173 BTwoDimensionalLayout::LocalLayouter::AddOwnerToArchive(BArchiver
* archiver
,
1174 CompoundLayouter
* requestedBy
, bool& _wasAvailable
)
1176 const char* field
= kHAlignedLayoutField
;
1177 if (requestedBy
== fVLayouter
)
1178 field
= kVAlignedLayoutField
;
1180 if ((_wasAvailable
= archiver
->IsArchived(fLayout
)))
1181 return archiver
->AddArchivable(field
, fLayout
);
1183 return B_NAME_NOT_FOUND
;
1188 BTwoDimensionalLayout::LocalLayouter::AlignLayoutsFromArchive(
1189 BUnarchiver
* unarchiver
, orientation posture
)
1191 const char* field
= kHAlignedLayoutField
;
1192 if (posture
== B_VERTICAL
)
1193 field
= kVAlignedLayoutField
;
1196 status_t err
= unarchiver
->ArchiveMessage()->GetInfo(field
, NULL
, &count
);
1197 if (err
== B_NAME_NOT_FOUND
)
1200 BTwoDimensionalLayout
* retriever
;
1201 for (int32 i
= 0; i
< count
&& err
== B_OK
; i
++) {
1202 err
= unarchiver
->FindObject(field
, i
,
1203 BUnarchiver::B_DONT_ASSUME_OWNERSHIP
, retriever
);
1206 retriever
->AlignLayoutWith(fLayout
, posture
);
1214 BTwoDimensionalLayout::LocalLayouter::PrepareItems(
1215 CompoundLayouter
* compoundLayouter
)
1217 fLayout
->PrepareItems(compoundLayouter
->Orientation());
1222 BTwoDimensionalLayout::LocalLayouter::CountElements(
1223 CompoundLayouter
* compoundLayouter
)
1225 if (compoundLayouter
->Orientation() == B_HORIZONTAL
)
1226 return fLayout
->InternalCountColumns();
1228 return fLayout
->InternalCountRows();
1233 BTwoDimensionalLayout::LocalLayouter::HasMultiElementItems(
1234 CompoundLayouter
* compoundLayouter
)
1236 if (compoundLayouter
->Orientation() == B_HORIZONTAL
)
1237 return fLayout
->HasMultiColumnItems();
1239 return fLayout
->HasMultiRowItems();
1244 BTwoDimensionalLayout::LocalLayouter::AddConstraints(
1245 CompoundLayouter
* compoundLayouter
, Layouter
* layouter
)
1247 enum orientation orientation
= compoundLayouter
->Orientation();
1248 int itemCount
= fLayout
->CountItems();
1249 if (itemCount
> 0) {
1250 for (int i
= 0; i
< itemCount
; i
++) {
1251 BLayoutItem
* item
= fLayout
->ItemAt(i
);
1252 if (item
->IsVisible()) {
1253 Dimensions itemDimensions
;
1254 fLayout
->GetItemDimensions(item
, &itemDimensions
);
1256 BSize min
= item
->MinSize();
1257 BSize max
= item
->MaxSize();
1258 BSize preferred
= item
->PreferredSize();
1260 if (orientation
== B_HORIZONTAL
) {
1261 layouter
->AddConstraints(
1263 itemDimensions
.width
,
1268 if (item
->HasHeightForWidth())
1269 fHeightForWidthItems
.AddItem(item
);
1272 layouter
->AddConstraints(
1274 itemDimensions
.height
,
1282 // add column/row constraints
1283 ColumnRowConstraints constraints
;
1284 int elementCount
= CountElements(compoundLayouter
);
1285 for (int element
= 0; element
< elementCount
; element
++) {
1286 fLayout
->GetColumnRowConstraints(orientation
, element
,
1288 layouter
->SetWeight(element
, constraints
.weight
);
1289 layouter
->AddConstraints(element
, 1, constraints
.min
,
1290 constraints
.max
, constraints
.min
);
1297 BTwoDimensionalLayout::LocalLayouter::Spacing(
1298 CompoundLayouter
* compoundLayouter
)
1300 return (compoundLayouter
->Orientation() == B_HORIZONTAL
1301 ? fLayout
->fHSpacing
: fLayout
->fVSpacing
);
1306 BTwoDimensionalLayout::LocalLayouter::HasHeightForWidth()
1308 return !fHeightForWidthItems
.IsEmpty();
1313 BTwoDimensionalLayout::LocalLayouter::AddHeightForWidthConstraints(
1314 VerticalCompoundLayouter
* compoundLayouter
, Layouter
* layouter
,
1315 BLayoutContext
* context
)
1317 if (context
!= fHorizontalLayoutContext
)
1320 if (fHeightForWidthConstraintsAdded
)
1323 LayoutInfo
* hLayoutInfo
= fHLayouter
->GetLayoutInfo();
1325 // add the children's height for width constraints
1326 int32 itemCount
= fHeightForWidthItems
.CountItems();
1327 for (int32 i
= 0; i
< itemCount
; i
++) {
1328 BLayoutItem
* item
= (BLayoutItem
*)fHeightForWidthItems
.ItemAt(i
);
1329 Dimensions itemDimensions
;
1330 fLayout
->GetItemDimensions(item
, &itemDimensions
);
1332 float minHeight
, maxHeight
, preferredHeight
;
1333 item
->GetHeightForWidth(
1334 hLayoutInfo
->ElementRangeSize(itemDimensions
.x
,
1335 itemDimensions
.width
),
1336 &minHeight
, &maxHeight
, &preferredHeight
);
1337 layouter
->AddConstraints(
1339 itemDimensions
.height
,
1345 SetHeightForWidthConstraintsAdded(true);
1352 BTwoDimensionalLayout::LocalLayouter::SetHeightForWidthConstraintsAdded(
1355 fHeightForWidthConstraintsAdded
= added
;
1360 BTwoDimensionalLayout::LocalLayouter::SetCompoundLayouter(
1361 CompoundLayouter
* compoundLayouter
, orientation orientation
)
1363 CompoundLayouter
* oldCompoundLayouter
;
1364 if (orientation
== B_HORIZONTAL
) {
1365 oldCompoundLayouter
= fHLayouter
;
1366 fHLayouter
= compoundLayouter
;
1368 oldCompoundLayouter
= fVLayouter
;
1369 fVLayouter
= static_cast<VerticalCompoundLayouter
*>(compoundLayouter
);
1372 if (compoundLayouter
== oldCompoundLayouter
)
1375 if (oldCompoundLayouter
!= NULL
) {
1376 oldCompoundLayouter
->RemoveLocalLayouter(this);
1377 oldCompoundLayouter
->ReleaseReference();
1380 if (compoundLayouter
!= NULL
)
1381 compoundLayouter
->AcquireReference();
1383 InternalInvalidateLayout(compoundLayouter
);
1388 BTwoDimensionalLayout::LocalLayouter::InternalInvalidateLayout(
1389 CompoundLayouter
* compoundLayouter
)
1391 _SetHorizontalLayoutContext(NULL
, -1);
1393 fLayout
->BLayout::InvalidateLayout();
1398 BTwoDimensionalLayout::LocalLayouter::_SetHorizontalLayoutContext(
1399 BLayoutContext
* context
, float width
)
1401 if (context
!= fHorizontalLayoutContext
) {
1402 if (fHorizontalLayoutContext
!= NULL
)
1403 fHorizontalLayoutContext
->RemoveListener(this);
1405 fHorizontalLayoutContext
= context
;
1407 if (fHorizontalLayoutContext
!= NULL
)
1408 fHorizontalLayoutContext
->AddListener(this);
1411 fHorizontalLayoutWidth
= width
;
1416 BTwoDimensionalLayout::LocalLayouter::LayoutContextLeft(BLayoutContext
* context
)
1418 fHorizontalLayoutContext
= NULL
;
1419 fHorizontalLayoutWidth
= -1;
1424 BTwoDimensionalLayout::Perform(perform_code code
, void* _data
)
1426 return BAbstractLayout::Perform(code
, _data
);
1430 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout1() {}
1431 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout2() {}
1432 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout3() {}
1433 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout4() {}
1434 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout5() {}
1435 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout6() {}
1436 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout7() {}
1437 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout8() {}
1438 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout9() {}
1439 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout10() {}