xref: /haiku/src/kits/interface/TwoDimensionalLayout.cpp (revision 2ffa9f8e542aa0c7dffd043e908d1af92da9d3aa)
1 /*
2  * Copyright 2006-2010, Ingo Weinhold <ingo_weinhold@gmx.de>.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <TwoDimensionalLayout.h>
8 
9 #include <stdio.h>
10 
11 #include <ControlLook.h>
12 #include <LayoutContext.h>
13 #include <LayoutItem.h>
14 #include <LayoutUtils.h>
15 #include <List.h>
16 #include <Message.h>
17 #include <View.h>
18 
19 #include <Referenceable.h>
20 
21 #include "CollapsingLayouter.h"
22 
23 
24 // Some words of explanation:
25 //
26 // This class is the base class for BLayouts that organize their items
27 // on a grid, with each item covering one or more grid cells (always a
28 // rectangular area). The derived classes only need to implement the
29 // hooks reporting the constraints for the items and additional constraints
30 // for the rows and columns. This class does all the layouting.
31 //
32 // The basic idea of the layout process is simple. The horizontal and the
33 // vertical dimensions are laid out independently and the items are set to the
34 // resulting locations and sizes. The "height for width" feature makes the
35 // height depend on the width, which makes things a bit more complicated.
36 // The horizontal dimension must be laid out first and and the results are
37 // fed into the vertical layout process.
38 //
39 // The AlignLayoutWith() feature, which allows to align layouts for different
40 // views with each other, causes the need for the three inner *Layouter classes.
41 // For each set of layouts aligned with each other with respect to one
42 // dimension that dimension must be laid out together. The class responsible
43 // is CompoundLayouter; one instance exists per such set. The derived class
44 // VerticalCompoundLayouter is a specialization for the vertical dimension
45 // which additionally takes care of the "height for width" feature. Per layout
46 // a single LocalLayouter exists, which comprises the required glue layout
47 // code and serves as a proxy for the layout, providing service methods
48 // needed by the CompoundLayouter.
49 
50 // TODO: Check for memory leaks!
51 
52 //#define DEBUG_LAYOUT
53 
54 // CompoundLayouter
55 class BTwoDimensionalLayout::CompoundLayouter : public BReferenceable {
56 public:
57 								CompoundLayouter(orientation orientation);
58 	virtual						~CompoundLayouter();
59 
60 			orientation			Orientation();
61 
62 	virtual	Layouter*			GetLayouter(bool minMax);
63 
64 			LayoutInfo*			GetLayoutInfo();
65 
66 			void				AddLocalLayouter(LocalLayouter* localLayouter);
67 			void				RemoveLocalLayouter(
68 									LocalLayouter* localLayouter);
69 
70 			status_t			AddAlignedLayoutsToArchive(BArchiver* archiver,
71 									LocalLayouter* requestedBy);
72 
73 			void				AbsorbCompoundLayouter(CompoundLayouter* other);
74 
75 	virtual	void				InvalidateLayout();
76 			bool				IsMinMaxValid();
77 			void				ValidateMinMax();
78 			void				Layout(float size, LocalLayouter* localLayouter,
79 									BLayoutContext* context);
80 
81 protected:
82 	virtual	void				DoLayout(float size,
83 									LocalLayouter* localLayouter,
84 									BLayoutContext* context);
85 
86 			Layouter*			fLayouter;
87 			LayoutInfo*			fLayoutInfo;
88 			orientation			fOrientation;
89 			BList				fLocalLayouters;
90 			BLayoutContext*		fLayoutContext;
91 			float				fLastLayoutSize;
92 
93 			void				_PrepareItems();
94 
95 			int32				_CountElements();
96 			bool				_HasMultiElementItems();
97 
98 			void				_AddConstraints(Layouter* layouter);
99 
100 			float				_Spacing();
101 };
102 
103 // VerticalCompoundLayouter
104 class BTwoDimensionalLayout::VerticalCompoundLayouter
105 	: public CompoundLayouter, private BLayoutContextListener {
106 public:
107 								VerticalCompoundLayouter();
108 
109 	virtual	Layouter*			GetLayouter(bool minMax);
110 
111 	virtual	void				InvalidateLayout();
112 
113 			void				InvalidateHeightForWidth();
114 
115 			void				InternalGetHeightForWidth(
116 									LocalLayouter* localLayouter,
117 									BLayoutContext* context,
118 									bool realLayout, float* minHeight,
119 									float* maxHeight, float* preferredHeight);
120 
121 protected:
122 	virtual	void				DoLayout(float size,
123 									LocalLayouter* localLayouter,
124 									BLayoutContext* context);
125 
126 private:
127 			Layouter*			fHeightForWidthLayouter;
128 			float				fCachedMinHeightForWidth;
129 			float				fCachedMaxHeightForWidth;
130 			float				fCachedPreferredHeightForWidth;
131 			BLayoutContext*		fHeightForWidthLayoutContext;
132 
133 			bool				_HasHeightForWidth();
134 
135 			bool				_SetHeightForWidthLayoutContext(
136 									BLayoutContext* context);
137 
138 	// BLayoutContextListener
139 	virtual	void				LayoutContextLeft(BLayoutContext* context);
140 };
141 
142 // LocalLayouter
143 class BTwoDimensionalLayout::LocalLayouter : private BLayoutContextListener {
144 public:
145 								LocalLayouter(BTwoDimensionalLayout* layout);
146 								~LocalLayouter();
147 
148 	// interface for the BTwoDimensionalLayout class
149 
150 			BSize				MinSize();
151 			BSize				MaxSize();
152 			BSize				PreferredSize();
153 
154 			void				InvalidateLayout();
155 			void				Layout(BSize size);
156 
157 			BRect				ItemFrame(Dimensions itemDimensions);
158 
159 			void				ValidateMinMax();
160 
161 			void				DoHorizontalLayout(float width);
162 
163 			void				InternalGetHeightForWidth(float width,
164 									float* minHeight, float* maxHeight,
165 									float* preferredHeight);
166 
167 			void				AlignWith(LocalLayouter* other,
168 									orientation orientation);
169 
170 	// Archiving stuff
171 			status_t			AddAlignedLayoutsToArchive(BArchiver* archiver);
172 			status_t			AddOwnerToArchive(BArchiver* archiver,
173 									CompoundLayouter* requestedBy,
174 									bool& _wasAvailable);
175 			status_t			AlignLayoutsFromArchive(BUnarchiver* unarchiver,
176 									orientation posture);
177 
178 
179 	// interface for the compound layout context
180 
181 			void				PrepareItems(
182 									CompoundLayouter* compoundLayouter);
183 			int32				CountElements(
184 									CompoundLayouter* compoundLayouter);
185 			bool				HasMultiElementItems(
186 									CompoundLayouter* compoundLayouter);
187 
188 			void				AddConstraints(
189 									CompoundLayouter* compoundLayouter,
190 									Layouter* layouter);
191 
192 			float				Spacing(CompoundLayouter* compoundLayouter);
193 
194 			bool				HasHeightForWidth();
195 
196 			bool				AddHeightForWidthConstraints(
197 									VerticalCompoundLayouter* compoundLayouter,
198 									Layouter* layouter,
199 									BLayoutContext* context);
200 			void				SetHeightForWidthConstraintsAdded(bool added);
201 
202 			void				SetCompoundLayouter(
203 									CompoundLayouter* compoundLayouter,
204 									orientation orientation);
205 
206 			void				InternalInvalidateLayout(
207 									CompoundLayouter* compoundLayouter);
208 
209 	// implementation private
210 private:
211 			BTwoDimensionalLayout* fLayout;
212 			CompoundLayouter*	fHLayouter;
213 			VerticalCompoundLayouter* fVLayouter;
214 			BList				fHeightForWidthItems;
215 
216 	// active layout context when doing last horizontal layout
217 			BLayoutContext*		fHorizontalLayoutContext;
218 			float				fHorizontalLayoutWidth;
219 			bool				fHeightForWidthConstraintsAdded;
220 
221 			void				_SetHorizontalLayoutContext(
222 									BLayoutContext* context, float width);
223 
224 	// BLayoutContextListener
225 	virtual	void				LayoutContextLeft(BLayoutContext* context);
226 };
227 
228 
229 // #pragma mark -
230 
231 // archiving constants
232 namespace {
233 	const char* const kHAlignedLayoutField = "BTwoDimensionalLayout:"
234 		"halignedlayout";
235 	const char* const kVAlignedLayoutField = "BTwoDimensionalLayout:"
236 		"valignedlayout";
237 	const char* const kInsetsField = "BTwoDimensionalLayout:insets";
238 	const char* const kSpacingField = "BTwoDimensionalLayout:spacing";
239 		// kSpacingField = {fHSpacing, fVSpacing}
240 }
241 
242 
BTwoDimensionalLayout()243 BTwoDimensionalLayout::BTwoDimensionalLayout()
244 	:
245 	fLeftInset(0),
246 	fRightInset(0),
247 	fTopInset(0),
248 	fBottomInset(0),
249 	fHSpacing(0),
250 	fVSpacing(0),
251 	fLocalLayouter(new LocalLayouter(this))
252 {
253 }
254 
255 
BTwoDimensionalLayout(BMessage * from)256 BTwoDimensionalLayout::BTwoDimensionalLayout(BMessage* from)
257 	:
258 	BAbstractLayout(from),
259 	fLeftInset(0),
260 	fRightInset(0),
261 	fTopInset(0),
262 	fBottomInset(0),
263 	fHSpacing(0),
264 	fVSpacing(0),
265 	fLocalLayouter(new LocalLayouter(this))
266 {
267 	BRect insets;
268 	from->FindRect(kInsetsField, &insets);
269 	SetInsets(insets.left, insets.top, insets.right, insets.bottom);
270 
271 	from->FindFloat(kSpacingField, 0, &fHSpacing);
272 	from->FindFloat(kSpacingField, 1, &fVSpacing);
273 }
274 
275 
~BTwoDimensionalLayout()276 BTwoDimensionalLayout::~BTwoDimensionalLayout()
277 {
278 	delete fLocalLayouter;
279 }
280 
281 
282 void
SetInsets(float left,float top,float right,float bottom)283 BTwoDimensionalLayout::SetInsets(float left, float top, float right,
284 	float bottom)
285 {
286 	fLeftInset = BControlLook::ComposeSpacing(left);
287 	fTopInset = BControlLook::ComposeSpacing(top);
288 	fRightInset = BControlLook::ComposeSpacing(right);
289 	fBottomInset = BControlLook::ComposeSpacing(bottom);
290 
291 	InvalidateLayout();
292 }
293 
294 
295 void
SetInsets(float horizontal,float vertical)296 BTwoDimensionalLayout::SetInsets(float horizontal, float vertical)
297 {
298 	fLeftInset = BControlLook::ComposeSpacing(horizontal);
299 	fRightInset = fLeftInset;
300 
301 	fTopInset = BControlLook::ComposeSpacing(vertical);
302 	fBottomInset = fTopInset;
303 
304 	InvalidateLayout();
305 }
306 
307 
308 void
SetInsets(float insets)309 BTwoDimensionalLayout::SetInsets(float insets)
310 {
311 	fLeftInset = BControlLook::ComposeSpacing(insets);
312 	fRightInset = fLeftInset;
313 	fTopInset = fLeftInset;
314 	fBottomInset = fLeftInset;
315 
316 	InvalidateLayout();
317 }
318 
319 
320 void
GetInsets(float * left,float * top,float * right,float * bottom) const321 BTwoDimensionalLayout::GetInsets(float* left, float* top, float* right,
322 	float* bottom) const
323 {
324 	if (left)
325 		*left = fLeftInset;
326 	if (top)
327 		*top = fTopInset;
328 	if (right)
329 		*right = fRightInset;
330 	if (bottom)
331 		*bottom = fBottomInset;
332 }
333 
334 
335 void
AlignLayoutWith(BTwoDimensionalLayout * other,orientation orientation)336 BTwoDimensionalLayout::AlignLayoutWith(BTwoDimensionalLayout* other,
337 	orientation orientation)
338 {
339 	if (!other || other == this)
340 		return;
341 
342 	fLocalLayouter->AlignWith(other->fLocalLayouter, orientation);
343 
344 	InvalidateLayout();
345 }
346 
347 
348 BSize
BaseMinSize()349 BTwoDimensionalLayout::BaseMinSize()
350 {
351 	_ValidateMinMax();
352 	return AddInsets(fLocalLayouter->MinSize());
353 }
354 
355 
356 BSize
BaseMaxSize()357 BTwoDimensionalLayout::BaseMaxSize()
358 {
359 	_ValidateMinMax();
360 	return AddInsets(fLocalLayouter->MaxSize());
361 }
362 
363 
364 BSize
BasePreferredSize()365 BTwoDimensionalLayout::BasePreferredSize()
366 {
367 	_ValidateMinMax();
368 	return AddInsets(fLocalLayouter->PreferredSize());
369 }
370 
371 
372 BAlignment
BaseAlignment()373 BTwoDimensionalLayout::BaseAlignment()
374 {
375 	return BAbstractLayout::BaseAlignment();
376 }
377 
378 
379 bool
HasHeightForWidth()380 BTwoDimensionalLayout::HasHeightForWidth()
381 {
382 	_ValidateMinMax();
383 	return fLocalLayouter->HasHeightForWidth();
384 }
385 
386 
387 void
GetHeightForWidth(float width,float * min,float * max,float * preferred)388 BTwoDimensionalLayout::GetHeightForWidth(float width, float* min, float* max,
389 	float* preferred)
390 {
391 	if (!HasHeightForWidth())
392 		return;
393 
394 	float outerSpacing = fLeftInset + fRightInset - 1;
395 	fLocalLayouter->InternalGetHeightForWidth(BLayoutUtils::SubtractDistances(
396 		width, outerSpacing), min, max, preferred);
397 	AddInsets(min, max, preferred);
398 }
399 
400 
401 void
SetFrame(BRect frame)402 BTwoDimensionalLayout::SetFrame(BRect frame)
403 {
404 	BAbstractLayout::SetFrame(frame);
405 }
406 
407 
408 status_t
Archive(BMessage * into,bool deep) const409 BTwoDimensionalLayout::Archive(BMessage* into, bool deep) const
410 {
411 	BArchiver archiver(into);
412 	status_t err = BAbstractLayout::Archive(into, deep);
413 
414 	if (err == B_OK) {
415 		BRect insets(fLeftInset, fTopInset, fRightInset, fBottomInset);
416 		err = into->AddRect(kInsetsField, insets);
417 	}
418 
419 	if (err == B_OK)
420 		err = into->AddFloat(kSpacingField, fHSpacing);
421 
422 	if (err == B_OK)
423 		err = into->AddFloat(kSpacingField, fVSpacing);
424 
425 	return archiver.Finish(err);
426 }
427 
428 
429 status_t
AllArchived(BMessage * into) const430 BTwoDimensionalLayout::AllArchived(BMessage* into) const
431 {
432 	BArchiver archiver(into);
433 
434 	status_t err = BLayout::AllArchived(into);
435 	if (err == B_OK)
436 		err = fLocalLayouter->AddAlignedLayoutsToArchive(&archiver);
437 	return err;
438 }
439 
440 
441 status_t
AllUnarchived(const BMessage * from)442 BTwoDimensionalLayout::AllUnarchived(const BMessage* from)
443 {
444 	status_t err = BLayout::AllUnarchived(from);
445 	if (err != B_OK)
446 		return err;
447 
448 	BUnarchiver unarchiver(from);
449 	err = fLocalLayouter->AlignLayoutsFromArchive(&unarchiver, B_HORIZONTAL);
450 	if (err == B_OK)
451 		err = fLocalLayouter->AlignLayoutsFromArchive(&unarchiver, B_VERTICAL);
452 
453 	return err;
454 }
455 
456 
457 status_t
ItemArchived(BMessage * into,BLayoutItem * item,int32 index) const458 BTwoDimensionalLayout::ItemArchived(BMessage* into, BLayoutItem* item,
459 	int32 index) const
460 {
461 	return BAbstractLayout::ItemArchived(into, item, index);
462 }
463 
464 
465 status_t
ItemUnarchived(const BMessage * from,BLayoutItem * item,int32 index)466 BTwoDimensionalLayout::ItemUnarchived(const BMessage* from, BLayoutItem* item,
467 	int32 index)
468 {
469 	return BAbstractLayout::ItemUnarchived(from, item, index);
470 }
471 
472 
473 
474 
475 void
LayoutInvalidated(bool children)476 BTwoDimensionalLayout::LayoutInvalidated(bool children)
477 {
478 	fLocalLayouter->InvalidateLayout();
479 }
480 
481 
482 void
DoLayout()483 BTwoDimensionalLayout::DoLayout()
484 {
485 	_ValidateMinMax();
486 
487 	// layout the horizontal/vertical elements
488 	BSize size(SubtractInsets(LayoutArea().Size()));
489 
490 #ifdef DEBUG_LAYOUT
491 printf("BTwoDimensionalLayout::DerivedLayoutItems(): view: %p"
492 	" size: (%.1f, %.1f)\n", View(), size.Width(), size.Height());
493 #endif
494 
495 	fLocalLayouter->Layout(size);
496 
497 	// layout the items
498 	BPoint itemOffset(LayoutArea().LeftTop());
499 	int itemCount = CountItems();
500 	for (int i = 0; i < itemCount; i++) {
501 		BLayoutItem* item = ItemAt(i);
502 		if (item->IsVisible()) {
503 			Dimensions itemDimensions;
504 			GetItemDimensions(item, &itemDimensions);
505 			BRect frame = fLocalLayouter->ItemFrame(itemDimensions);
506 			frame.left += fLeftInset;
507 			frame.top += fTopInset;
508 			frame.right += fLeftInset;
509 			frame.bottom += fTopInset;
510 			frame.OffsetBy(itemOffset);
511 {
512 #ifdef DEBUG_LAYOUT
513 printf("  frame for item %2d (view: %p): ", i, item->View());
514 frame.PrintToStream();
515 #endif
516 //BSize min(item->MinSize());
517 //BSize max(item->MaxSize());
518 //printf("    min: (%.1f, %.1f), max: (%.1f, %.1f)\n", min.width, min.height,
519 //	max.width, max.height);
520 //if (item->HasHeightForWidth()) {
521 //float minHeight, maxHeight, preferredHeight;
522 //item->GetHeightForWidth(frame.Width(), &minHeight, &maxHeight,
523 //	&preferredHeight);
524 //printf("    hfw: min: %.1f, max: %.1f, pref: %.1f\n", minHeight, maxHeight,
525 //	preferredHeight);
526 //}
527 }
528 
529 			item->AlignInFrame(frame);
530 		}
531 //else
532 //printf("  item %2d not visible", i);
533 	}
534 }
535 
536 
537 BSize
AddInsets(BSize size)538 BTwoDimensionalLayout::AddInsets(BSize size)
539 {
540 	size.width = BLayoutUtils::AddDistances(size.width,
541 		fLeftInset + fRightInset - 1);
542 	size.height = BLayoutUtils::AddDistances(size.height,
543 		fTopInset + fBottomInset - 1);
544 	return size;
545 }
546 
547 
548 void
AddInsets(float * minHeight,float * maxHeight,float * preferredHeight)549 BTwoDimensionalLayout::AddInsets(float* minHeight, float* maxHeight,
550 	float* preferredHeight)
551 {
552 	float insets = fTopInset + fBottomInset - 1;
553 	if (minHeight)
554 		*minHeight = BLayoutUtils::AddDistances(*minHeight, insets);
555 	if (maxHeight)
556 		*maxHeight = BLayoutUtils::AddDistances(*maxHeight, insets);
557 	if (preferredHeight)
558 		*preferredHeight = BLayoutUtils::AddDistances(*preferredHeight, insets);
559 }
560 
561 
562 BSize
SubtractInsets(BSize size)563 BTwoDimensionalLayout::SubtractInsets(BSize size)
564 {
565 	size.width = BLayoutUtils::SubtractDistances(size.width,
566 		fLeftInset + fRightInset - 1);
567 	size.height = BLayoutUtils::SubtractDistances(size.height,
568 		fTopInset + fBottomInset - 1);
569 	return size;
570 }
571 
572 
573 void
PrepareItems(orientation orientation)574 BTwoDimensionalLayout::PrepareItems(orientation orientation)
575 {
576 }
577 
578 
579 bool
HasMultiColumnItems()580 BTwoDimensionalLayout::HasMultiColumnItems()
581 {
582 	return false;
583 }
584 
585 
586 bool
HasMultiRowItems()587 BTwoDimensionalLayout::HasMultiRowItems()
588 {
589 	return false;
590 }
591 
592 
593 void
_ValidateMinMax()594 BTwoDimensionalLayout::_ValidateMinMax()
595 {
596 	fLocalLayouter->ValidateMinMax();
597 }
598 
599 
600 // #pragma mark - CompoundLayouter
601 
602 
CompoundLayouter(orientation orientation)603 BTwoDimensionalLayout::CompoundLayouter::CompoundLayouter(
604 	orientation orientation)
605 	:
606 	fLayouter(NULL),
607 	fLayoutInfo(NULL),
608 	fOrientation(orientation),
609 	fLocalLayouters(10),
610 	fLayoutContext(NULL),
611 	fLastLayoutSize(-1)
612 {
613 }
614 
615 
~CompoundLayouter()616 BTwoDimensionalLayout::CompoundLayouter::~CompoundLayouter()
617 {
618 	delete fLayouter;
619 	delete fLayoutInfo;
620 }
621 
622 
623 orientation
Orientation()624 BTwoDimensionalLayout::CompoundLayouter::Orientation()
625 {
626 	return fOrientation;
627 }
628 
629 
630 Layouter*
GetLayouter(bool minMax)631 BTwoDimensionalLayout::CompoundLayouter::GetLayouter(bool minMax)
632 {
633 	return fLayouter;
634 }
635 
636 
637 LayoutInfo*
GetLayoutInfo()638 BTwoDimensionalLayout::CompoundLayouter::GetLayoutInfo()
639 {
640 	return fLayoutInfo;
641 }
642 
643 
644 void
AddLocalLayouter(LocalLayouter * localLayouter)645 BTwoDimensionalLayout::CompoundLayouter::AddLocalLayouter(
646 	LocalLayouter* localLayouter)
647 {
648 	if (localLayouter) {
649 		if (!fLocalLayouters.HasItem(localLayouter)) {
650 			fLocalLayouters.AddItem(localLayouter);
651 			InvalidateLayout();
652 		}
653 	}
654 }
655 
656 
657 void
RemoveLocalLayouter(LocalLayouter * localLayouter)658 BTwoDimensionalLayout::CompoundLayouter::RemoveLocalLayouter(
659 	LocalLayouter* localLayouter)
660 {
661 	if (fLocalLayouters.RemoveItem(localLayouter))
662 		InvalidateLayout();
663 }
664 
665 
666 status_t
AddAlignedLayoutsToArchive(BArchiver * archiver,LocalLayouter * requestedBy)667 BTwoDimensionalLayout::CompoundLayouter::AddAlignedLayoutsToArchive(
668 	BArchiver* archiver, LocalLayouter* requestedBy)
669 {
670 	// The LocalLayouter* that really owns us is at index 0, layouts
671 	// at other indices are aligned to this one.
672 	if (requestedBy != fLocalLayouters.ItemAt(0))
673 		return B_OK;
674 
675 	status_t err;
676 	for (int32 i = fLocalLayouters.CountItems() - 1; i > 0; i--) {
677 		LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
678 
679 		bool wasAvailable;
680 		err = layouter->AddOwnerToArchive(archiver, this, wasAvailable);
681 		if (err != B_OK && wasAvailable)
682 			return err;
683 	}
684 	return B_OK;
685 }
686 
687 
688 void
AbsorbCompoundLayouter(CompoundLayouter * other)689 BTwoDimensionalLayout::CompoundLayouter::AbsorbCompoundLayouter(
690 	CompoundLayouter* other)
691 {
692 	if (other == this)
693 		return;
694 
695 	int32 count = other->fLocalLayouters.CountItems();
696 	for (int32 i = count - 1; i >= 0; i--) {
697 		LocalLayouter* layouter
698 			= (LocalLayouter*)other->fLocalLayouters.ItemAt(i);
699 		AddLocalLayouter(layouter);
700 		layouter->SetCompoundLayouter(this, fOrientation);
701 	}
702 
703 	InvalidateLayout();
704 }
705 
706 
707 void
InvalidateLayout()708 BTwoDimensionalLayout::CompoundLayouter::InvalidateLayout()
709 {
710 	if (!fLayouter)
711 		return;
712 
713 	delete fLayouter;
714 	delete fLayoutInfo;
715 
716 	fLayouter = NULL;
717 	fLayoutInfo = NULL;
718 	fLayoutContext = NULL;
719 
720 	// notify all local layouters to invalidate the respective views
721 	int32 count = fLocalLayouters.CountItems();
722 	for (int32 i = 0; i < count; i++) {
723 		LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
724 		layouter->InternalInvalidateLayout(this);
725 	}
726 }
727 
728 
729 bool
IsMinMaxValid()730 BTwoDimensionalLayout::CompoundLayouter::IsMinMaxValid()
731 {
732 	return (fLayouter != NULL);
733 }
734 
735 
736 void
ValidateMinMax()737 BTwoDimensionalLayout::CompoundLayouter::ValidateMinMax()
738 {
739 	if (IsMinMaxValid())
740 		return;
741 
742 	fLastLayoutSize = -1;
743 
744 	// create the layouter
745 	_PrepareItems();
746 
747 	int elementCount = _CountElements();
748 
749 	fLayouter = new CollapsingLayouter(elementCount, _Spacing());
750 
751 	// tell the layouter about our constraints
752 	// TODO: We should probably ignore local layouters whose view is hidden.
753 	// It's a bit tricky to find out, whether the view is hidden, though, since
754 	// this doesn't necessarily mean only hidden relative to the parent, but
755 	// hidden relative to a common parent.
756 	_AddConstraints(fLayouter);
757 
758 	fLayoutInfo = fLayouter->CreateLayoutInfo();
759 }
760 
761 
762 void
Layout(float size,LocalLayouter * localLayouter,BLayoutContext * context)763 BTwoDimensionalLayout::CompoundLayouter::Layout(float size,
764 	LocalLayouter* localLayouter, BLayoutContext* context)
765 {
766 	ValidateMinMax();
767 
768 	if (context != fLayoutContext || fLastLayoutSize != size) {
769 		DoLayout(size, localLayouter, context);
770 		fLayoutContext = context;
771 		fLastLayoutSize = size;
772 	}
773 }
774 
775 
776 void
DoLayout(float size,LocalLayouter * localLayouter,BLayoutContext * context)777 BTwoDimensionalLayout::CompoundLayouter::DoLayout(float size,
778 	LocalLayouter* localLayouter, BLayoutContext* context)
779 {
780 	fLayouter->Layout(fLayoutInfo, size);
781 }
782 
783 
784 void
_PrepareItems()785 BTwoDimensionalLayout::CompoundLayouter::_PrepareItems()
786 {
787 	int32 count = fLocalLayouters.CountItems();
788 	for (int32 i = 0; i < count; i++) {
789 		LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
790 		layouter->PrepareItems(this);
791 	}
792 }
793 
794 
795 int32
_CountElements()796 BTwoDimensionalLayout::CompoundLayouter::_CountElements()
797 {
798 	int32 elementCount = 0;
799 	int32 count = fLocalLayouters.CountItems();
800 	for (int32 i = 0; i < count; i++) {
801 		LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
802 		int32 layouterCount = layouter->CountElements(this);
803 		elementCount = max_c(elementCount, layouterCount);
804 	}
805 
806 	return elementCount;
807 }
808 
809 
810 bool
_HasMultiElementItems()811 BTwoDimensionalLayout::CompoundLayouter::_HasMultiElementItems()
812 {
813 	int32 count = fLocalLayouters.CountItems();
814 	for (int32 i = 0; i < count; i++) {
815 		LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
816 		if (layouter->HasMultiElementItems(this))
817 			return true;
818 	}
819 
820 	return false;
821 }
822 
823 
824 void
_AddConstraints(Layouter * layouter)825 BTwoDimensionalLayout::CompoundLayouter::_AddConstraints(Layouter* layouter)
826 {
827 	int32 count = fLocalLayouters.CountItems();
828 	for (int32 i = 0; i < count; i++) {
829 		LocalLayouter* localLayouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
830 		localLayouter->AddConstraints(this, layouter);
831 	}
832 }
833 
834 
835 float
_Spacing()836 BTwoDimensionalLayout::CompoundLayouter::_Spacing()
837 {
838 	if (!fLocalLayouters.IsEmpty())
839 		return ((LocalLayouter*)fLocalLayouters.ItemAt(0))->Spacing(this);
840 	return 0;
841 }
842 
843 
844 // #pragma mark - VerticalCompoundLayouter
845 
846 
VerticalCompoundLayouter()847 BTwoDimensionalLayout::VerticalCompoundLayouter::VerticalCompoundLayouter()
848 	:
849 	CompoundLayouter(B_VERTICAL),
850 	fHeightForWidthLayouter(NULL),
851 	fCachedMinHeightForWidth(0),
852 	fCachedMaxHeightForWidth(0),
853 	fCachedPreferredHeightForWidth(0),
854 	fHeightForWidthLayoutContext(NULL)
855 {
856 }
857 
858 
859 Layouter*
GetLayouter(bool minMax)860 BTwoDimensionalLayout::VerticalCompoundLayouter::GetLayouter(bool minMax)
861 {
862 	return (minMax || !_HasHeightForWidth()
863 		? fLayouter : fHeightForWidthLayouter);
864 }
865 
866 
867 void
InvalidateLayout()868 BTwoDimensionalLayout::VerticalCompoundLayouter::InvalidateLayout()
869 {
870 	CompoundLayouter::InvalidateLayout();
871 
872 	InvalidateHeightForWidth();
873 }
874 
875 
876 void
InvalidateHeightForWidth()877 BTwoDimensionalLayout::VerticalCompoundLayouter::InvalidateHeightForWidth()
878 {
879 	if (fHeightForWidthLayouter != NULL) {
880 		delete fHeightForWidthLayouter;
881 		fHeightForWidthLayouter = NULL;
882 
883 		// also make sure we're not reusing the old layout info
884 		fLastLayoutSize = -1;
885 
886 		int32 count = fLocalLayouters.CountItems();
887 		for (int32 i = 0; i < count; i++) {
888 			LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
889 			layouter->SetHeightForWidthConstraintsAdded(false);
890 		}
891 	}
892 }
893 
894 
895 void
InternalGetHeightForWidth(LocalLayouter * localLayouter,BLayoutContext * context,bool realLayout,float * minHeight,float * maxHeight,float * preferredHeight)896 BTwoDimensionalLayout::VerticalCompoundLayouter::InternalGetHeightForWidth(
897 	LocalLayouter* localLayouter, BLayoutContext* context, bool realLayout,
898 	float* minHeight, float* maxHeight, float* preferredHeight)
899 {
900 	bool updateCachedInfo = false;
901 
902 	if (_SetHeightForWidthLayoutContext(context)
903 		|| fHeightForWidthLayouter == NULL) {
904 		// Either the layout context changed or we haven't initialized the
905 		// height for width layouter yet. We create it and init it now.
906 
907 		// clone the vertical layouter
908 		delete fHeightForWidthLayouter;
909 		delete fLayoutInfo;
910 		fHeightForWidthLayouter = fLayouter->CloneLayouter();
911 		fLayoutInfo = fHeightForWidthLayouter->CreateLayoutInfo();
912 
913 		// add the children's height for width constraints
914 		int32 count = fLocalLayouters.CountItems();
915 		for (int32 i = 0; i < count; i++) {
916 			LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
917 			if (layouter->HasHeightForWidth()) {
918 				layouter->AddHeightForWidthConstraints(this,
919 					fHeightForWidthLayouter, context);
920 			}
921 		}
922 
923 		updateCachedInfo = true;
924 	} else if (localLayouter->HasHeightForWidth()) {
925 		// There is a height for width layouter and it has been initialized
926 		// in the current layout context. So we just add the height for width
927 		// constraints of the calling local layouter, if they haven't been
928 		// added yet.
929 		updateCachedInfo = localLayouter->AddHeightForWidthConstraints(this,
930 			fHeightForWidthLayouter, context);
931 	}
932 
933 	// update cached height for width info, if something changed
934 	if (updateCachedInfo) {
935 		// get the height for width info
936 		fCachedMinHeightForWidth = fHeightForWidthLayouter->MinSize();
937 		fCachedMaxHeightForWidth = fHeightForWidthLayouter->MaxSize();
938 		fCachedPreferredHeightForWidth
939 			= fHeightForWidthLayouter->PreferredSize();
940 	}
941 
942 	if (minHeight)
943 		*minHeight = fCachedMinHeightForWidth;
944 	if (maxHeight)
945 		*maxHeight = fCachedMaxHeightForWidth;
946 	if (preferredHeight)
947 		*preferredHeight = fCachedPreferredHeightForWidth;
948 }
949 
950 
951 void
DoLayout(float size,LocalLayouter * localLayouter,BLayoutContext * context)952 BTwoDimensionalLayout::VerticalCompoundLayouter::DoLayout(float size,
953 	LocalLayouter* localLayouter, BLayoutContext* context)
954 {
955 	Layouter* layouter;
956 	if (_HasHeightForWidth()) {
957 		float minHeight, maxHeight, preferredHeight;
958 		InternalGetHeightForWidth(localLayouter, context, true, &minHeight,
959 			&maxHeight, &preferredHeight);
960 		size = max_c(size, minHeight);
961 		layouter = fHeightForWidthLayouter;
962 	} else
963 		layouter = fLayouter;
964 
965 	layouter->Layout(fLayoutInfo, size);
966 }
967 
968 
969 bool
_HasHeightForWidth()970 BTwoDimensionalLayout::VerticalCompoundLayouter::_HasHeightForWidth()
971 {
972 	int32 count = fLocalLayouters.CountItems();
973 	for (int32 i = 0; i < count; i++) {
974 		LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
975 		if (layouter->HasHeightForWidth())
976 			return true;
977 	}
978 
979 	return false;
980 }
981 
982 
983 bool
984 BTwoDimensionalLayout::VerticalCompoundLayouter
_SetHeightForWidthLayoutContext(BLayoutContext * context)985 	::_SetHeightForWidthLayoutContext(BLayoutContext* context)
986 {
987 	if (context == fHeightForWidthLayoutContext)
988 		return false;
989 
990 	if (fHeightForWidthLayoutContext != NULL) {
991 		fHeightForWidthLayoutContext->RemoveListener(this);
992 		fHeightForWidthLayoutContext = NULL;
993 	}
994 
995 	// We can ignore the whole context business, if we have no more than one
996 	// local layouter. We use the layout context only to recognize when calls
997 	// of different local layouters belong to the same context.
998 	if (fLocalLayouters.CountItems() <= 1)
999 		return false;
1000 
1001 	fHeightForWidthLayoutContext = context;
1002 
1003 	if (fHeightForWidthLayoutContext != NULL)
1004 		fHeightForWidthLayoutContext->AddListener(this);
1005 
1006 	InvalidateHeightForWidth();
1007 
1008 	return true;
1009 }
1010 
1011 
1012 void
LayoutContextLeft(BLayoutContext * context)1013 BTwoDimensionalLayout::VerticalCompoundLayouter::LayoutContextLeft(
1014 	BLayoutContext* context)
1015 {
1016 	fHeightForWidthLayoutContext = NULL;
1017 }
1018 
1019 
1020 // #pragma mark - LocalLayouter
1021 
1022 
LocalLayouter(BTwoDimensionalLayout * layout)1023 BTwoDimensionalLayout::LocalLayouter::LocalLayouter(
1024 		BTwoDimensionalLayout* layout)
1025 	:
1026 	fLayout(layout),
1027 	fHLayouter(new CompoundLayouter(B_HORIZONTAL)),
1028 	fVLayouter(new VerticalCompoundLayouter),
1029 	fHeightForWidthItems(),
1030 	fHorizontalLayoutContext(NULL),
1031 	fHorizontalLayoutWidth(0),
1032 	fHeightForWidthConstraintsAdded(false)
1033 {
1034 	fHLayouter->AddLocalLayouter(this);
1035 	fVLayouter->AddLocalLayouter(this);
1036 }
1037 
1038 
~LocalLayouter()1039 BTwoDimensionalLayout::LocalLayouter::~LocalLayouter()
1040 {
1041 	if (fHLayouter != NULL) {
1042 		fHLayouter->RemoveLocalLayouter(this);
1043 		fHLayouter->ReleaseReference();
1044 	}
1045 
1046 	if (fVLayouter != NULL) {
1047 		fVLayouter->RemoveLocalLayouter(this);
1048 		fVLayouter->ReleaseReference();
1049 	}
1050 }
1051 
1052 
1053 BSize
MinSize()1054 BTwoDimensionalLayout::LocalLayouter::MinSize()
1055 {
1056 	return BSize(fHLayouter->GetLayouter(true)->MinSize(),
1057 		fVLayouter->GetLayouter(true)->MinSize());
1058 }
1059 
1060 
1061 BSize
MaxSize()1062 BTwoDimensionalLayout::LocalLayouter::MaxSize()
1063 {
1064 	return BSize(fHLayouter->GetLayouter(true)->MaxSize(),
1065 		fVLayouter->GetLayouter(true)->MaxSize());
1066 }
1067 
1068 
1069 BSize
PreferredSize()1070 BTwoDimensionalLayout::LocalLayouter::PreferredSize()
1071 {
1072 	return BSize(fHLayouter->GetLayouter(true)->PreferredSize(),
1073 		fVLayouter->GetLayouter(true)->PreferredSize());
1074 }
1075 
1076 
1077 void
InvalidateLayout()1078 BTwoDimensionalLayout::LocalLayouter::InvalidateLayout()
1079 {
1080 	fHLayouter->InvalidateLayout();
1081 	fVLayouter->InvalidateLayout();
1082 }
1083 
1084 
1085 void
Layout(BSize size)1086 BTwoDimensionalLayout::LocalLayouter::Layout(BSize size)
1087 {
1088 	DoHorizontalLayout(size.width);
1089 	fVLayouter->Layout(size.height, this, fLayout->LayoutContext());
1090 }
1091 
1092 
1093 BRect
ItemFrame(Dimensions itemDimensions)1094 BTwoDimensionalLayout::LocalLayouter::ItemFrame(Dimensions itemDimensions)
1095 {
1096 	LayoutInfo* hLayoutInfo = fHLayouter->GetLayoutInfo();
1097 	LayoutInfo* vLayoutInfo = fVLayouter->GetLayoutInfo();
1098 	float x = hLayoutInfo->ElementLocation(itemDimensions.x);
1099 	float y = vLayoutInfo->ElementLocation(itemDimensions.y);
1100 	float width = hLayoutInfo->ElementRangeSize(itemDimensions.x,
1101 		itemDimensions.width);
1102 	float height = vLayoutInfo->ElementRangeSize(itemDimensions.y,
1103 		itemDimensions.height);
1104 	return BRect(x, y, x + width, y + height);
1105 }
1106 
1107 
1108 void
ValidateMinMax()1109 BTwoDimensionalLayout::LocalLayouter::ValidateMinMax()
1110 {
1111 	if (fHLayouter->IsMinMaxValid() && fVLayouter->IsMinMaxValid())
1112 		return;
1113 
1114 	if (!fHLayouter->IsMinMaxValid())
1115 		fHeightForWidthItems.MakeEmpty();
1116 
1117 	_SetHorizontalLayoutContext(NULL, -1);
1118 
1119 	fHLayouter->ValidateMinMax();
1120 	fVLayouter->ValidateMinMax();
1121 	fLayout->ResetLayoutInvalidation();
1122 }
1123 
1124 
1125 void
DoHorizontalLayout(float width)1126 BTwoDimensionalLayout::LocalLayouter::DoHorizontalLayout(float width)
1127 {
1128 	BLayoutContext* context = fLayout->LayoutContext();
1129 	if (fHorizontalLayoutContext != context
1130 			|| width != fHorizontalLayoutWidth) {
1131 		_SetHorizontalLayoutContext(context, width);
1132 		fHLayouter->Layout(width, this, context);
1133 		fVLayouter->InvalidateHeightForWidth();
1134 	}
1135 }
1136 
1137 
1138 void
InternalGetHeightForWidth(float width,float * minHeight,float * maxHeight,float * preferredHeight)1139 BTwoDimensionalLayout::LocalLayouter::InternalGetHeightForWidth(float width,
1140 	float* minHeight, float* maxHeight, float* preferredHeight)
1141 {
1142 	DoHorizontalLayout(width);
1143 	fVLayouter->InternalGetHeightForWidth(this, fHorizontalLayoutContext, false,
1144 		minHeight, maxHeight, preferredHeight);
1145 }
1146 
1147 
1148 void
AlignWith(LocalLayouter * other,orientation orientation)1149 BTwoDimensionalLayout::LocalLayouter::AlignWith(LocalLayouter* other,
1150 	orientation orientation)
1151 {
1152 	if (orientation == B_HORIZONTAL)
1153 		other->fHLayouter->AbsorbCompoundLayouter(fHLayouter);
1154 	else
1155 		other->fVLayouter->AbsorbCompoundLayouter(fVLayouter);
1156 }
1157 
1158 
1159 status_t
AddAlignedLayoutsToArchive(BArchiver * archiver)1160 BTwoDimensionalLayout::LocalLayouter::AddAlignedLayoutsToArchive(
1161 	BArchiver* archiver)
1162 {
1163 	status_t err = fHLayouter->AddAlignedLayoutsToArchive(archiver, this);
1164 
1165 	if (err == B_OK)
1166 		err = fVLayouter->AddAlignedLayoutsToArchive(archiver, this);
1167 
1168 	return err;
1169 }
1170 
1171 
1172 status_t
AddOwnerToArchive(BArchiver * archiver,CompoundLayouter * requestedBy,bool & _wasAvailable)1173 BTwoDimensionalLayout::LocalLayouter::AddOwnerToArchive(BArchiver* archiver,
1174 	CompoundLayouter* requestedBy, bool& _wasAvailable)
1175 {
1176 	const char* field = kHAlignedLayoutField;
1177 	if (requestedBy == fVLayouter)
1178 		field = kVAlignedLayoutField;
1179 
1180 	if ((_wasAvailable = archiver->IsArchived(fLayout)))
1181 		return archiver->AddArchivable(field, fLayout);
1182 
1183 	return B_NAME_NOT_FOUND;
1184 }
1185 
1186 
1187 status_t
AlignLayoutsFromArchive(BUnarchiver * unarchiver,orientation posture)1188 BTwoDimensionalLayout::LocalLayouter::AlignLayoutsFromArchive(
1189 	BUnarchiver* unarchiver, orientation posture)
1190 {
1191 	const char* field = kHAlignedLayoutField;
1192 	if (posture == B_VERTICAL)
1193 		field = kVAlignedLayoutField;
1194 
1195 	int32 count;
1196 	status_t err = unarchiver->ArchiveMessage()->GetInfo(field, NULL, &count);
1197 	if (err == B_NAME_NOT_FOUND)
1198 		return B_OK;
1199 
1200 	BTwoDimensionalLayout* retriever;
1201 	for (int32 i = 0; i < count && err == B_OK; i++) {
1202 		err = unarchiver->FindObject(field, i,
1203 			BUnarchiver::B_DONT_ASSUME_OWNERSHIP, retriever);
1204 
1205 		if (err == B_OK)
1206 			retriever->AlignLayoutWith(fLayout, posture);
1207 	}
1208 
1209 	return err;
1210 }
1211 
1212 
1213 void
PrepareItems(CompoundLayouter * compoundLayouter)1214 BTwoDimensionalLayout::LocalLayouter::PrepareItems(
1215 	CompoundLayouter* compoundLayouter)
1216 {
1217 	fLayout->PrepareItems(compoundLayouter->Orientation());
1218 }
1219 
1220 
1221 int32
CountElements(CompoundLayouter * compoundLayouter)1222 BTwoDimensionalLayout::LocalLayouter::CountElements(
1223 	CompoundLayouter* compoundLayouter)
1224 {
1225 	if (compoundLayouter->Orientation() == B_HORIZONTAL)
1226 		return fLayout->InternalCountColumns();
1227 	else
1228 		return fLayout->InternalCountRows();
1229 }
1230 
1231 
1232 bool
HasMultiElementItems(CompoundLayouter * compoundLayouter)1233 BTwoDimensionalLayout::LocalLayouter::HasMultiElementItems(
1234 	CompoundLayouter* compoundLayouter)
1235 {
1236 	if (compoundLayouter->Orientation() == B_HORIZONTAL)
1237 		return fLayout->HasMultiColumnItems();
1238 	else
1239 		return fLayout->HasMultiRowItems();
1240 }
1241 
1242 
1243 void
AddConstraints(CompoundLayouter * compoundLayouter,Layouter * layouter)1244 BTwoDimensionalLayout::LocalLayouter::AddConstraints(
1245 	CompoundLayouter* compoundLayouter, Layouter* layouter)
1246 {
1247 	enum orientation orientation = compoundLayouter->Orientation();
1248 	int itemCount = fLayout->CountItems();
1249 	if (itemCount > 0) {
1250 		for (int i = 0; i < itemCount; i++) {
1251 			BLayoutItem* item = fLayout->ItemAt(i);
1252 			if (item->IsVisible()) {
1253 				Dimensions itemDimensions;
1254 				fLayout->GetItemDimensions(item, &itemDimensions);
1255 
1256 				BSize min = item->MinSize();
1257 				BSize max = item->MaxSize();
1258 				BSize preferred = item->PreferredSize();
1259 
1260 				if (orientation == B_HORIZONTAL) {
1261 					layouter->AddConstraints(
1262 						itemDimensions.x,
1263 						itemDimensions.width,
1264 						min.width,
1265 						max.width,
1266 						preferred.width);
1267 
1268 					if (item->HasHeightForWidth())
1269 						fHeightForWidthItems.AddItem(item);
1270 
1271 				} else {
1272 					layouter->AddConstraints(
1273 						itemDimensions.y,
1274 						itemDimensions.height,
1275 						min.height,
1276 						max.height,
1277 						preferred.height);
1278 				}
1279 			}
1280 		}
1281 
1282 		// add column/row constraints
1283 		ColumnRowConstraints constraints;
1284 		int elementCount = CountElements(compoundLayouter);
1285 		for (int element = 0; element < elementCount; element++) {
1286 			fLayout->GetColumnRowConstraints(orientation, element,
1287 				&constraints);
1288 			layouter->SetWeight(element, constraints.weight);
1289 			layouter->AddConstraints(element, 1, constraints.min,
1290 				constraints.max, constraints.min);
1291 		}
1292 	}
1293 }
1294 
1295 
1296 float
Spacing(CompoundLayouter * compoundLayouter)1297 BTwoDimensionalLayout::LocalLayouter::Spacing(
1298 	CompoundLayouter* compoundLayouter)
1299 {
1300 	return (compoundLayouter->Orientation() == B_HORIZONTAL
1301 		? fLayout->fHSpacing : fLayout->fVSpacing);
1302 }
1303 
1304 
1305 bool
HasHeightForWidth()1306 BTwoDimensionalLayout::LocalLayouter::HasHeightForWidth()
1307 {
1308 	return !fHeightForWidthItems.IsEmpty();
1309 }
1310 
1311 
1312 bool
AddHeightForWidthConstraints(VerticalCompoundLayouter * compoundLayouter,Layouter * layouter,BLayoutContext * context)1313 BTwoDimensionalLayout::LocalLayouter::AddHeightForWidthConstraints(
1314 	VerticalCompoundLayouter* compoundLayouter, Layouter* layouter,
1315 	BLayoutContext* context)
1316 {
1317 	if (context != fHorizontalLayoutContext)
1318 		return false;
1319 
1320 	if (fHeightForWidthConstraintsAdded)
1321 		return false;
1322 
1323 	LayoutInfo* hLayoutInfo = fHLayouter->GetLayoutInfo();
1324 
1325 	// add the children's height for width constraints
1326 	int32 itemCount = fHeightForWidthItems.CountItems();
1327 	for (int32 i = 0; i < itemCount; i++) {
1328 		BLayoutItem* item = (BLayoutItem*)fHeightForWidthItems.ItemAt(i);
1329 		Dimensions itemDimensions;
1330 		fLayout->GetItemDimensions(item, &itemDimensions);
1331 
1332 		float minHeight, maxHeight, preferredHeight;
1333 		item->GetHeightForWidth(
1334 			hLayoutInfo->ElementRangeSize(itemDimensions.x,
1335 				itemDimensions.width),
1336 			&minHeight, &maxHeight, &preferredHeight);
1337 		layouter->AddConstraints(
1338 			itemDimensions.y,
1339 			itemDimensions.height,
1340 			minHeight,
1341 			maxHeight,
1342 			preferredHeight);
1343 	}
1344 
1345 	SetHeightForWidthConstraintsAdded(true);
1346 
1347 	return true;
1348 }
1349 
1350 
1351 void
SetHeightForWidthConstraintsAdded(bool added)1352 BTwoDimensionalLayout::LocalLayouter::SetHeightForWidthConstraintsAdded(
1353 	bool added)
1354 {
1355 	fHeightForWidthConstraintsAdded = added;
1356 }
1357 
1358 
1359 void
SetCompoundLayouter(CompoundLayouter * compoundLayouter,orientation orientation)1360 BTwoDimensionalLayout::LocalLayouter::SetCompoundLayouter(
1361 	CompoundLayouter* compoundLayouter, orientation orientation)
1362 {
1363 	CompoundLayouter* oldCompoundLayouter;
1364 	if (orientation == B_HORIZONTAL) {
1365 		oldCompoundLayouter = fHLayouter;
1366 		fHLayouter = compoundLayouter;
1367 	} else {
1368 		oldCompoundLayouter = fVLayouter;
1369 		fVLayouter = static_cast<VerticalCompoundLayouter*>(compoundLayouter);
1370 	}
1371 
1372 	if (compoundLayouter == oldCompoundLayouter)
1373 		return;
1374 
1375 	if (oldCompoundLayouter != NULL) {
1376 		oldCompoundLayouter->RemoveLocalLayouter(this);
1377 		oldCompoundLayouter->ReleaseReference();
1378 	}
1379 
1380 	if (compoundLayouter != NULL)
1381 		compoundLayouter->AcquireReference();
1382 
1383 	InternalInvalidateLayout(compoundLayouter);
1384 }
1385 
1386 
1387 void
InternalInvalidateLayout(CompoundLayouter * compoundLayouter)1388 BTwoDimensionalLayout::LocalLayouter::InternalInvalidateLayout(
1389 	CompoundLayouter* compoundLayouter)
1390 {
1391 	_SetHorizontalLayoutContext(NULL, -1);
1392 
1393 	fLayout->BLayout::InvalidateLayout();
1394 }
1395 
1396 
1397 void
_SetHorizontalLayoutContext(BLayoutContext * context,float width)1398 BTwoDimensionalLayout::LocalLayouter::_SetHorizontalLayoutContext(
1399 	BLayoutContext* context, float width)
1400 {
1401 	if (context != fHorizontalLayoutContext) {
1402 		if (fHorizontalLayoutContext != NULL)
1403 			fHorizontalLayoutContext->RemoveListener(this);
1404 
1405 		fHorizontalLayoutContext = context;
1406 
1407 		if (fHorizontalLayoutContext != NULL)
1408 			fHorizontalLayoutContext->AddListener(this);
1409 	}
1410 
1411 	fHorizontalLayoutWidth = width;
1412 }
1413 
1414 
1415 void
LayoutContextLeft(BLayoutContext * context)1416 BTwoDimensionalLayout::LocalLayouter::LayoutContextLeft(BLayoutContext* context)
1417 {
1418 	fHorizontalLayoutContext = NULL;
1419 	fHorizontalLayoutWidth = -1;
1420 }
1421 
1422 
1423 status_t
Perform(perform_code code,void * _data)1424 BTwoDimensionalLayout::Perform(perform_code code, void* _data)
1425 {
1426 	return BAbstractLayout::Perform(code, _data);
1427 }
1428 
1429 
_ReservedTwoDimensionalLayout1()1430 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout1() {}
_ReservedTwoDimensionalLayout2()1431 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout2() {}
_ReservedTwoDimensionalLayout3()1432 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout3() {}
_ReservedTwoDimensionalLayout4()1433 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout4() {}
_ReservedTwoDimensionalLayout5()1434 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout5() {}
_ReservedTwoDimensionalLayout6()1435 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout6() {}
_ReservedTwoDimensionalLayout7()1436 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout7() {}
_ReservedTwoDimensionalLayout8()1437 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout8() {}
_ReservedTwoDimensionalLayout9()1438 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout9() {}
_ReservedTwoDimensionalLayout10()1439 void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout10() {}
1440 
1441