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