xref: /haiku/src/tests/kits/interface/layout/LayoutTest1.cpp (revision 7749d0bb0c358a3279b1b9cc76d8376e900130a5)
1 
2 #include <stdio.h>
3 #include <stdlib.h>
4 
5 #include <typeinfo>
6 
7 #include <Application.h>
8 #include <Button.h>
9 #include <CardLayout.h>
10 #include <LayoutBuilder.h>
11 #include <LayoutUtils.h>
12 #include <ListView.h>
13 #include <MenuField.h>
14 #include <RadioButton.h>
15 #include <ScrollView.h>
16 #include <String.h>
17 #include <StringView.h>
18 #include <TextControl.h>
19 #include <View.h>
20 #include <Window.h>
21 
22 
23 static const rgb_color kBlack	= {0, 0, 0, 255};
24 static const rgb_color kRed		= {255, 0, 0, 255};
25 
26 // message what codes
27 enum {
28 	MSG_TEST_SELECTED		= 'tsts',
29 
30 	// used in tests
31 	MSG_TOGGLE_1			= 'tgl1',
32 	MSG_TOGGLE_2			= 'tgl2',
33 
34 	MSG_FIXED_ASPECT_RATIO	= 'hwas',
35 	MSG_FIXED_SUM			= 'hwfs',
36 	MSG_FIXED_PRODUCT		= 'hwfp',
37 };
38 
39 // HeightForWidthTestView types
40 enum {
41 	FIXED_SUM,
42 	FIXED_PRODUCT,
43 	FIXED_ASPECT_RATIO,
44 };
45 
46 
47 // TestView
48 class TestView : public BView {
49 public:
50 	TestView(const rgb_color& color = kBlack)
51 		: BView("test view", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
52 		  fColor(color)
53 	{
54 	}
55 
56 	void SetColor(const rgb_color& color)
57 	{
58 		fColor = color;
59 		Invalidate();
60 	}
61 
62 	virtual void Draw(BRect updateRect)
63 	{
64 		SetHighColor(fColor);
65 
66 		BRect bounds(Bounds());
67 		StrokeRect(bounds);
68 
69 		BPoint rightBottom = bounds.RightBottom();
70 		StrokeLine(B_ORIGIN, rightBottom);
71 		StrokeLine(BPoint(rightBottom.x, 0), BPoint(0, rightBottom.y));
72 	}
73 
74 	virtual BSize MinSize()
75 	{
76 		return BLayoutUtils::ComposeSize(ExplicitMinSize(), BSize(10, 10));
77 	}
78 
79 	virtual BSize PreferredSize()
80 	{
81 		return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
82 			BSize(50, 50));
83 	}
84 
85 private:
86 	rgb_color	fColor;
87 };
88 
89 
90 // HeightForWidthTestView
91 class HeightForWidthTestView : public TestView {
92 public:
93 	HeightForWidthTestView(uint32 type, float value)
94 		: fType(NULL)
95 	{
96 		SetType(type, value);
97 	}
98 
99 	HeightForWidthTestView(const rgb_color& color, uint32 type, float value)
100 		: TestView(color),
101 		  fType(NULL)
102 	{
103 		SetType(type, value);
104 	}
105 
106 	~HeightForWidthTestView()
107 	{
108 		delete fType;
109 	}
110 
111 	void SetType(uint32 type, float value)
112 	{
113 		delete fType;
114 
115 		switch (type) {
116 			case FIXED_SUM:
117 				fType = new FixedSumType((int)value);
118 				break;
119 			case FIXED_PRODUCT:
120 				fType = new FixedProductType((int)value);
121 				break;
122 			case FIXED_ASPECT_RATIO:
123 			default:
124 				fType = new FixedAspectRatioType(value);
125 				break;
126 		}
127 
128 		InvalidateLayout();
129 	}
130 
131 	BSize MinSize() {
132 		return BLayoutUtils::ComposeSize(ExplicitMinSize(), fType->MinSize());
133 	}
134 
135 	BSize MaxSize() {
136 		return BLayoutUtils::ComposeSize(ExplicitMaxSize(), fType->MaxSize());
137 	}
138 
139 	BSize PreferredSize() {
140 		return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
141 			fType->PreferredSize());
142 	}
143 
144 	bool HasHeightForWidth() {
145 		return true;
146 	}
147 
148 	void GetHeightForWidth(float width, float* minHeight, float* maxHeight,
149 			float* preferredHeight) {
150 		float dummy;
151 		fType->GetHeightForWidth(width,
152 			minHeight ? minHeight : &dummy,
153 			maxHeight ? maxHeight : &dummy,
154 			preferredHeight ? preferredHeight : &dummy);
155 	}
156 
157 private:
158 	class HeightForWidthType {
159 	public:
160 		virtual ~HeightForWidthType()
161 		{
162 		}
163 
164 		virtual BSize MinSize() = 0;
165 		virtual BSize MaxSize() = 0;
166 		virtual BSize PreferredSize() = 0;
167 		virtual void GetHeightForWidth(float width, float* minHeight,
168 			float* maxHeight, float* preferredHeight) = 0;
169 	};
170 
171 	class FixedAspectRatioType : public HeightForWidthType {
172 	public:
173 		FixedAspectRatioType(float ratio)
174 			: fAspectRatio(ratio)
175 		{
176 		}
177 
178 		virtual BSize MinSize()
179 		{
180 			return BSize(-1, -1);
181 		}
182 
183 		virtual BSize MaxSize()
184 		{
185 			return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
186 		}
187 
188 		virtual BSize PreferredSize()
189 		{
190 			float preferredWidth = 49;
191 			float dummy, preferredHeight;
192 			GetHeightForWidth(preferredWidth, &dummy, &dummy, &preferredHeight);
193 			return BSize(preferredWidth, preferredHeight);
194 		}
195 
196 		virtual void GetHeightForWidth(float width, float* minHeight,
197 			float* maxHeight, float* preferredHeight)
198 		{
199 			float height = floor((width + 1) * fAspectRatio) - 1;
200 			*minHeight = height;
201 			*maxHeight = height;
202 			*preferredHeight = height;
203 		}
204 
205 	private:
206 		float	fAspectRatio;
207 	};
208 
209 	class FixedSumType : public HeightForWidthType {
210 	public:
211 		FixedSumType(float sum)
212 			: fSum(sum)
213 		{
214 		}
215 
216 		virtual BSize MinSize()
217 		{
218 			return BSize(0, 0);
219 		}
220 
221 		virtual BSize MaxSize()
222 		{
223 			return BSize(fSum - 2, fSum - 2);
224 		}
225 
226 		virtual BSize PreferredSize()
227 		{
228 			float preferredWidth = floor(fSum / 2) - 1;
229 			float dummy, preferredHeight;
230 			GetHeightForWidth(preferredWidth, &dummy, &dummy, &preferredHeight);
231 			return BSize(preferredWidth, preferredHeight);
232 		}
233 
234 		virtual void GetHeightForWidth(float width, float* minHeight,
235 			float* maxHeight, float* preferredHeight)
236 		{
237 			float height = fSum - (width + 1) - 1;
238 			*minHeight = height;
239 			*maxHeight = height;
240 			*preferredHeight = height;
241 		}
242 
243 	private:
244 		float	fSum;
245 	};
246 
247 	class FixedProductType : public HeightForWidthType {
248 	public:
249 		FixedProductType(float product)
250 			: fProduct(product)
251 		{
252 		}
253 
254 		virtual BSize MinSize()
255 		{
256 			return BSize(0, 0);
257 		}
258 
259 		virtual BSize MaxSize()
260 		{
261 			return BSize(fProduct - 1, fProduct - 1);
262 		}
263 
264 		virtual BSize PreferredSize()
265 		{
266 			float preferredWidth = floor(sqrt(fProduct));
267 			float dummy, preferredHeight;
268 			GetHeightForWidth(preferredWidth, &dummy, &dummy, &preferredHeight);
269 			return BSize(preferredWidth, preferredHeight);
270 		}
271 
272 		virtual void GetHeightForWidth(float width, float* minHeight,
273 			float* maxHeight, float* preferredHeight)
274 		{
275 			float height = floor(fProduct / (width + 1)) - 1;
276 			*minHeight = height;
277 			*maxHeight = height;
278 			*preferredHeight = height;
279 		}
280 
281 	private:
282 		float	fProduct;
283 	};
284 
285 private:
286 	HeightForWidthType*	fType;
287 };
288 
289 
290 // Test
291 struct Test : BHandler {
292 	BString	name;
293 	BView*	rootView;
294 	BString	description;
295 
296 	Test(const char* name, const char* description)
297 		: BHandler(name),
298 		  name(name),
299 		  rootView(new BView(name, 0)),
300 		  description(description)
301 	{
302 	}
303 
304 	virtual ~Test()
305 	{
306 	}
307 
308 	virtual void RegisterListeners()
309 	{
310 	}
311 };
312 
313 
314 // GroupLayoutTest1
315 struct GroupLayoutTest1 : public Test {
316 	GroupLayoutTest1()
317 		:
318 		Test("Group", "Simple BGroupLayout.")
319 	{
320 		 BLayoutBuilder::Group<>(rootView, B_HORIZONTAL)
321 			// controls
322 			.AddGroup(B_VERTICAL)
323 				.Add(toggleRowButton = new BButton("Toggle Row",
324 						new BMessage(MSG_TOGGLE_1)))
325 				.Add(toggleViewButton = new BButton("Toggle View",
326 						new BMessage(MSG_TOGGLE_2)))
327 				.AddGlue()
328 				.End()
329 
330 			// test views
331 			.AddGroup(B_VERTICAL)
332 				// row 1
333 				.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1)
334 					.Add(new TestView(), 1)
335 					.Add(toggledView = new TestView(), 2)
336 					.Add(new TestView(), 3)
337 					.End()
338 
339 				// row 2
340 				.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 2)
341 					.GetView(&toggledRow)
342 					.Add(new TestView())
343 					.Add(new TestView())
344 					.Add(new TestView())
345 					.End()
346 
347 				// row 3
348 				.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 3)
349 					.Add(new TestView(), 3)
350 					.Add(new TestView(), 2)
351 					.Add(new TestView(), 1);
352 	}
353 
354 	virtual void RegisterListeners()
355 	{
356 		toggleRowButton->SetTarget(this);
357 		toggleViewButton->SetTarget(this);
358 	}
359 
360 	virtual void MessageReceived(BMessage* message)
361 	{
362 		switch (message->what) {
363 			case MSG_TOGGLE_1:
364 			{
365 				if (toggledRow->IsHidden(toggledRow))
366 					toggledRow->Show();
367 				else
368 					toggledRow->Hide();
369 				break;
370 			}
371 
372 			case MSG_TOGGLE_2:
373 			{
374 				if (toggledView->IsHidden(toggledView))
375 					toggledView->Show();
376 				else
377 					toggledView->Hide();
378 				break;
379 			}
380 
381 			default:
382 				BHandler::MessageReceived(message);
383 				break;
384 		}
385 	}
386 
387 private:
388 	BButton*	toggleRowButton;
389 	BButton*	toggleViewButton;
390 	BView*		toggledRow;
391 	TestView*	toggledView;
392 };
393 
394 
395 // GroupAlignedLayoutTest1
396 struct GroupAlignedLayoutTest1 : public Test {
397 	GroupAlignedLayoutTest1()
398 		: Test("Group aligned", "Simple BGroupLayout, rows 1 and 3 aligned.")
399 	{
400 		BGroupView* rootView  = new BGroupView(B_HORIZONTAL, 10);
401 		this->rootView = rootView;
402 
403 		// controls
404 
405 		BGroupView* controls = new BGroupView(B_VERTICAL, 10);
406 		rootView->AddChild(controls);
407 
408 		toggleRowButton = new BButton("Toggle Row", new BMessage(MSG_TOGGLE_1));
409 		controls->AddChild(toggleRowButton);
410 
411 		toggleViewButton = new BButton("Toggle View",
412 			new BMessage(MSG_TOGGLE_2));
413 		controls->AddChild(toggleViewButton);
414 
415 
416 		controls->AddChild(BSpaceLayoutItem::CreateGlue());
417 
418 		// test views
419 
420 		BGroupView* testViews = new BGroupView(B_VERTICAL, 10);
421 		rootView->AddChild(testViews);
422 
423 		// row 1
424 		BGroupView* row = new BGroupView(B_HORIZONTAL, 10);
425 		BGroupView* row1 = row;
426 		testViews->GroupLayout()->AddView(row, 1);
427 
428 		row->GroupLayout()->AddView(new TestView(), 1);
429 		toggledView = new TestView();
430 		row->GroupLayout()->AddView(toggledView, 2);
431 		row->GroupLayout()->AddView(new TestView(), 3);
432 
433 		// row 2
434 		row = new BGroupView(B_HORIZONTAL, 10);
435 		toggledRow = row;
436 		testViews->GroupLayout()->AddView(row, 2);
437 
438 		row->GroupLayout()->AddView(new TestView());
439 		row->GroupLayout()->AddView(new TestView());
440 		row->GroupLayout()->AddView(new TestView());
441 
442 		// row 3
443 		row = new BGroupView(B_HORIZONTAL, 10);
444 		BGroupView* row3 = row;
445 		testViews->GroupLayout()->AddView(row, 3);
446 
447 		row->GroupLayout()->AddView(new TestView(), 3);
448 		row->GroupLayout()->AddView(new TestView(), 2);
449 		row->GroupLayout()->AddView(new TestView(), 1);
450 
451 		// align rows 1 and 3
452 		row1->GroupLayout()->AlignLayoutWith(row3->GroupLayout(), B_HORIZONTAL);
453 	}
454 
455 	virtual void RegisterListeners()
456 	{
457 		toggleRowButton->SetTarget(this);
458 		toggleViewButton->SetTarget(this);
459 	}
460 
461 	virtual void MessageReceived(BMessage* message)
462 	{
463 		switch (message->what) {
464 			case MSG_TOGGLE_1:
465 			{
466 				if (toggledRow->IsHidden(toggledRow))
467 					toggledRow->Show();
468 				else
469 					toggledRow->Hide();
470 				break;
471 			}
472 
473 			case MSG_TOGGLE_2:
474 			{
475 				if (toggledView->IsHidden(toggledView))
476 					toggledView->Show();
477 				else
478 					toggledView->Hide();
479 				break;
480 			}
481 
482 			default:
483 				BHandler::MessageReceived(message);
484 				break;
485 		}
486 	}
487 
488 private:
489 	BButton*	toggleRowButton;
490 	BButton*	toggleViewButton;
491 	BGroupView*	toggledRow;
492 	TestView*	toggledView;
493 };
494 
495 
496 // GridLayoutTest1
497 struct GridLayoutTest1 : public Test {
498 	GridLayoutTest1()
499 		: Test("Grid", "Simple BGridLayout.")
500 	{
501 		BLayoutBuilder::Group<>(rootView, B_HORIZONTAL)
502 			// controls
503 			.AddGroup(B_VERTICAL)
504 				.Add(toggleView1Button = new BButton("Toggle View 1",
505 						new BMessage(MSG_TOGGLE_1)))
506 				.Add(toggleView2Button = new BButton("Toggle View 2",
507 						new BMessage(MSG_TOGGLE_2)))
508 				.AddGlue()
509 				.End()
510 
511 			// test views
512 			.AddGrid()
513 				// row 1
514 				.Add(toggledView1 = new TestView(), 0, 0, 3, 1)
515 				.Add(new TestView(), 3, 0)
516 				.Add(new TestView(), 4, 0)
517 
518 				// row 2
519 				.Add(new TestView(), 0, 1)
520 				.Add(new TestView(), 1, 1)
521 				.Add(new TestView(), 2, 1)
522 				.Add(new TestView(), 3, 1)
523 				.Add(new TestView(), 4, 1)
524 
525 				// row 3
526 				.Add(new TestView(), 0, 2)
527 				.Add(toggledView2 = new TestView(), 1, 2, 2, 2)
528 				.Add(new TestView(), 3, 2)
529 				.Add(new TestView(), 4, 2)
530 
531 				// row 4
532 				.Add(new TestView(), 0, 3)
533 				.Add(new TestView(), 3, 3)
534 				.Add(new TestView(), 4, 3)
535 
536 				// weights
537 				.SetColumnWeight(0, 1)
538 				.SetColumnWeight(1, 2)
539 				.SetColumnWeight(2, 3)
540 				.SetColumnWeight(3, 4)
541 				.SetColumnWeight(4, 5)
542 
543 				.SetRowWeight(0, 1)
544 				.SetRowWeight(1, 2)
545 				.SetRowWeight(2, 3)
546 				.SetRowWeight(3, 4);
547 	}
548 
549 	virtual void RegisterListeners()
550 	{
551 		toggleView1Button->SetTarget(this);
552 		toggleView2Button->SetTarget(this);
553 	}
554 
555 	virtual void MessageReceived(BMessage* message)
556 	{
557 		switch (message->what) {
558 			case MSG_TOGGLE_1:
559 			{
560 				if (toggledView1->IsHidden(toggledView1))
561 					toggledView1->Show();
562 				else
563 					toggledView1->Hide();
564 				break;
565 			}
566 
567 			case MSG_TOGGLE_2:
568 			{
569 				if (toggledView2->IsHidden(toggledView2))
570 					toggledView2->Show();
571 				else
572 					toggledView2->Hide();
573 				break;
574 			}
575 
576 			default:
577 				BHandler::MessageReceived(message);
578 				break;
579 		}
580 	}
581 
582 private:
583 	BButton*	toggleView1Button;
584 	BButton*	toggleView2Button;
585 	TestView*	toggledView1;
586 	TestView*	toggledView2;
587 };
588 
589 
590 // SplitterGroupLayoutTest1
591 struct SplitterGroupLayoutTest1 : public Test {
592 	SplitterGroupLayoutTest1()
593 		: Test("Group, splitters 1", "BGroupLayout with BSplitters.")
594 	{
595 		BLayoutBuilder::Group<>(rootView, B_HORIZONTAL)
596 			// controls
597 			.AddGroup(B_VERTICAL)
598 				.Add(toggleRowButton = new BButton("Toggle Row",
599 						new BMessage(MSG_TOGGLE_1)))
600 				.Add(toggleViewButton = new BButton("Toggle View",
601 						new BMessage(MSG_TOGGLE_2)))
602 				.AddGlue()
603 				.End()
604 
605 			// test views
606 			.AddSplit(B_VERTICAL)
607 				// row 1
608 				.AddSplit(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1)
609 					.Add(new TestView(), 1)
610 					.Add(toggledView = new TestView(), 2)
611 					.Add(new TestView(), 3)
612 					.End()
613 				// make the row uncollapsible
614 				.SetCollapsible(false)
615 
616 				// row 2
617 				.AddSplit(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 2)
618 					.GetView(&toggledRow)
619 					.Add(new TestView())
620 					.Add(new TestView())
621 					.Add(new TestView())
622 					.End()
623 
624 				// row 3
625 				.AddSplit(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 3)
626 					.Add(new TestView(), 3)
627 					.Add(toggledView = new TestView(), 2)
628 					.Add(new TestView(), 1)
629 					.End()
630 				// make the row uncollapsible
631 				.SetCollapsible(false);
632 	}
633 
634 	virtual void RegisterListeners()
635 	{
636 		toggleRowButton->SetTarget(this);
637 		toggleViewButton->SetTarget(this);
638 	}
639 
640 	virtual void MessageReceived(BMessage* message)
641 	{
642 		switch (message->what) {
643 			case MSG_TOGGLE_1:
644 			{
645 				if (toggledRow->IsHidden(toggledRow))
646 					toggledRow->Show();
647 				else
648 					toggledRow->Hide();
649 				break;
650 			}
651 
652 			case MSG_TOGGLE_2:
653 			{
654 				if (toggledView->IsHidden(toggledView))
655 					toggledView->Show();
656 				else
657 					toggledView->Hide();
658 				break;
659 			}
660 
661 			default:
662 				BHandler::MessageReceived(message);
663 				break;
664 		}
665 	}
666 
667 private:
668 	BButton*	toggleRowButton;
669 	BButton*	toggleViewButton;
670 	BView*		toggledRow;
671 	TestView*	toggledView;
672 };
673 
674 
675 // SplitterGroupLayoutTest2
676 struct SplitterGroupLayoutTest2 : public Test {
677 	SplitterGroupLayoutTest2()
678 		: Test("Group, splitters 2",
679 			"BGroupLayout with BSplitters. Restricted maximum widths.")
680 	{
681 		TestView* testView1 = new TestView();
682 		TestView* testView2 = new TestView();
683 		TestView* testView3 = new TestView();
684 
685 		BLayoutBuilder::Group<>(rootView, B_HORIZONTAL)
686 			// test views
687 			.AddGroup(B_VERTICAL)
688 				// split view
689 				.AddSplit(B_HORIZONTAL)
690 					.Add(testView1, 0)
691 					.Add(testView2, 1)
692 					.Add(testView3, 2);
693 
694 		// set maximal width on the test views
695 		testView1->SetExplicitMaxSize(BSize(100, B_SIZE_UNSET));
696 		testView2->SetExplicitMaxSize(BSize(100, B_SIZE_UNSET));
697 		testView3->SetExplicitMaxSize(BSize(100, B_SIZE_UNSET));
698 	}
699 };
700 
701 
702 // SplitterGridLayoutTest1
703 struct SplitterGridLayoutTest1 : public Test {
704 	SplitterGridLayoutTest1()
705 		: Test("Grid, h splitters", "BGridLayout with horizontal BSplitters.")
706 	{
707 		BGridLayout* layouts[3];
708 
709 		BLayoutBuilder::Group<>(rootView, B_HORIZONTAL)
710 			// controls
711 			.AddGroup(B_VERTICAL)
712 				.Add(toggleView1Button = new BButton("Toggle View 1",
713 						new BMessage(MSG_TOGGLE_1)))
714 				.Add(toggleView2Button = new BButton("Toggle View 2",
715 						new BMessage(MSG_TOGGLE_2)))
716 				.AddGlue()
717 				.End()
718 
719 			// test views
720 			.AddSplit(B_HORIZONTAL)
721 				// splitter element 1
722 				.AddGrid(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, 6)
723 					.GetLayout(&layouts[0])
724 					// row 1
725 					.Add(toggledView1 = new TestView(), 0, 0, 3, 1)
726 					// row 2
727 					.Add(new TestView(), 0, 1)
728 					.Add(new TestView(), 1, 1)
729 					.Add(new TestView(), 2, 1)
730 					// row 3
731 					.Add(new TestView(), 0, 2)
732 					.Add(toggledView2 = new TestView(), 1, 2, 2, 2)
733 					// row 4
734 					.Add(new TestView(), 0, 3)
735 
736 					// column weights
737 					.SetColumnWeight(0, 1)
738 					.SetColumnWeight(1, 2)
739 					.SetColumnWeight(2, 3)
740 					.End()
741 
742 				// splitter element 2
743 				.AddGrid(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, 4)
744 					.GetLayout(&layouts[1])
745 					// row 1
746 					.Add(new TestView(), 0, 0)
747 					// row 2
748 					.Add(new TestView(), 0, 1)
749 					// row 3
750 					.Add(new TestView(), 0, 2)
751 					// row 4
752 					.Add(new TestView(), 0, 3)
753 					.End()
754 
755 				// splitter element 3
756 				.AddGrid(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, 5)
757 					.GetLayout(&layouts[2])
758 					// row 1
759 					.Add(new TestView(), 0, 0)
760 					// row 2
761 					.Add(new TestView(), 0, 1)
762 					// row 3
763 					.Add(new TestView(), 0, 2)
764 					// row 4
765 					.Add(new TestView(), 0, 3);
766 
767 		// set row weights
768 		for (int i = 0; i < 3; i++) {
769 			layouts[i]->SetRowWeight(0, 1);
770 			layouts[i]->SetRowWeight(1, 2);
771 			layouts[i]->SetRowWeight(2, 3);
772 			layouts[i]->SetRowWeight(3, 4);
773 		}
774 
775 		// set explicit min/max heights for toggled views
776 		toggledView1->SetExplicitMinSize(BSize(B_SIZE_UNSET, 100));
777 		toggledView2->SetExplicitMaxSize(BSize(B_SIZE_UNSET, 200));
778 
779 		// align the layouts
780 		layouts[0]->AlignLayoutWith(layouts[1], B_VERTICAL);
781 		layouts[0]->AlignLayoutWith(layouts[2], B_VERTICAL);
782 	}
783 
784 	virtual void RegisterListeners()
785 	{
786 		toggleView1Button->SetTarget(this);
787 		toggleView2Button->SetTarget(this);
788 	}
789 
790 	virtual void MessageReceived(BMessage* message)
791 	{
792 		switch (message->what) {
793 			case MSG_TOGGLE_1:
794 			{
795 				if (toggledView1->IsHidden(toggledView1))
796 					toggledView1->Show();
797 				else
798 					toggledView1->Hide();
799 				break;
800 			}
801 
802 			case MSG_TOGGLE_2:
803 			{
804 				if (toggledView2->IsHidden(toggledView2))
805 					toggledView2->Show();
806 				else
807 					toggledView2->Hide();
808 				break;
809 			}
810 
811 			default:
812 				BHandler::MessageReceived(message);
813 				break;
814 		}
815 	}
816 
817 private:
818 	BButton*	toggleView1Button;
819 	BButton*	toggleView2Button;
820 	TestView*	toggledView1;
821 	TestView*	toggledView2;
822 };
823 
824 
825 // SplitterGridLayoutTest2
826 struct SplitterGridLayoutTest2 : public Test {
827 	SplitterGridLayoutTest2()
828 		: Test("Grid, v splitters", "BGridLayout with vertical BSplitters.")
829 	{
830 		BGridLayout* layouts[3];
831 
832 		BLayoutBuilder::Group<>(rootView, B_HORIZONTAL)
833 			// controls
834 			.AddGroup(B_VERTICAL)
835 				.Add(toggleView1Button = new BButton("Toggle View 1",
836 						new BMessage(MSG_TOGGLE_1)))
837 				.Add(toggleView2Button = new BButton("Toggle View 2",
838 						new BMessage(MSG_TOGGLE_2)))
839 				.AddGlue()
840 			.End()
841 
842 			// test views
843 			.AddSplit(B_VERTICAL)
844 				// splitter element 1
845 				.AddGrid(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, 1)
846 					.GetLayout(&layouts[0])
847 					// row 1
848 					.Add(toggledView1 = new TestView(), 0, 0, 3, 1)
849 					.Add(new TestView(), 3, 0)
850 					.Add(new TestView(), 4, 0)
851 					.End()
852 
853 				// splitter element 2
854 				.AddGrid(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, 2)
855 					.GetLayout(&layouts[1])
856 					// row 2
857 					.Add(new TestView(), 0, 0)
858 					.Add(new TestView(), 1, 0)
859 					.Add(new TestView(), 2, 0)
860 					.Add(new TestView(), 3, 0)
861 					.Add(new TestView(), 4, 0)
862 					.End()
863 
864 				// splitter element 3
865 				.AddGrid(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, 7)
866 					.GetLayout(&layouts[2])
867 					// row 3
868 					.Add(new TestView(), 0, 0)
869 					.Add(toggledView2 = new TestView(), 1, 0, 2, 2)
870 					.Add(new TestView(), 3, 0)
871 					.Add(new TestView(), 4, 0)
872 					// row 4
873 					.Add(new TestView(), 0, 1)
874 					.Add(new TestView(), 3, 1)
875 					.Add(new TestView(), 4, 1)
876 
877 					// row weights
878 					.SetRowWeight(0, 3)
879 					.SetRowWeight(1, 4);
880 
881 		// set column weights
882 		for (int i = 0; i < 3; i++) {
883 			layouts[i]->SetColumnWeight(0, 1);
884 			layouts[i]->SetColumnWeight(1, 2);
885 			layouts[i]->SetColumnWeight(2, 3);
886 			layouts[i]->SetColumnWeight(3, 4);
887 			layouts[i]->SetColumnWeight(4, 5);
888 		}
889 
890 		// align the layouts
891 		layouts[0]->AlignLayoutWith(layouts[1], B_HORIZONTAL);
892 		layouts[0]->AlignLayoutWith(layouts[2], B_HORIZONTAL);
893 	}
894 
895 	virtual void RegisterListeners()
896 	{
897 		toggleView1Button->SetTarget(this);
898 		toggleView2Button->SetTarget(this);
899 	}
900 
901 	virtual void MessageReceived(BMessage* message)
902 	{
903 		switch (message->what) {
904 			case MSG_TOGGLE_1:
905 			{
906 				if (toggledView1->IsHidden(toggledView1))
907 					toggledView1->Show();
908 				else
909 					toggledView1->Hide();
910 				break;
911 			}
912 
913 			case MSG_TOGGLE_2:
914 			{
915 				if (toggledView2->IsHidden(toggledView2))
916 					toggledView2->Show();
917 				else
918 					toggledView2->Hide();
919 				break;
920 			}
921 
922 			default:
923 				BHandler::MessageReceived(message);
924 				break;
925 		}
926 	}
927 
928 private:
929 	BButton*	toggleView1Button;
930 	BButton*	toggleView2Button;
931 	TestView*	toggledView1;
932 	TestView*	toggledView2;
933 };
934 
935 
936 // GroupLayoutHeightForWidthTestHorizontal1
937 struct GroupLayoutHeightForWidthTestHorizontal1 : public Test {
938 	GroupLayoutHeightForWidthTestHorizontal1()
939 		: Test("Group, height for width, h",
940 			"Horizontal BGroupLayout with height for width view.")
941 	{
942 		BLayoutBuilder::Group<>(rootView, B_HORIZONTAL)
943 			// controls
944 			.AddGroup(B_VERTICAL, 10, 0)
945 				.Add(aspectRatioButton = new BRadioButton("fixed aspect ratio",
946 						new BMessage(MSG_FIXED_ASPECT_RATIO)))
947 				.Add(sumButton = new BRadioButton("fixed sum",
948 						new BMessage(MSG_FIXED_SUM)))
949 				.Add(productButton = new BRadioButton("fixed product",
950 						new BMessage(MSG_FIXED_PRODUCT)))
951 				.AddGlue()
952 			.End()
953 
954 			// test views
955 			.AddGroup(B_VERTICAL, 10)
956 				// row 1
957 				.AddGroup(B_HORIZONTAL, 10)
958 					.Add(new TestView())
959 					.Add(new TestView())
960 					.Add(new TestView())
961 				.End()
962 
963 				// row 2
964 				.AddGroup(B_HORIZONTAL, 10)
965 					.Add(new TestView())
966 					.Add(heightForWidthView = new HeightForWidthTestView(kRed,
967 							FIXED_ASPECT_RATIO, 0.5f))
968 					.Add(new TestView())
969 				.End()
970 
971 				// row 3
972 				.AddGroup(B_HORIZONTAL, 10)
973 					.Add(new TestView())
974 					.Add(new TestView())
975 					.Add(new TestView())
976 				.End()
977 			.End()
978 		;
979 
980 		aspectRatioButton->SetValue(1);
981 	}
982 
983 	virtual void RegisterListeners()
984 	{
985 		aspectRatioButton->SetTarget(this);
986 		sumButton->SetTarget(this);
987 		productButton->SetTarget(this);
988 	}
989 
990 	virtual void MessageReceived(BMessage* message)
991 	{
992 		switch (message->what) {
993 			case MSG_FIXED_ASPECT_RATIO:
994 			{
995 				heightForWidthView->SetType(FIXED_ASPECT_RATIO, 0.5f);
996 				break;
997 			}
998 
999 			case MSG_FIXED_SUM:
1000 			{
1001 				heightForWidthView->SetType(FIXED_SUM, 200);
1002 				break;
1003 			}
1004 
1005 			case MSG_FIXED_PRODUCT:
1006 			{
1007 				heightForWidthView->SetType(FIXED_PRODUCT, 40000);
1008 				break;
1009 			}
1010 
1011 			default:
1012 				BHandler::MessageReceived(message);
1013 				break;
1014 		}
1015 	}
1016 
1017 private:
1018 	BRadioButton*			aspectRatioButton;
1019 	BRadioButton*			sumButton;
1020 	BRadioButton*			productButton;
1021 	HeightForWidthTestView*	heightForWidthView;
1022 };
1023 
1024 
1025 // GroupLayoutHeightForWidthTestVertical1
1026 struct GroupLayoutHeightForWidthTestVertical1 : public Test {
1027 	GroupLayoutHeightForWidthTestVertical1()
1028 		: Test("Group, height for width, v",
1029 			"Vertical BGroupLayout with height for width view.")
1030 	{
1031 		BLayoutBuilder::Group<>(rootView, B_HORIZONTAL)
1032 			// controls
1033 			.AddGroup(B_VERTICAL, 10, 0)
1034 				.Add(aspectRatioButton = new BRadioButton("fixed aspect ratio",
1035 						new BMessage(MSG_FIXED_ASPECT_RATIO)))
1036 				.Add(sumButton = new BRadioButton("fixed sum",
1037 						new BMessage(MSG_FIXED_SUM)))
1038 				.Add(productButton = new BRadioButton("fixed product",
1039 						new BMessage(MSG_FIXED_PRODUCT)))
1040 				.AddGlue()
1041 			.End()
1042 
1043 			// test views
1044 			.AddGroup(B_HORIZONTAL, 10)
1045 				// column 1
1046 				.AddGroup(B_VERTICAL, 10)
1047 					.Add(new TestView())
1048 					.Add(new TestView())
1049 					.Add(new TestView())
1050 				.End()
1051 
1052 				// column 2
1053 				.AddGroup(B_VERTICAL, 10)
1054 					.Add(new TestView())
1055 					.Add(heightForWidthView = new HeightForWidthTestView(kRed,
1056 							FIXED_ASPECT_RATIO, 0.5f))
1057 					.Add(new TestView())
1058 				.End()
1059 
1060 				// column 3
1061 				.AddGroup(B_VERTICAL, 10)
1062 					.Add(new TestView())
1063 					.Add(new TestView())
1064 					.Add(new TestView())
1065 				.End()
1066 			.End()
1067 		;
1068 
1069 		aspectRatioButton->SetValue(1);
1070 	}
1071 
1072 	virtual void RegisterListeners()
1073 	{
1074 		aspectRatioButton->SetTarget(this);
1075 		sumButton->SetTarget(this);
1076 		productButton->SetTarget(this);
1077 	}
1078 
1079 	virtual void MessageReceived(BMessage* message)
1080 	{
1081 		switch (message->what) {
1082 			case MSG_FIXED_ASPECT_RATIO:
1083 			{
1084 				heightForWidthView->SetType(FIXED_ASPECT_RATIO, 0.5f);
1085 				break;
1086 			}
1087 
1088 			case MSG_FIXED_SUM:
1089 			{
1090 				heightForWidthView->SetType(FIXED_SUM, 200);
1091 				break;
1092 			}
1093 
1094 			case MSG_FIXED_PRODUCT:
1095 			{
1096 				heightForWidthView->SetType(FIXED_PRODUCT, 40000);
1097 				break;
1098 			}
1099 
1100 			default:
1101 				BHandler::MessageReceived(message);
1102 				break;
1103 		}
1104 	}
1105 
1106 private:
1107 	BRadioButton*			aspectRatioButton;
1108 	BRadioButton*			sumButton;
1109 	BRadioButton*			productButton;
1110 	HeightForWidthTestView*	heightForWidthView;
1111 };
1112 
1113 
1114 // GridLayoutHeightForWidthTest1
1115 struct GridLayoutHeightForWidthTest1 : public Test {
1116 	GridLayoutHeightForWidthTest1()
1117 		: Test("Grid, height for width",
1118 			"BGridLayout with height for width view.")
1119 	{
1120 		BLayoutBuilder::Group<>(rootView, B_HORIZONTAL)
1121 			// controls
1122 			.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING, 0)
1123 				.Add(aspectRatioButton = new BRadioButton("fixed aspect ratio",
1124 						new BMessage(MSG_FIXED_ASPECT_RATIO)))
1125 				.Add(sumButton = new BRadioButton("fixed sum",
1126 						new BMessage(MSG_FIXED_SUM)))
1127 				.Add(productButton = new BRadioButton("fixed product",
1128 						new BMessage(MSG_FIXED_PRODUCT)))
1129 				.AddGlue()
1130 			.End()
1131 
1132 			// test views
1133 			.AddGrid()
1134 				// row 1
1135 				.Add(new TestView(), 0, 0, 3, 1)
1136 				.Add(new TestView(), 3, 0)
1137 				.Add(new TestView(), 4, 0)
1138 
1139 				// row 2
1140 				.Add(new TestView(), 0, 1)
1141 				.Add(new TestView(), 1, 1)
1142 				.Add(new TestView(), 2, 1)
1143 				.Add(new TestView(), 3, 1)
1144 				.Add(new TestView(), 4, 1)
1145 
1146 				// row 3
1147 				.Add(new TestView(), 0, 2)
1148 				.Add(heightForWidthView = new HeightForWidthTestView(kRed,
1149 						FIXED_ASPECT_RATIO, 0.5f), 1, 2, 2, 2)
1150 				.Add(new TestView(), 3, 2)
1151 				.Add(new TestView(), 4, 2)
1152 
1153 				// row 4
1154 				.Add(new TestView(), 0, 3)
1155 				.Add(new TestView(), 3, 3)
1156 				.Add(new TestView(), 4, 3)
1157 
1158 				// weights
1159 				.SetColumnWeight(0, 1)
1160 				.SetColumnWeight(1, 2)
1161 				.SetColumnWeight(2, 3)
1162 				.SetColumnWeight(3, 4)
1163 				.SetColumnWeight(4, 5)
1164 
1165 				.SetRowWeight(0, 1)
1166 				.SetRowWeight(1, 2)
1167 				.SetRowWeight(2, 3)
1168 				.SetRowWeight(3, 4);
1169 
1170 		aspectRatioButton->SetValue(1);
1171 	}
1172 
1173 	virtual void RegisterListeners()
1174 	{
1175 		aspectRatioButton->SetTarget(this);
1176 		sumButton->SetTarget(this);
1177 		productButton->SetTarget(this);
1178 	}
1179 
1180 	virtual void MessageReceived(BMessage* message)
1181 	{
1182 		switch (message->what) {
1183 			case MSG_FIXED_ASPECT_RATIO:
1184 			{
1185 				heightForWidthView->SetType(FIXED_ASPECT_RATIO, 0.5f);
1186 				break;
1187 			}
1188 
1189 			case MSG_FIXED_SUM:
1190 			{
1191 				heightForWidthView->SetType(FIXED_SUM, 200);
1192 				break;
1193 			}
1194 
1195 			case MSG_FIXED_PRODUCT:
1196 			{
1197 				heightForWidthView->SetType(FIXED_PRODUCT, 40000);
1198 				break;
1199 			}
1200 
1201 			default:
1202 				BHandler::MessageReceived(message);
1203 				break;
1204 		}
1205 	}
1206 
1207 private:
1208 	BRadioButton*			aspectRatioButton;
1209 	BRadioButton*			sumButton;
1210 	BRadioButton*			productButton;
1211 	HeightForWidthTestView*	heightForWidthView;
1212 };
1213 
1214 
1215 // SplitterGroupLayoutHeightForWidthTest1
1216 struct SplitterGroupLayoutHeightForWidthTest1 : public Test {
1217 	SplitterGroupLayoutHeightForWidthTest1()
1218 		: Test("Group, splitters, height for width",
1219 			"Horizontal BGroupLayout with height for width view and "
1220 				"BSplitters.")
1221 	{
1222 		BLayoutBuilder::Group<>(rootView, B_HORIZONTAL)
1223 			// controls
1224 			.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING, 0)
1225 				.Add(aspectRatioButton = new BRadioButton("fixed aspect ratio",
1226 						new BMessage(MSG_FIXED_ASPECT_RATIO)))
1227 				.Add(sumButton = new BRadioButton("fixed sum",
1228 						new BMessage(MSG_FIXED_SUM)))
1229 				.Add(productButton = new BRadioButton("fixed product",
1230 						new BMessage(MSG_FIXED_PRODUCT)))
1231 				.AddGlue()
1232 			.End()
1233 
1234 			// test views
1235 			.AddSplit(B_VERTICAL, B_USE_DEFAULT_SPACING, 1)
1236 				// row 1
1237 				.AddSplit(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1)
1238 					.Add(new TestView(), 1)
1239 					.Add(new TestView(), 2)
1240 					.Add(new TestView(), 3)
1241 					.End()
1242 				// make the row uncollapsible
1243 				.SetCollapsible(false)
1244 
1245 				// row 2
1246 				.AddSplit(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 2)
1247 					.Add(new TestView())
1248 					.Add(heightForWidthView = new HeightForWidthTestView(kRed,
1249 							FIXED_ASPECT_RATIO, 0.5f))
1250 					.Add(new TestView())
1251 					.End()
1252 
1253 				// row 3
1254 				.AddSplit(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 3)
1255 					.Add(new TestView(), 3)
1256 					.Add(new TestView(), 2)
1257 					.Add(new TestView(), 1)
1258 					.End()
1259 				// make the row uncollapsible
1260 				.SetCollapsible(false);
1261 
1262 		aspectRatioButton->SetValue(1);
1263 	}
1264 
1265 	virtual void RegisterListeners()
1266 	{
1267 		aspectRatioButton->SetTarget(this);
1268 		sumButton->SetTarget(this);
1269 		productButton->SetTarget(this);
1270 	}
1271 
1272 	virtual void MessageReceived(BMessage* message)
1273 	{
1274 		switch (message->what) {
1275 			case MSG_FIXED_ASPECT_RATIO:
1276 			{
1277 				heightForWidthView->SetType(FIXED_ASPECT_RATIO, 0.5f);
1278 				break;
1279 			}
1280 
1281 			case MSG_FIXED_SUM:
1282 			{
1283 				heightForWidthView->SetType(FIXED_SUM, 200);
1284 				break;
1285 			}
1286 
1287 			case MSG_FIXED_PRODUCT:
1288 			{
1289 				heightForWidthView->SetType(FIXED_PRODUCT, 40000);
1290 				break;
1291 			}
1292 
1293 			default:
1294 				BHandler::MessageReceived(message);
1295 				break;
1296 		}
1297 	}
1298 
1299 private:
1300 	BRadioButton*			aspectRatioButton;
1301 	BRadioButton*			sumButton;
1302 	BRadioButton*			productButton;
1303 	HeightForWidthTestView*	heightForWidthView;
1304 };
1305 
1306 
1307 // SplitterGridLayoutHeightForWidthTest1
1308 struct SplitterGridLayoutHeightForWidthTest1 : public Test {
1309 	SplitterGridLayoutHeightForWidthTest1()
1310 		: Test("Grid, splitters, height for width",
1311 			"BGridLayout with height for width view and horizontal BSplitters.")
1312 	{
1313 		BGridLayout* layouts[3];
1314 
1315 		BLayoutBuilder::Group<>(rootView, B_HORIZONTAL, B_USE_DEFAULT_SPACING)
1316 			// controls
1317 			.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING, 0)
1318 				.Add(aspectRatioButton = new BRadioButton("fixed aspect ratio",
1319 						new BMessage(MSG_FIXED_ASPECT_RATIO)))
1320 				.Add(sumButton = new BRadioButton("fixed sum",
1321 						new BMessage(MSG_FIXED_SUM)))
1322 				.Add(productButton = new BRadioButton("fixed product",
1323 						new BMessage(MSG_FIXED_PRODUCT)))
1324 				.AddGlue()
1325 			.End()
1326 
1327 			// test views
1328 			.AddSplit(B_HORIZONTAL)
1329 				// splitter element 1
1330 				.AddGrid(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, 6)
1331 					.GetLayout(&layouts[0])
1332 					// row 1
1333 					.Add(new TestView(), 0, 0, 3, 1)
1334 					// row 2
1335 					.Add(new TestView(), 0, 1)
1336 					.Add(new TestView(), 1, 1)
1337 					.Add(new TestView(), 2, 1)
1338 					// row 3
1339 					.Add(new TestView(), 0, 2)
1340 					.Add(heightForWidthView = new HeightForWidthTestView(kRed,
1341 							FIXED_ASPECT_RATIO, 0.5f), 1, 2, 2, 2)
1342 					// row 4
1343 					.Add(new TestView(), 0, 3)
1344 
1345 					// column weights
1346 					.SetColumnWeight(0, 1)
1347 					.SetColumnWeight(1, 2)
1348 					.SetColumnWeight(2, 3)
1349 					.End()
1350 
1351 				// splitter element 2
1352 				.AddGrid(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, 4)
1353 					.GetLayout(&layouts[1])
1354 					// row 1
1355 					.Add(new TestView(), 0, 0)
1356 					// row 2
1357 					.Add(new TestView(), 0, 1)
1358 					// row 3
1359 					.Add(new TestView(), 0, 2)
1360 					// row 4
1361 					.Add(new TestView(), 0, 3)
1362 					.End()
1363 
1364 				// splitter element 3
1365 				.AddGrid(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, 5)
1366 					.GetLayout(&layouts[2])
1367 					// row 1
1368 					.Add(new TestView(), 0, 0)
1369 					// row 2
1370 					.Add(new TestView(), 0, 1)
1371 					// row 3
1372 					.Add(new TestView(), 0, 2)
1373 					// row 4
1374 					.Add(new TestView(), 0, 3);
1375 
1376 		// set row weights
1377 		for (int i = 0; i < 3; i++) {
1378 			layouts[i]->SetRowWeight(0, 1);
1379 			layouts[i]->SetRowWeight(1, 2);
1380 			layouts[i]->SetRowWeight(2, 3);
1381 			layouts[i]->SetRowWeight(3, 4);
1382 		}
1383 
1384 		// align the layouts
1385 		layouts[0]->AlignLayoutWith(layouts[1], B_VERTICAL);
1386 		layouts[0]->AlignLayoutWith(layouts[2], B_VERTICAL);
1387 
1388 		aspectRatioButton->SetValue(1);
1389 	}
1390 
1391 	virtual void RegisterListeners()
1392 	{
1393 		aspectRatioButton->SetTarget(this);
1394 		sumButton->SetTarget(this);
1395 		productButton->SetTarget(this);
1396 	}
1397 
1398 	virtual void MessageReceived(BMessage* message)
1399 	{
1400 		switch (message->what) {
1401 			case MSG_FIXED_ASPECT_RATIO:
1402 			{
1403 				heightForWidthView->SetType(FIXED_ASPECT_RATIO, 0.5f);
1404 				break;
1405 			}
1406 
1407 			case MSG_FIXED_SUM:
1408 			{
1409 				heightForWidthView->SetType(FIXED_SUM, 200);
1410 				break;
1411 			}
1412 
1413 			case MSG_FIXED_PRODUCT:
1414 			{
1415 				heightForWidthView->SetType(FIXED_PRODUCT, 40000);
1416 				break;
1417 			}
1418 
1419 			default:
1420 				BHandler::MessageReceived(message);
1421 				break;
1422 		}
1423 	}
1424 
1425 private:
1426 	BRadioButton*			aspectRatioButton;
1427 	BRadioButton*			sumButton;
1428 	BRadioButton*			productButton;
1429 	HeightForWidthTestView*	heightForWidthView;
1430 };
1431 
1432 
1433 // LabelTest1
1434 struct LabelTest1 : public Test {
1435 	LabelTest1()
1436 		: Test("BTextControl, BMenuField, grid",
1437 			"Aligning BTextControl/BMenuField labels using a 2 column "
1438 			"BGridLayout.")
1439 	{
1440 		textControl1 = new BTextControl("Label", NULL, NULL);
1441 		textControl2 = new BTextControl("Long Label", NULL, NULL);
1442 		textControl3 = new BTextControl("Very Long Label", NULL, NULL);
1443 
1444 		menuField1 = new BMenuField("Label", new BMenu("Options"));
1445 		menuField2 = new BMenuField("Long Label",
1446 			new BMenu("More Options"));
1447 		menuField3 = new BMenuField("Very Long Label",
1448 			new BMenu("Obscure Options"));
1449 
1450 		BLayoutBuilder::Group<>(rootView, B_VERTICAL)
1451 			// controls
1452 			.AddGroup(B_HORIZONTAL)
1453 				.Add(changeLabelsButton = new BButton("Random Labels",
1454 						new BMessage(MSG_TOGGLE_1)))
1455 				.AddGlue()
1456 				.End()
1457 
1458 			.AddGlue()
1459 
1460 			// test views
1461 			.AddGrid()
1462 				// padding
1463 				.Add(BSpaceLayoutItem::CreateGlue(), 0, 0)
1464 				.Add(BSpaceLayoutItem::CreateGlue(), 1, 0)
1465 
1466 				// row 1
1467 				.Add(textControl1->CreateLabelLayoutItem(), 0, 1)
1468 				.Add(textControl1->CreateTextViewLayoutItem(), 1, 1)
1469 
1470 				// row 2
1471 				.Add(textControl2->CreateLabelLayoutItem(), 0, 2)
1472 				.Add(textControl2->CreateTextViewLayoutItem(), 1, 2)
1473 
1474 				// row 3
1475 				.Add(textControl3->CreateLabelLayoutItem(), 0, 3)
1476 				.Add(textControl3->CreateTextViewLayoutItem(), 1, 3)
1477 
1478 				// row 4
1479 				.Add(menuField1->CreateLabelLayoutItem(), 0, 4)
1480 				.Add(menuField1->CreateMenuBarLayoutItem(), 1, 4)
1481 
1482 				// row 5
1483 				.Add(menuField2->CreateLabelLayoutItem(), 0, 5)
1484 				.Add(menuField2->CreateMenuBarLayoutItem(), 1, 5)
1485 
1486 				// row 6
1487 				.Add(menuField3->CreateLabelLayoutItem(), 0, 6)
1488 				.Add(menuField3->CreateMenuBarLayoutItem(), 1, 6)
1489 
1490 				// padding
1491 				.Add(BSpaceLayoutItem::CreateGlue(), 0, 7)
1492 				.Add(BSpaceLayoutItem::CreateGlue(), 1, 7)
1493 				.End()
1494 			.AddGlue();
1495 	}
1496 
1497 	virtual void RegisterListeners()
1498 	{
1499 		changeLabelsButton->SetTarget(this);
1500 	}
1501 
1502 	virtual void MessageReceived(BMessage* message)
1503 	{
1504 		switch (message->what) {
1505 			case MSG_TOGGLE_1:
1506 			{
1507 				BTextControl* textControls[] = {
1508 					textControl1, textControl2, textControl3
1509 				};
1510 
1511 				BMenuField* menuFields[] = {
1512 					menuField1, menuField2, menuField3
1513 				};
1514 
1515 				for (int i = 0; i < 3; i++) {
1516 					BTextControl* textControl = textControls[i];
1517 					BMenuField* menuField = menuFields[i];
1518 
1519 					textControl->SetLabel(_RandomLabel().String());
1520 					menuField->SetLabel(_RandomLabel().String());
1521 				}
1522 			}
1523 
1524 			default:
1525 				BHandler::MessageReceived(message);
1526 				break;
1527 		}
1528 	}
1529 
1530 	BString _RandomLabel() const
1531 	{
1532 		const char* digits = "0123456789";
1533 
1534 		int length = rand() % 20;
1535 		BString label("Random ");
1536 		for (int k = 0; k < length; k++)
1537 			label.Append(digits[k % 10], 1);
1538 
1539 		return label;
1540 	}
1541 
1542 private:
1543 	BButton*		changeLabelsButton;
1544 	BTextControl*	textControl1;
1545 	BTextControl*	textControl2;
1546 	BTextControl*	textControl3;
1547 	BMenuField*		menuField1;
1548 	BMenuField*		menuField2;
1549 	BMenuField*		menuField3;
1550 };
1551 
1552 
1553 // TestWindow
1554 class TestWindow : public BWindow {
1555 public:
1556 	TestWindow()
1557 		: BWindow(BRect(100, 100, 700, 500), "LayoutTest1",
1558 			B_TITLED_WINDOW,
1559 			B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE
1560 				| B_AUTO_UPDATE_SIZE_LIMITS)
1561 	{
1562 		fTestList = new BListView(BRect(0, 0, 10, 10), "test list",
1563 			B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL);
1564 		BView* scrollView = new BScrollView("test scroll view", fTestList);
1565 		scrollView->SetExplicitMaxSize(BSize(190, B_SIZE_UNLIMITED));
1566 
1567 		fTestCardLayout = new BCardLayout();
1568 		BView* cardView = new BView("card view", 0, fTestCardLayout);
1569 
1570 		BLayoutBuilder::Group<>(this, B_HORIZONTAL)
1571 			.SetInsets(B_USE_WINDOW_INSETS)
1572 			.Add(scrollView)
1573 			.Add(cardView);
1574 
1575 		// add the tests
1576 		_AddTest(new GroupLayoutTest1());
1577 		_AddTest(new GroupAlignedLayoutTest1());
1578 		_AddTest(new GridLayoutTest1());
1579 		_AddTest(new SplitterGroupLayoutTest1());
1580 		_AddTest(new SplitterGroupLayoutTest2());
1581 		_AddTest(new SplitterGridLayoutTest1());
1582 		_AddTest(new SplitterGridLayoutTest2());
1583 		_AddTest(new GroupLayoutHeightForWidthTestHorizontal1());
1584 		_AddTest(new GroupLayoutHeightForWidthTestVertical1());
1585 		_AddTest(new GridLayoutHeightForWidthTest1());
1586 		_AddTest(new SplitterGroupLayoutHeightForWidthTest1());
1587 		_AddTest(new SplitterGridLayoutHeightForWidthTest1());
1588 		_AddTest(new LabelTest1());
1589 
1590 		fTestList->SetSelectionMessage(new BMessage(MSG_TEST_SELECTED));
1591 		_DumpViewHierarchy(GetLayout()->Owner());
1592 	}
1593 
1594 	virtual void MessageReceived(BMessage* message)
1595 	{
1596 		switch (message->what) {
1597 			case MSG_TEST_SELECTED:
1598 				fTestCardLayout->SetVisibleItem(fTestList->CurrentSelection());
1599 				break;
1600 			default:
1601 				BWindow::MessageReceived(message);
1602 				break;
1603 		}
1604 	}
1605 
1606 private:
1607 	void _AddTest(Test* test) {
1608 		fTestList->AddItem(new BStringItem(test->name.String()));
1609 
1610 		BGroupView* containerView = new BGroupView(B_VERTICAL, 0);
1611 
1612 		BStringView* descriptionView = new BStringView("test description",
1613 			test->description.String());
1614 
1615 		descriptionView->SetExplicitMinSize(BSize(0, B_SIZE_UNSET));
1616 		containerView->AddChild(descriptionView);
1617 
1618 		// spacing/glue
1619 		containerView->GroupLayout()->AddItem(
1620 			BSpaceLayoutItem::CreateVerticalStrut(10));
1621 		containerView->GroupLayout()->AddItem(
1622 			BSpaceLayoutItem::CreateGlue(), 0);
1623 
1624 		// the test view: wrap it, so we can have unlimited size
1625 		BGroupView* wrapperView = new BGroupView(B_HORIZONTAL, 0);
1626 		containerView->AddChild(wrapperView);
1627 		wrapperView->AddChild(test->rootView);
1628 
1629 		// glue
1630 		containerView->GroupLayout()->AddItem(
1631 			BSpaceLayoutItem::CreateGlue(), 0);
1632 
1633 		wrapperView->SetExplicitMaxSize(
1634 			BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
1635 		containerView->SetExplicitMaxSize(
1636 			BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
1637 
1638 		fTestCardLayout->AddView(containerView);
1639 
1640 		AddHandler(test);
1641 		test->RegisterListeners();
1642 	}
1643 
1644 	void _DumpViewHierarchy(BView* view, int32 indent = 0)
1645 	{
1646 		for (int32 i = 0; i < indent; i++)
1647 			printf("  ");
1648 		printf("view: %p", view);
1649 		for (int32 i = 0; i < 15 - indent; i++)
1650 			printf("  ");
1651 		printf("(%s)\n", typeid(*view).name());
1652 
1653 		int32 count = view->CountChildren();
1654 		for (int32 i = 0; i < count; i++)
1655 			_DumpViewHierarchy(view->ChildAt(i), indent + 1);
1656 	}
1657 
1658 private:
1659 	BListView*		fTestList;
1660 	BCardLayout*	fTestCardLayout;
1661 };
1662 
1663 
1664 int
1665 main()
1666 {
1667 	BApplication app("application/x-vnd.haiku.layout-test1");
1668 
1669 	BWindow* window = new TestWindow;
1670 	window->Show();
1671 
1672 	app.Run();
1673 
1674 	return 0;
1675 }
1676