xref: /haiku/src/kits/interface/AbstractLayout.cpp (revision bf243977ffd34197ad7c0820c2da5d21abea0402)
1 /*
2  * Copyright 2010, Haiku, Inc.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <AbstractLayout.h>
8 #include <LayoutUtils.h>
9 #include <Message.h>
10 #include <View.h>
11 #include <ViewPrivate.h>
12 
13 
14 namespace {
15 	const char* const kSizesField = "BAbstractLayout:sizes";
16 		// kSizesField == {min, max, preferred}
17 	const char* const kAlignmentField = "BAbstractLayout:alignment";
18 	const char* const kFrameField = "BAbstractLayout:frame";
19 	const char* const kVisibleField = "BAbstractLayout:visible";
20 
21 	enum proxy_type { VIEW_PROXY_TYPE, DATA_PROXY_TYPE };
22 }
23 
24 
25 struct BAbstractLayout::Proxy {
26 
27 	Proxy(proxy_type type)
28 		:
29 		type(type)
30 	{
31 	}
32 
33 	virtual	BSize		MinSize() const = 0;
34 	virtual void		SetMinSize(const BSize&) = 0;
35 
36 	virtual	BSize		MaxSize() const = 0;
37 	virtual void		SetMaxSize(const BSize&) = 0;
38 
39 	virtual	BSize		PreferredSize() const = 0;
40 	virtual void		SetPreferredSize(const BSize&) = 0;
41 
42 	virtual	BAlignment	Alignment() const = 0;
43 	virtual	void		SetAlignment(const BAlignment&) = 0;
44 
45 	virtual	BRect		Frame() const = 0;
46 	virtual	void		SetFrame(const BRect& frame) = 0;
47 
48 	virtual bool		IsVisible(bool ancestorHidden) const = 0;
49 	virtual	void		SetVisible(bool visible) = 0;
50 
51 	virtual	status_t	AddDataToArchive(BMessage* archive,
52 							bool ancestorHidden) = 0;
53 	virtual	status_t	RestoreDataFromArchive(const BMessage* archive) = 0;
54 
55 			proxy_type	type;
56 };
57 
58 
59 struct BAbstractLayout::DataProxy : Proxy {
60 
61 	DataProxy()
62 		:
63 		Proxy(DATA_PROXY_TYPE),
64 		minSize(),
65 		maxSize(),
66 		preferredSize(),
67 		alignment(),
68 		frame(-1, -1, 0, 0),
69 		visible(true)
70 	{
71 	}
72 
73 	BSize MinSize() const
74 	{
75 		return minSize;
76 	}
77 
78 	void SetMinSize(const BSize& min)
79 	{
80 		minSize = min;
81 	}
82 
83 	BSize MaxSize() const
84 	{
85 		return maxSize;
86 	}
87 
88 	void SetMaxSize(const BSize& max)
89 	{
90 		maxSize = max;
91 	}
92 
93 	BSize PreferredSize() const
94 	{
95 		return preferredSize;
96 	}
97 
98 	void SetPreferredSize(const BSize& preferred)
99 	{
100 		preferredSize = preferred;
101 	}
102 
103 	BAlignment Alignment() const
104 	{
105 		return this->alignment;
106 	}
107 
108 	void SetAlignment(const BAlignment& align)
109 	{
110 		this->alignment = align;
111 	}
112 
113 	BRect Frame() const
114 	{
115 		return frame;
116 	}
117 
118 	void SetFrame(const BRect& frame)
119 	{
120 		if (frame == this->frame)
121 			return;
122 		this->frame = frame;
123 	}
124 
125 	bool IsVisible(bool) const
126 	{
127 		return visible;
128 	}
129 
130 	void SetVisible(bool visible)
131 	{
132 		this->visible = visible;
133 	}
134 
135 	status_t AddDataToArchive(BMessage* archive, bool ancestorHidden)
136 	{
137 		status_t err = archive->AddSize(kSizesField, minSize);
138 		if (err == B_OK)
139 			err = archive->AddSize(kSizesField, maxSize);
140 		if (err == B_OK)
141 			err = archive->AddSize(kSizesField, preferredSize);
142 		if (err == B_OK)
143 			err = archive->AddAlignment(kAlignmentField, alignment);
144 		if (err == B_OK)
145 			err = archive->AddRect(kFrameField, frame);
146 		if (err == B_OK)
147 			err = archive->AddBool(kVisibleField, visible);
148 
149 		return err;
150 	}
151 
152 	status_t RestoreDataFromArchive(const BMessage* archive)
153 	{
154 		status_t err = archive->FindSize(kSizesField, 0, &minSize);
155 		if (err == B_OK)
156 			err = archive->FindSize(kSizesField, 1, &maxSize);
157 		if (err == B_OK)
158 			err = archive->FindSize(kSizesField, 2, &preferredSize);
159 		if (err == B_OK)
160 			err = archive->FindAlignment(kAlignmentField, &alignment);
161 		if (err == B_OK)
162 			err = archive->FindRect(kFrameField, &frame);
163 		if (err == B_OK)
164 			err = archive->FindBool(kVisibleField, &visible);
165 
166 		return err;
167 	}
168 
169 	BSize		minSize;
170 	BSize		maxSize;
171 	BSize		preferredSize;
172 	BAlignment	alignment;
173 	BRect		frame;
174 	bool		visible;
175 };
176 
177 
178 struct BAbstractLayout::ViewProxy : Proxy {
179 	ViewProxy(BView* target)
180 		:
181 		Proxy(VIEW_PROXY_TYPE),
182 		view(target)
183 	{
184 	}
185 
186 	BSize MinSize() const
187 	{
188 		return view->ExplicitMinSize();
189 	}
190 
191 	void SetMinSize(const BSize& min)
192 	{
193 		view->SetExplicitMinSize(min);
194 	}
195 
196 	BSize MaxSize() const
197 	{
198 		return view->ExplicitMaxSize();
199 	}
200 
201 	void SetMaxSize(const BSize& min)
202 	{
203 		view->SetExplicitMaxSize(min);
204 	}
205 
206 	BSize PreferredSize() const
207 	{
208 		return view->ExplicitPreferredSize();
209 	}
210 
211 	void SetPreferredSize(const BSize& preferred)
212 	{
213 		view->SetExplicitPreferredSize(preferred);
214 	}
215 
216 	BAlignment Alignment() const
217 	{
218 		return view->ExplicitAlignment();
219 	}
220 
221 	void SetAlignment(const BAlignment& alignment)
222 	{
223 		view->SetExplicitAlignment(alignment);
224 	}
225 
226 	BRect Frame() const
227 	{
228 		return view->Frame();
229 	}
230 
231 	void SetFrame(const BRect& frame)
232 	{
233 		view->MoveTo(frame.LeftTop());
234 		view->ResizeTo(frame.Width(), frame.Height());
235 	}
236 
237 	bool IsVisible(bool ancestorsVisible) const
238 	{
239 		int16 showLevel = BView::Private(view).ShowLevel();
240 		return (showLevel - (ancestorsVisible) ? 0 : 1) <= 0;
241 	}
242 
243 	void SetVisible(bool visible)
244 	{
245 		// No need to check that we are not re-hiding, that is done
246 		// for us.
247 		if (visible)
248 			view->Show();
249 		else
250 			view->Hide();
251 	}
252 
253 	status_t AddDataToArchive(BMessage* archive, bool ancestorHidden)
254 	{
255 		return B_OK;
256 	}
257 
258 	status_t RestoreDataFromArchive(const BMessage* archive)
259 	{
260 		return B_OK;
261 	}
262 
263 	BView*	view;
264 };
265 
266 
267 BAbstractLayout::BAbstractLayout()
268 	:
269 	fExplicitData(new BAbstractLayout::DataProxy())
270 {
271 }
272 
273 
274 BAbstractLayout::BAbstractLayout(BMessage* from)
275 	:
276 	BLayout(BUnarchiver::PrepareArchive(from)),
277 	fExplicitData(new DataProxy())
278 {
279 	BUnarchiver(from).Finish();
280 }
281 
282 
283 BAbstractLayout::~BAbstractLayout()
284 {
285 	delete fExplicitData;
286 }
287 
288 
289 BSize
290 BAbstractLayout::MinSize()
291 {
292 	return BLayoutUtils::ComposeSize(fExplicitData->MinSize(), BaseMinSize());
293 }
294 
295 
296 BSize
297 BAbstractLayout::MaxSize()
298 {
299 	return BLayoutUtils::ComposeSize(fExplicitData->MaxSize(), BaseMaxSize());
300 }
301 
302 
303 BSize
304 BAbstractLayout::PreferredSize()
305 {
306 	return BLayoutUtils::ComposeSize(fExplicitData->PreferredSize(),
307 		BasePreferredSize());
308 }
309 
310 
311 BAlignment
312 BAbstractLayout::Alignment()
313 {
314 	return BLayoutUtils::ComposeAlignment(fExplicitData->Alignment(),
315 		BaseAlignment());
316 }
317 
318 
319 void
320 BAbstractLayout::SetExplicitMinSize(BSize size)
321 {
322 	fExplicitData->SetMinSize(size);
323 }
324 
325 
326 void
327 BAbstractLayout::SetExplicitMaxSize(BSize size)
328 {
329 	fExplicitData->SetMaxSize(size);
330 }
331 
332 
333 void
334 BAbstractLayout::SetExplicitPreferredSize(BSize size)
335 {
336 	fExplicitData->SetPreferredSize(size);
337 }
338 
339 
340 void
341 BAbstractLayout::SetExplicitAlignment(BAlignment alignment)
342 {
343 	fExplicitData->SetAlignment(alignment);
344 }
345 
346 
347 BSize
348 BAbstractLayout::BaseMinSize()
349 {
350 	return BSize(0, 0);
351 }
352 
353 
354 BSize
355 BAbstractLayout::BaseMaxSize()
356 {
357 	return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
358 }
359 
360 
361 BSize
362 BAbstractLayout::BasePreferredSize()
363 {
364 	return BSize(0, 0);
365 }
366 
367 
368 BAlignment
369 BAbstractLayout::BaseAlignment()
370 {
371 	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
372 }
373 
374 
375 BRect
376 BAbstractLayout::Frame()
377 {
378 	return fExplicitData->Frame();
379 }
380 
381 
382 void
383 BAbstractLayout::SetFrame(BRect frame)
384 {
385 	if (frame != fExplicitData->Frame()) {
386 		fExplicitData->SetFrame(frame);
387 		if (!Owner())
388 			Relayout();
389 	}
390 }
391 
392 
393 bool
394 BAbstractLayout::IsVisible()
395 {
396 	return fExplicitData->IsVisible(AncestorsVisible());
397 }
398 
399 
400 void
401 BAbstractLayout::SetVisible(bool visible)
402 {
403 	if (visible != fExplicitData->IsVisible(AncestorsVisible())) {
404 		fExplicitData->SetVisible(visible);
405 		if (Layout())
406 			Layout()->InvalidateLayout(false);
407 		VisibilityChanged(visible);
408 	}
409 }
410 
411 
412 status_t
413 BAbstractLayout::Archive(BMessage* into, bool deep) const
414 {
415 	BArchiver archiver(into);
416 	status_t err = BLayout::Archive(into, deep);
417 
418 	return archiver.Finish(err);
419 }
420 
421 
422 status_t
423 BAbstractLayout::AllUnarchived(const BMessage* from)
424 {
425 	status_t err = fExplicitData->RestoreDataFromArchive(from);
426 	if (err != B_OK)
427 		return err;
428 
429 	return BLayout::AllUnarchived(from);
430 }
431 
432 
433 void
434 BAbstractLayout::OwnerChanged(BView* was)
435 {
436 	if (was) {
437 		static_cast<ViewProxy*>(fExplicitData)->view = Owner();
438 		return;
439 	}
440 
441 	delete fExplicitData;
442 	fExplicitData = new ViewProxy(Owner());
443 }
444 
445 
446 void
447 BAbstractLayout::AncestorVisibilityChanged(bool shown)
448 {
449 	if (AncestorsVisible() == shown)
450 		return;
451 
452 	if (BView* owner = Owner()) {
453 		if (shown)
454 			owner->Show();
455 		else
456 			owner->Hide();
457 	}
458 	BLayout::AncestorVisibilityChanged(shown);
459 }
460 
461