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
BCardLayout()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
BCardLayout(BMessage * from)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
~BCardLayout()43 BCardLayout::~BCardLayout()
44 {
45 }
46
47
48 BLayoutItem*
VisibleItem() const49 BCardLayout::VisibleItem() const
50 {
51 return fVisibleItem;
52 }
53
54
55 int32
VisibleIndex() const56 BCardLayout::VisibleIndex() const
57 {
58 return IndexOfItem(fVisibleItem);
59 }
60
61
62 void
SetVisibleItem(int32 index)63 BCardLayout::SetVisibleItem(int32 index)
64 {
65 SetVisibleItem(ItemAt(index));
66 }
67
68
69 void
SetVisibleItem(BLayoutItem * item)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
BaseMinSize()99 BCardLayout::BaseMinSize()
100 {
101 _ValidateMinMax();
102 return fMin;
103 }
104
105
106 BSize
BaseMaxSize()107 BCardLayout::BaseMaxSize()
108 {
109 _ValidateMinMax();
110 return fMax;
111 }
112
113
114 BSize
BasePreferredSize()115 BCardLayout::BasePreferredSize()
116 {
117 _ValidateMinMax();
118 return fPreferred;
119 }
120
121
122 BAlignment
BaseAlignment()123 BCardLayout::BaseAlignment()
124 {
125 return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
126 }
127
128
129 bool
HasHeightForWidth()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
GetHeightForWidth(float width,float * min,float * max,float * preferred)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
LayoutInvalidated(bool children)184 BCardLayout::LayoutInvalidated(bool children)
185 {
186 fMinMaxValid = false;
187 }
188
189
190 void
DoLayout()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
Archive(BMessage * into,bool deep) const210 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
AllArchived(BMessage * archive) const223 BCardLayout::AllArchived(BMessage* archive) const
224 {
225 return BAbstractLayout::AllArchived(archive);
226 }
227
228
229 status_t
AllUnarchived(const BMessage * from)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
ItemArchived(BMessage * into,BLayoutItem * item,int32 index) const246 BCardLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const
247 {
248 return BAbstractLayout::ItemArchived(into, item, index);
249 }
250
251
252 status_t
ItemUnarchived(const BMessage * from,BLayoutItem * item,int32 index)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*
Instantiate(BMessage * from)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
ItemAdded(BLayoutItem * item,int32 atIndex)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
ItemRemoved(BLayoutItem * item,int32 fromIndex)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
_ValidateMinMax()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
Perform(perform_code d,void * arg)338 BCardLayout::Perform(perform_code d, void* arg)
339 {
340 return BAbstractLayout::Perform(d, arg);
341 }
342
343
_ReservedCardLayout1()344 void BCardLayout::_ReservedCardLayout1() {}
_ReservedCardLayout2()345 void BCardLayout::_ReservedCardLayout2() {}
_ReservedCardLayout3()346 void BCardLayout::_ReservedCardLayout3() {}
_ReservedCardLayout4()347 void BCardLayout::_ReservedCardLayout4() {}
_ReservedCardLayout5()348 void BCardLayout::_ReservedCardLayout5() {}
_ReservedCardLayout6()349 void BCardLayout::_ReservedCardLayout6() {}
_ReservedCardLayout7()350 void BCardLayout::_ReservedCardLayout7() {}
_ReservedCardLayout8()351 void BCardLayout::_ReservedCardLayout8() {}
_ReservedCardLayout9()352 void BCardLayout::_ReservedCardLayout9() {}
_ReservedCardLayout10()353 void BCardLayout::_ReservedCardLayout10() {}
354
355