xref: /haiku/src/kits/interface/CardLayout.cpp (revision 68ea01249e1e2088933cb12f9c28d4e5c5d1c9ef)
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 		debugger("BCardLayout::SetVisibleItem(BLayoutItem*): this item is not "
77 			"part of this layout, or the item does not exist.");
78 		return;
79 	}
80 
81 	// Changing an item's visibility will invalidate its parent's layout (us),
82 	// which would normally cause the min-max to be re-computed. But in this
83 	// case, that is unnecessary, and so we can skip it.
84 	const bool minMaxValid = fMinMaxValid;
85 
86 	if (fVisibleItem != NULL)
87 		fVisibleItem->SetVisible(false);
88 
89 	fVisibleItem = item;
90 
91 	if (fVisibleItem != NULL)
92 		fVisibleItem->SetVisible(true);
93 
94 	fMinMaxValid = minMaxValid;
95 }
96 
97 
98 BSize
99 BCardLayout::BaseMinSize()
100 {
101 	_ValidateMinMax();
102 	return fMin;
103 }
104 
105 
106 BSize
107 BCardLayout::BaseMaxSize()
108 {
109 	_ValidateMinMax();
110 	return fMax;
111 }
112 
113 
114 BSize
115 BCardLayout::BasePreferredSize()
116 {
117 	_ValidateMinMax();
118 	return fPreferred;
119 }
120 
121 
122 BAlignment
123 BCardLayout::BaseAlignment()
124 {
125 	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
126 }
127 
128 
129 bool
130 BCardLayout::HasHeightForWidth()
131 {
132 	int32 count = CountItems();
133 	for (int32 i = 0; i < count; i++) {
134 		if (ItemAt(i)->HasHeightForWidth())
135 			return true;
136 	}
137 
138 	return false;
139 }
140 
141 
142 void
143 BCardLayout::GetHeightForWidth(float width, float* min, float* max,
144 	float* preferred)
145 {
146 	_ValidateMinMax();
147 
148 	// init with useful values
149 	float minHeight = fMin.height;
150 	float maxHeight = fMax.height;
151 	float preferredHeight = fPreferred.height;
152 
153 	// apply the items' constraints
154 	int32 count = CountItems();
155 	for (int32 i = 0; i < count; i++) {
156 		BLayoutItem* item = ItemAt(i);
157 		if (item->HasHeightForWidth()) {
158 			float itemMinHeight;
159 			float itemMaxHeight;
160 			float itemPreferredHeight;
161 			item->GetHeightForWidth(width, &itemMinHeight, &itemMaxHeight,
162 				&itemPreferredHeight);
163 			minHeight = max_c(minHeight, itemMinHeight);
164 			maxHeight = min_c(maxHeight, itemMaxHeight);
165 			preferredHeight = min_c(preferredHeight, itemPreferredHeight);
166 		}
167 	}
168 
169 	// adjust max and preferred, if necessary
170 	maxHeight = max_c(maxHeight, minHeight);
171 	preferredHeight = max_c(preferredHeight, minHeight);
172 	preferredHeight = min_c(preferredHeight, maxHeight);
173 
174 	if (min)
175 		*min = minHeight;
176 	if (max)
177 		*max = maxHeight;
178 	if (preferred)
179 		*preferred = preferredHeight;
180 }
181 
182 
183 void
184 BCardLayout::LayoutInvalidated(bool children)
185 {
186 	fMinMaxValid = false;
187 }
188 
189 
190 void
191 BCardLayout::DoLayout()
192 {
193 	_ValidateMinMax();
194 
195 	BSize size(LayoutArea().Size());
196 
197 	// this cannot be done when we are viewless, as our children
198 	// would not get cut off in the right place.
199 	if (Owner()) {
200 		size.width = max_c(size.width, fMin.width);
201 		size.height = max_c(size.height, fMin.height);
202 	}
203 
204 	if (fVisibleItem != NULL)
205 		fVisibleItem->AlignInFrame(BRect(LayoutArea().LeftTop(), size));
206 }
207 
208 
209 status_t
210 BCardLayout::Archive(BMessage* into, bool deep) const
211 {
212 	BArchiver archiver(into);
213 	status_t err = BAbstractLayout::Archive(into, deep);
214 
215 	if (err == B_OK && deep)
216 		err = into->AddInt32(kVisibleItemField, IndexOfItem(fVisibleItem));
217 
218 	return archiver.Finish(err);
219 }
220 
221 
222 status_t
223 BCardLayout::AllArchived(BMessage* archive) const
224 {
225 	return BAbstractLayout::AllArchived(archive);
226 }
227 
228 
229 status_t
230 BCardLayout::AllUnarchived(const BMessage* from)
231 {
232 	status_t err = BLayout::AllUnarchived(from);
233 	if (err != B_OK)
234 		return err;
235 
236 	int32 visibleIndex;
237 	err = from->FindInt32(kVisibleItemField, &visibleIndex);
238 	if (err == B_OK)
239 		SetVisibleItem(visibleIndex);
240 
241 	return err;
242 }
243 
244 
245 status_t
246 BCardLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const
247 {
248 	return BAbstractLayout::ItemArchived(into, item, index);
249 }
250 
251 
252 status_t
253 BCardLayout::ItemUnarchived(const BMessage* from, BLayoutItem* item,
254 	int32 index)
255 {
256 	return BAbstractLayout::ItemUnarchived(from, item, index);
257 }
258 
259 
260 
261 BArchivable*
262 BCardLayout::Instantiate(BMessage* from)
263 {
264 	if (validate_instantiation(from, "BCardLayout"))
265 		return new BCardLayout(from);
266 	return NULL;
267 }
268 
269 
270 bool
271 BCardLayout::ItemAdded(BLayoutItem* item, int32 atIndex)
272 {
273 	if (CountItems() <= 1)
274 		SetVisibleItem(item);
275 	else
276 		item->SetVisible(false);
277 	return true;
278 }
279 
280 
281 void
282 BCardLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex)
283 {
284 	fMinMaxValid = false;
285 
286 	if (fVisibleItem == item) {
287 		BLayoutItem* newVisibleItem = NULL;
288 		SetVisibleItem(newVisibleItem);
289 	}
290 }
291 
292 
293 void
294 BCardLayout::_ValidateMinMax()
295 {
296 	if (fMinMaxValid)
297 		return;
298 
299 	fMin.width = 0;
300 	fMin.height = 0;
301 	fMax.width = B_SIZE_UNLIMITED;
302 	fMax.height = B_SIZE_UNLIMITED;
303 	fPreferred.width = 0;
304 	fPreferred.height = 0;
305 
306 	int32 itemCount = CountItems();
307 	for (int32 i = 0; i < itemCount; i++) {
308 		BLayoutItem* item = ItemAt(i);
309 
310 		BSize min = item->MinSize();
311 		BSize max = item->MaxSize();
312 		BSize preferred = item->PreferredSize();
313 
314 		fMin.width = max_c(fMin.width, min.width);
315 		fMin.height = max_c(fMin.height, min.height);
316 
317 		fMax.width = min_c(fMax.width, max.width);
318 		fMax.height = min_c(fMax.height, max.height);
319 
320 		fPreferred.width = max_c(fPreferred.width, preferred.width);
321 		fPreferred.height = max_c(fPreferred.height, preferred.height);
322 	}
323 
324 	fMax.width = max_c(fMax.width, fMin.width);
325 	fMax.height = max_c(fMax.height, fMin.height);
326 
327 	fPreferred.width = max_c(fPreferred.width, fMin.width);
328 	fPreferred.height = max_c(fPreferred.height, fMin.height);
329 	fPreferred.width = min_c(fPreferred.width, fMax.width);
330 	fPreferred.height = min_c(fPreferred.height, fMax.height);
331 
332 	fMinMaxValid = true;
333 	ResetLayoutInvalidation();
334 }
335 
336 
337 status_t
338 BCardLayout::Perform(perform_code d, void* arg)
339 {
340 	return BAbstractLayout::Perform(d, arg);
341 }
342 
343 
344 void BCardLayout::_ReservedCardLayout1() {}
345 void BCardLayout::_ReservedCardLayout2() {}
346 void BCardLayout::_ReservedCardLayout3() {}
347 void BCardLayout::_ReservedCardLayout4() {}
348 void BCardLayout::_ReservedCardLayout5() {}
349 void BCardLayout::_ReservedCardLayout6() {}
350 void BCardLayout::_ReservedCardLayout7() {}
351 void BCardLayout::_ReservedCardLayout8() {}
352 void BCardLayout::_ReservedCardLayout9() {}
353 void BCardLayout::_ReservedCardLayout10() {}
354 
355