2 * Copyright 2011, Haiku, Inc.
3 * All rights reserved. Distributed under the terms of the MIT License.
6 #include "CollapsingLayouter.h"
8 #include "ComplexLayouter.h"
9 #include "OneElementLayouter.h"
10 #include "SimpleLayouter.h"
12 #include <ObjectList.h>
16 class CollapsingLayouter::ProxyLayoutInfo
: public LayoutInfo
{
18 ProxyLayoutInfo(LayoutInfo
* target
, int32 elementCount
)
21 fElementCount(elementCount
)
23 fElements
= new int32
[elementCount
];
33 LayoutTarget(Layouter
* layouter
, float size
)
36 layouter
->Layout(fTarget
, size
);
40 SetElementPosition(int32 element
, int32 position
)
42 fElements
[element
] = position
;
46 ElementLocation(int32 element
)
48 if (element
< 0 || element
>= fElementCount
|| fElements
[element
] < 0)
50 return fTarget
->ElementLocation(fElements
[element
]);
54 ElementSize(int32 element
)
56 if (element
< 0 || element
>= fElementCount
|| fElements
[element
] < 0)
58 return fTarget
->ElementSize(fElements
[element
]);
62 ElementRangeSize(int32 element
, int32 length
)
64 if (element
< 0 || element
>= fElementCount
|| fElements
[element
] < 0)
66 return fTarget
->ElementRangeSize(fElements
[element
], length
);
76 struct CollapsingLayouter::Constraint
{
84 struct CollapsingLayouter::ElementInfo
{
88 BObjectList
<Constraint
> constraints
;
103 void SetTo(const ElementInfo
& other
)
105 weight
= other
.weight
;
106 position
= other
.position
;
108 for (int32 i
= other
.constraints
.CountItems() - 1; i
>= 0; i
--)
109 constraints
.AddItem(new Constraint(*other
.constraints
.ItemAt(i
)));
114 CollapsingLayouter::CollapsingLayouter(int32 elementCount
, float spacing
)
116 fElementCount(elementCount
),
117 fElements(new ElementInfo
[elementCount
]),
118 fValidElementCount(0),
119 fHaveMultiElementConstraints(false),
126 CollapsingLayouter::~CollapsingLayouter()
134 CollapsingLayouter::AddConstraints(int32 element
, int32 length
, float min
,
135 float max
, float preferred
)
137 if (min
== B_SIZE_UNSET
&& max
== B_SIZE_UNSET
)
139 if (element
< 0 || length
<= 0 || element
+ length
> fElementCount
)
142 Constraint
* constraint
= new Constraint();
143 constraint
->length
= length
;
144 constraint
->min
= min
;
145 constraint
->max
= max
;
146 constraint
->preferred
= preferred
;
149 fHaveMultiElementConstraints
= true;
151 int32 validElements
= fValidElementCount
;
153 for (int32 i
= element
; i
< element
+ length
; i
++) {
154 if (fElements
[i
].valid
== false) {
155 fElements
[i
].valid
= true;
156 fValidElementCount
++;
160 fElements
[element
].constraints
.AddItem(constraint
);
161 if (fValidElementCount
> validElements
) {
167 _AddConstraints(element
, constraint
);
173 CollapsingLayouter::SetWeight(int32 element
, float weight
)
175 if (element
< 0 || element
>= fElementCount
)
178 ElementInfo
& elementInfo
= fElements
[element
];
179 elementInfo
.weight
= weight
;
181 if (fLayouter
&& elementInfo
.position
>= 0)
182 fLayouter
->SetWeight(elementInfo
.position
, weight
);
187 CollapsingLayouter::MinSize()
190 return fLayouter
? fLayouter
->MinSize() : 0;
195 CollapsingLayouter::MaxSize()
198 return fLayouter
? fLayouter
->MaxSize() : B_SIZE_UNLIMITED
;
203 CollapsingLayouter::PreferredSize()
206 return fLayouter
? fLayouter
->PreferredSize() : 0;
211 CollapsingLayouter::CreateLayoutInfo()
215 LayoutInfo
* info
= fLayouter
? fLayouter
->CreateLayoutInfo() : NULL
;
216 return new ProxyLayoutInfo(info
, fElementCount
);
221 CollapsingLayouter::Layout(LayoutInfo
* layoutInfo
, float size
)
224 ProxyLayoutInfo
* info
= static_cast<ProxyLayoutInfo
*>(layoutInfo
);
225 for (int32 i
= 0; i
< fElementCount
; i
++) {
226 info
->SetElementPosition(i
, fElements
[i
].position
);
229 info
->LayoutTarget(fLayouter
, size
);
234 CollapsingLayouter::CloneLayouter()
236 CollapsingLayouter
* clone
= new CollapsingLayouter(fElementCount
, fSpacing
);
237 for (int32 i
= 0; i
< fElementCount
; i
++)
238 clone
->fElements
[i
].SetTo(fElements
[i
]);
240 clone
->fValidElementCount
= fValidElementCount
;
241 clone
->fHaveMultiElementConstraints
= fHaveMultiElementConstraints
;
244 clone
->fLayouter
= fLayouter
->CloneLayouter();
250 CollapsingLayouter::_ValidateLayouter()
263 CollapsingLayouter::_CreateLayouter()
268 if (fValidElementCount
== 0) {
270 } else if (fValidElementCount
== 1) {
271 fLayouter
= new OneElementLayouter();
272 } else if (fHaveMultiElementConstraints
) {
273 fLayouter
= new ComplexLayouter(fValidElementCount
, fSpacing
);
275 fLayouter
= new SimpleLayouter(fValidElementCount
, fSpacing
);
283 CollapsingLayouter::_DoCollapse()
286 for (int32 i
= 0; i
< fElementCount
; i
++) {
287 ElementInfo
& element
= fElements
[i
];
288 if (!element
.valid
) {
290 element
.position
= -1;
293 element
.position
= i
- shift
;
300 CollapsingLayouter::_AddConstraints()
302 if (fLayouter
== NULL
)
305 for (int32 i
= 0; i
< fElementCount
; i
++) {
306 ElementInfo
& element
= fElements
[i
];
307 for (int32 i
= element
.constraints
.CountItems() - 1; i
>= 0; i
--)
308 _AddConstraints(element
.position
, element
.constraints
.ItemAt(i
));
314 CollapsingLayouter::_AddConstraints(int32 position
, const Constraint
* c
)
316 fLayouter
->AddConstraints(position
, c
->length
, c
->min
, c
->max
,
322 CollapsingLayouter::_SetWeights()
327 for (int32 i
= 0; i
< fElementCount
; i
++) {
328 fLayouter
->SetWeight(fElements
[i
].position
, fElements
[i
].weight
);