xref: /haiku/src/kits/interface/CardLayout.cpp (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
1 /*
2  * Copyright 2006-2009, Ingo Weinhold <ingo_weinhold@gmx.de>.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 #include <CardLayout.h>
7 
8 #include <LayoutItem.h>
9 #include <Message.h>
10 #include <View.h>
11 
12 
13 namespace {
14 	const char* kVisibleItemField = "BCardLayout:visibleItem";
15 }
16 
17 
18 BCardLayout::BCardLayout()
19 	:
20 	BAbstractLayout(),
21 	fMin(0, 0),
22 	fMax(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED),
23 	fPreferred(0, 0),
24 	fVisibleItem(NULL),
25 	fMinMaxValid(false)
26 {
27 }
28 
29 
30 BCardLayout::BCardLayout(BMessage* from)
31 	:
32 	BAbstractLayout(BUnarchiver::PrepareArchive(from)),
33 	fMin(0, 0),
34 	fMax(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED),
35 	fPreferred(0, 0),
36 	fVisibleItem(NULL),
37 	fMinMaxValid(false)
38 {
39 	BUnarchiver(from).Finish();
40 }
41 
42 
43 BCardLayout::~BCardLayout()
44 {
45 }
46 
47 
48 BLayoutItem*
49 BCardLayout::VisibleItem() const
50 {
51 	return fVisibleItem;
52 }
53 
54 
55 int32
56 BCardLayout::VisibleIndex() const
57 {
58 	return IndexOfItem(fVisibleItem);
59 }
60 
61 
62 void
63 BCardLayout::SetVisibleItem(int32 index)
64 {
65 	SetVisibleItem(ItemAt(index));
66 }
67 
68 
69 void
70 BCardLayout::SetVisibleItem(BLayoutItem* item)
71 {
72 	if (item == fVisibleItem)
73 		return;
74 
75 	if (item != NULL && IndexOfItem(item) < 0)
76 		return;
77 
78 	if (fVisibleItem != NULL)
79 		fVisibleItem->SetVisible(false);
80 
81 	fVisibleItem = item;
82 
83 	if (fVisibleItem != NULL) {
84 		fVisibleItem->SetVisible(true);
85 
86 		Relayout();
87 	}
88 }
89 
90 
91 BSize
92 BCardLayout::BaseMinSize()
93 {
94 	_ValidateMinMax();
95 	return fMin;
96 }
97 
98 
99 BSize
100 BCardLayout::BaseMaxSize()
101 {
102 	_ValidateMinMax();
103 	return fMax;
104 }
105 
106 
107 BSize
108 BCardLayout::BasePreferredSize()
109 {
110 	_ValidateMinMax();
111 	return fPreferred;
112 }
113 
114 
115 BAlignment
116 BCardLayout::BaseAlignment()
117 {
118 	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
119 }
120 
121 
122 bool
123 BCardLayout::HasHeightForWidth()
124 {
125 	int32 count = CountItems();
126 	for (int32 i = 0; i < count; i++) {
127 		if (ItemAt(i)->HasHeightForWidth())
128 			return true;
129 	}
130 
131 	return false;
132 }
133 
134 
135 void
136 BCardLayout::GetHeightForWidth(float width, float* min, float* max,
137 	float* preferred)
138 {
139 	_ValidateMinMax();
140 
141 	// init with useful values
142 	float minHeight = fMin.height;
143 	float maxHeight = fMax.height;
144 	float preferredHeight = fPreferred.height;
145 
146 	// apply the items' constraints
147 	int32 count = CountItems();
148 	for (int32 i = 0; i < count; i++) {
149 		BLayoutItem* item = ItemAt(i);
150 		if (item->HasHeightForWidth()) {
151 			float itemMinHeight;
152 			float itemMaxHeight;
153 			float itemPreferredHeight;
154 			item->GetHeightForWidth(width, &itemMinHeight, &itemMaxHeight,
155 				&itemPreferredHeight);
156 			minHeight = max_c(minHeight, itemMinHeight);
157 			maxHeight = min_c(maxHeight, itemMaxHeight);
158 			preferredHeight = min_c(preferredHeight, itemPreferredHeight);
159 		}
160 	}
161 
162 	// adjust max and preferred, if necessary
163 	maxHeight = max_c(maxHeight, minHeight);
164 	preferredHeight = max_c(preferredHeight, minHeight);
165 	preferredHeight = min_c(preferredHeight, maxHeight);
166 
167 	if (min)
168 		*min = minHeight;
169 	if (max)
170 		*max = maxHeight;
171 	if (preferred)
172 		*preferred = preferredHeight;
173 }
174 
175 
176 void
177 BCardLayout::LayoutInvalidated(bool children)
178 {
179 	fMinMaxValid = false;
180 }
181 
182 
183 void
184 BCardLayout::DoLayout()
185 {
186 	_ValidateMinMax();
187 
188 	BSize size(LayoutArea().Size());
189 
190 	// this cannot be done when we are viewless, as our children
191 	// would not get cut off in the right place.
192 	if (Owner()) {
193 		size.width = max_c(size.width, fMin.width);
194 		size.height = max_c(size.height, fMin.height);
195 	}
196 
197 	if (fVisibleItem != NULL)
198 		fVisibleItem->AlignInFrame(BRect(LayoutArea().LeftTop(), size));
199 }
200 
201 
202 status_t
203 BCardLayout::Archive(BMessage* into, bool deep) const
204 {
205 	BArchiver archiver(into);
206 	status_t err = BAbstractLayout::Archive(into, deep);
207 
208 	if (err == B_OK && deep)
209 		err = into->AddInt32(kVisibleItemField, IndexOfItem(fVisibleItem));
210 
211 	return archiver.Finish(err);
212 }
213 
214 
215 status_t
216 BCardLayout::AllArchived(BMessage* archive) const
217 {
218 	return BAbstractLayout::AllArchived(archive);
219 }
220 
221 
222 status_t
223 BCardLayout::AllUnarchived(const BMessage* from)
224 {
225 	status_t err = BLayout::AllUnarchived(from);
226 	if (err != B_OK)
227 		return err;
228 
229 	int32 visibleIndex;
230 	err = from->FindInt32(kVisibleItemField, &visibleIndex);
231 	if (err == B_OK)
232 		SetVisibleItem(visibleIndex);
233 
234 	return err;
235 }
236 
237 
238 status_t
239 BCardLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const
240 {
241 	return BAbstractLayout::ItemArchived(into, item, index);
242 }
243 
244 
245 status_t
246 BCardLayout::ItemUnarchived(const BMessage* from, BLayoutItem* item,
247 	int32 index)
248 {
249 	return BAbstractLayout::ItemUnarchived(from, item, index);
250 }
251 
252 
253 
254 BArchivable*
255 BCardLayout::Instantiate(BMessage* from)
256 {
257 	if (validate_instantiation(from, "BCardLayout"))
258 		return new BCardLayout(from);
259 	return NULL;
260 }
261 
262 
263 bool
264 BCardLayout::ItemAdded(BLayoutItem* item, int32 atIndex)
265 {
266 	item->SetVisible(false);
267 	return true;
268 }
269 
270 
271 void
272 BCardLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex)
273 {
274 	if (fVisibleItem == item) {
275 		BLayoutItem* newVisibleItem = NULL;
276 		SetVisibleItem(newVisibleItem);
277 	}
278 }
279 
280 
281 void
282 BCardLayout::_ValidateMinMax()
283 {
284 	if (fMinMaxValid)
285 		return;
286 
287 	fMin.width = 0;
288 	fMin.height = 0;
289 	fMax.width = B_SIZE_UNLIMITED;
290 	fMax.height = B_SIZE_UNLIMITED;
291 	fPreferred.width = 0;
292 	fPreferred.height = 0;
293 
294 	int32 itemCount = CountItems();
295 	for (int32 i = 0; i < itemCount; i++) {
296 		BLayoutItem* item = ItemAt(i);
297 
298 		BSize min = item->MinSize();
299 		BSize max = item->MaxSize();
300 		BSize preferred = item->PreferredSize();
301 
302 		fMin.width = max_c(fMin.width, min.width);
303 		fMin.height = max_c(fMin.height, min.height);
304 
305 		fMax.width = min_c(fMax.width, max.width);
306 		fMax.height = min_c(fMax.height, max.height);
307 
308 		fPreferred.width = max_c(fPreferred.width, preferred.width);
309 		fPreferred.height = max_c(fPreferred.height, preferred.height);
310 	}
311 
312 	fMax.width = max_c(fMax.width, fMin.width);
313 	fMax.height = max_c(fMax.height, fMin.height);
314 
315 	fPreferred.width = max_c(fPreferred.width, fMin.width);
316 	fPreferred.height = max_c(fPreferred.height, fMin.height);
317 	fPreferred.width = min_c(fPreferred.width, fMax.width);
318 	fPreferred.height = min_c(fPreferred.height, fMax.height);
319 
320 	fMinMaxValid = true;
321 	ResetLayoutInvalidation();
322 }
323 
324 
325 status_t
326 BCardLayout::Perform(perform_code d, void* arg)
327 {
328 	return BAbstractLayout::Perform(d, arg);
329 }
330 
331 
332 void BCardLayout::_ReservedCardLayout1() {}
333 void BCardLayout::_ReservedCardLayout2() {}
334 void BCardLayout::_ReservedCardLayout3() {}
335 void BCardLayout::_ReservedCardLayout4() {}
336 void BCardLayout::_ReservedCardLayout5() {}
337 void BCardLayout::_ReservedCardLayout6() {}
338 void BCardLayout::_ReservedCardLayout7() {}
339 void BCardLayout::_ReservedCardLayout8() {}
340 void BCardLayout::_ReservedCardLayout9() {}
341 void BCardLayout::_ReservedCardLayout10() {}
342 
343