xref: /haiku/src/kits/interface/CardLayout.cpp (revision 0d452c8f34013b611a54c746a71c05e28796eae2)
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::InvalidateLayout(bool children)
178 {
179 	BLayout::InvalidateLayout(children);
180 
181 	fMinMaxValid = false;
182 }
183 
184 
185 void
186 BCardLayout::DerivedLayoutItems()
187 {
188 	_ValidateMinMax();
189 
190 	BSize size(LayoutArea().Size());
191 
192 	// this cannot be done when we are viewless, as our children
193 	// would not get cut off in the right place.
194 	if (Owner()) {
195 		size.width = max_c(size.width, fMin.width);
196 		size.height = max_c(size.height, fMin.height);
197 	}
198 
199  	if (fVisibleItem != NULL)
200 		fVisibleItem->AlignInFrame(BRect(LayoutArea().LeftTop(), size));
201 }
202 
203 
204 status_t
205 BCardLayout::Archive(BMessage* into, bool deep) const
206 {
207 	BArchiver archiver(into);
208 	status_t err = BAbstractLayout::Archive(into, deep);
209 
210 	if (err == B_OK && deep)
211 		err = into->AddInt32(kVisibleItemField, IndexOfItem(fVisibleItem));
212 
213 	return archiver.Finish(err);
214 }
215 
216 
217 status_t
218 BCardLayout::AllUnarchived(const BMessage* from)
219 {
220 	status_t err = BLayout::AllUnarchived(from);
221 	if (err != B_OK)
222 		return err;
223 
224 	int32 visibleIndex;
225 	err = from->FindInt32(kVisibleItemField, &visibleIndex);
226 	if (err == B_OK)
227 		SetVisibleItem(visibleIndex);
228 
229 	return err;
230 }
231 
232 
233 BArchivable*
234 BCardLayout::Instantiate(BMessage* from)
235 {
236 	if (validate_instantiation(from, "BCardLayout"))
237 		return new BCardLayout(from);
238 	return NULL;
239 }
240 
241 
242 bool
243 BCardLayout::ItemAdded(BLayoutItem* item, int32 atIndex)
244 {
245 	item->SetVisible(false);
246 	return true;
247 }
248 
249 
250 void
251 BCardLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex)
252 {
253 	if (fVisibleItem == item) {
254 		BLayoutItem* newVisibleItem = NULL;
255 		SetVisibleItem(newVisibleItem);
256 	}
257 }
258 
259 
260 void
261 BCardLayout::_ValidateMinMax()
262 {
263 	if (fMinMaxValid)
264 		return;
265 
266 	fMin.width = 0;
267 	fMin.height = 0;
268 	fMax.width = B_SIZE_UNLIMITED;
269 	fMax.height = B_SIZE_UNLIMITED;
270 	fPreferred.width = 0;
271 	fPreferred.height = 0;
272 
273 	int32 itemCount = CountItems();
274 	for (int32 i = 0; i < itemCount; i++) {
275 		BLayoutItem* item = ItemAt(i);
276 
277 		BSize min = item->MinSize();
278 		BSize max = item->MaxSize();
279 		BSize preferred = item->PreferredSize();
280 
281 		fMin.width = max_c(fMin.width, min.width);
282 		fMin.height = max_c(fMin.height, min.height);
283 
284 		fMax.width = min_c(fMax.width, max.width);
285 		fMax.height = min_c(fMax.height, max.height);
286 
287 		fPreferred.width = max_c(fPreferred.width, preferred.width);
288 		fPreferred.height = max_c(fPreferred.height, preferred.height);
289 	}
290 
291 	fMax.width = max_c(fMax.width, fMin.width);
292 	fMax.height = max_c(fMax.height, fMin.height);
293 
294 	fPreferred.width = max_c(fPreferred.width, fMin.width);
295 	fPreferred.height = max_c(fPreferred.height, fMin.height);
296 	fPreferred.width = min_c(fPreferred.width, fMax.width);
297 	fPreferred.height = min_c(fPreferred.height, fMax.height);
298 
299 	fMinMaxValid = true;
300 	ResetLayoutInvalidation();
301 }
302