1/*
2 * Copyright 2010 Haiku, Inc. All rights reserved.
3 * Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
4 *
5 * Distributed under the terms of the MIT License.
6 */
7
8
9#include <GroupLayout.h>
10
11#include <ControlLook.h>
12#include <LayoutItem.h>
13#include <Message.h>
14
15#include <new>
16
17
18using std::nothrow;
19
20
21namespace {
22	const char* const kItemWeightField = "BGroupLayout:item:weight";
23	const char* const kVerticalField = "BGroupLayout:vertical";
24}
25
26
27struct BGroupLayout::ItemLayoutData {
28	float	weight;
29
30	ItemLayoutData()
31		: weight(1)
32	{
33	}
34};
35
36
37BGroupLayout::BGroupLayout(orientation orientation, float spacing)
38	:
39	BTwoDimensionalLayout(),
40	fOrientation(orientation)
41{
42	SetSpacing(spacing);
43}
44
45
46BGroupLayout::BGroupLayout(BMessage* from)
47	:
48	BTwoDimensionalLayout(from)
49{
50	bool isVertical;
51	if (from->FindBool(kVerticalField, &isVertical) != B_OK)
52		isVertical = false;
53	fOrientation = isVertical ? B_VERTICAL : B_HORIZONTAL;
54}
55
56
57BGroupLayout::~BGroupLayout()
58{
59}
60
61
62float
63BGroupLayout::Spacing() const
64{
65	return fHSpacing;
66}
67
68
69void
70BGroupLayout::SetSpacing(float spacing)
71{
72	spacing = BControlLook::ComposeSpacing(spacing);
73	if (spacing != fHSpacing) {
74		fHSpacing = spacing;
75		fVSpacing = spacing;
76		InvalidateLayout();
77	}
78}
79
80
81orientation
82BGroupLayout::Orientation() const
83{
84	return fOrientation;
85}
86
87
88void
89BGroupLayout::SetOrientation(orientation orientation)
90{
91	if (orientation != fOrientation) {
92		fOrientation = orientation;
93
94		InvalidateLayout();
95	}
96}
97
98
99float
100BGroupLayout::ItemWeight(int32 index) const
101{
102	if (index < 0 || index >= CountItems())
103		return 0;
104
105	ItemLayoutData* data = _LayoutDataForItem(ItemAt(index));
106	return (data ? data->weight : 0);
107}
108
109
110void
111BGroupLayout::SetItemWeight(int32 index, float weight)
112{
113	if (index < 0 || index >= CountItems())
114		return;
115
116	if (ItemLayoutData* data = _LayoutDataForItem(ItemAt(index)))
117		data->weight = weight;
118
119	InvalidateLayout();
120}
121
122
123BLayoutItem*
124BGroupLayout::AddView(BView* child)
125{
126	return BTwoDimensionalLayout::AddView(child);
127}
128
129
130BLayoutItem*
131BGroupLayout::AddView(int32 index, BView* child)
132{
133	return BTwoDimensionalLayout::AddView(index, child);
134}
135
136
137BLayoutItem*
138BGroupLayout::AddView(BView* child, float weight)
139{
140	return AddView(-1, child, weight);
141}
142
143
144BLayoutItem*
145BGroupLayout::AddView(int32 index, BView* child, float weight)
146{
147	BLayoutItem* item = AddView(index, child);
148	if (ItemLayoutData* data = _LayoutDataForItem(item))
149		data->weight = weight;
150
151	return item;
152}
153
154
155bool
156BGroupLayout::AddItem(BLayoutItem* item)
157{
158	return BTwoDimensionalLayout::AddItem(item);
159}
160
161
162bool
163BGroupLayout::AddItem(int32 index, BLayoutItem* item)
164{
165	return BTwoDimensionalLayout::AddItem(index, item);
166}
167
168
169bool
170BGroupLayout::AddItem(BLayoutItem* item, float weight)
171{
172	return AddItem(-1, item, weight);
173}
174
175
176bool
177BGroupLayout::AddItem(int32 index, BLayoutItem* item, float weight)
178{
179	bool success = AddItem(index, item);
180	if (success) {
181		if (ItemLayoutData* data = _LayoutDataForItem(item))
182			data->weight = weight;
183	}
184
185	return success;
186}
187
188
189status_t
190BGroupLayout::Archive(BMessage* into, bool deep) const
191{
192	BArchiver archiver(into);
193	status_t result = BTwoDimensionalLayout::Archive(into, deep);
194
195	if (result == B_OK)
196		result = into->AddBool(kVerticalField, fOrientation == B_VERTICAL);
197
198	return archiver.Finish(result);
199}
200
201
202status_t
203BGroupLayout::AllArchived(BMessage* into) const
204{
205	return BTwoDimensionalLayout::AllArchived(into);
206}
207
208
209status_t
210BGroupLayout::AllUnarchived(const BMessage* from)
211{
212	return BTwoDimensionalLayout::AllUnarchived(from);
213}
214
215
216BArchivable*
217BGroupLayout::Instantiate(BMessage* from)
218{
219	if (validate_instantiation(from, "BGroupLayout"))
220		return new(nothrow) BGroupLayout(from);
221	return NULL;
222}
223
224
225status_t
226BGroupLayout::ItemArchived(BMessage* into,
227	BLayoutItem* item, int32 index) const
228{
229	return into->AddFloat(kItemWeightField, _LayoutDataForItem(item)->weight);
230}
231
232
233status_t
234BGroupLayout::ItemUnarchived(const BMessage* from,
235	BLayoutItem* item, int32 index)
236{
237	float weight;
238	status_t result = from->FindFloat(kItemWeightField, index, &weight);
239
240	if (result == B_OK)
241		_LayoutDataForItem(item)->weight = weight;
242
243	return result;
244}
245
246
247bool
248BGroupLayout::ItemAdded(BLayoutItem* item, int32 atIndex)
249{
250	item->SetLayoutData(new(nothrow) ItemLayoutData);
251	return item->LayoutData() != NULL;
252}
253
254
255void
256BGroupLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex)
257{
258	if (ItemLayoutData* data = _LayoutDataForItem(item)) {
259		item->SetLayoutData(NULL);
260		delete data;
261	}
262}
263
264
265void
266BGroupLayout::PrepareItems(orientation orientation)
267{
268	// filter the visible items
269	fVisibleItems.MakeEmpty();
270	int32 itemCount = CountItems();
271	for (int i = 0; i < itemCount; i++) {
272		BLayoutItem* item = ItemAt(i);
273		if (item->IsVisible())
274			fVisibleItems.AddItem(item);
275	}
276}
277
278
279int32
280BGroupLayout::InternalCountColumns()
281{
282	return (fOrientation == B_HORIZONTAL ? fVisibleItems.CountItems() : 1);
283}
284
285
286int32
287BGroupLayout::InternalCountRows()
288{
289	return (fOrientation == B_VERTICAL ? fVisibleItems.CountItems() : 1);
290}
291
292
293void
294BGroupLayout::GetColumnRowConstraints(orientation orientation, int32 index,
295	ColumnRowConstraints* constraints)
296{
297	if (index >= 0 && index < fVisibleItems.CountItems()) {
298		BLayoutItem* item = (BLayoutItem*)fVisibleItems.ItemAt(index);
299		constraints->min = -1;
300		constraints->max = B_SIZE_UNLIMITED;
301		if (ItemLayoutData* data = _LayoutDataForItem(item))
302			constraints->weight = data->weight;
303		else
304			constraints->weight = 1;
305	}
306}
307
308
309void
310BGroupLayout::GetItemDimensions(BLayoutItem* item, Dimensions* dimensions)
311{
312	int32 index = fVisibleItems.IndexOf(item);
313	if (index < 0)
314		return;
315
316	if (fOrientation == B_HORIZONTAL) {
317		dimensions->x = index;
318		dimensions->y = 0;
319		dimensions->width = 1;
320		dimensions->height = 1;
321	} else {
322		dimensions->x = 0;
323		dimensions->y = index;
324		dimensions->width = 1;
325		dimensions->height = 1;
326	}
327}
328
329
330BGroupLayout::ItemLayoutData*
331BGroupLayout::_LayoutDataForItem(BLayoutItem* item) const
332{
333	return item == NULL ? NULL : (ItemLayoutData*)item->LayoutData();
334}
335
336
337status_t
338BGroupLayout::Perform(perform_code code, void* _data)
339{
340	return BTwoDimensionalLayout::Perform(code, _data);
341}
342
343
344void BGroupLayout::_ReservedGroupLayout1() {}
345void BGroupLayout::_ReservedGroupLayout2() {}
346void BGroupLayout::_ReservedGroupLayout3() {}
347void BGroupLayout::_ReservedGroupLayout4() {}
348void BGroupLayout::_ReservedGroupLayout5() {}
349void BGroupLayout::_ReservedGroupLayout6() {}
350void BGroupLayout::_ReservedGroupLayout7() {}
351void BGroupLayout::_ReservedGroupLayout8() {}
352void BGroupLayout::_ReservedGroupLayout9() {}
353void BGroupLayout::_ReservedGroupLayout10() {}
354