1/*
2 * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8
9#include <Application.h>
10#include <Window.h>
11
12#include "BoxTest.h"
13#include "ButtonTest.h"
14#include "CheckBox.h"
15#include "CheckBoxTest.h"
16#include "GroupView.h"
17#include "ListViewTest.h"
18#include "MenuBarTest.h"
19#include "MenuFieldTest.h"
20#include "MenuTest.h"
21#include "RadioButtonTest.h"
22#include "ScrollBarTest.h"
23#include "SliderTest.h"
24#include "StringView.h"
25#include "Test.h"
26#include "TextControlTest.h"
27#include "TextViewTest.h"
28#include "TwoDimensionalSliderView.h"
29#include "View.h"
30#include "ViewContainer.h"
31#include "WrapperView.h"
32
33
34// internal messages
35enum {
36	MSG_2D_SLIDER_VALUE_CHANGED		= '2dsv',
37	MSG_UNLIMITED_MAX_SIZE_CHANGED	= 'usch',
38};
39
40
41struct test_info {
42	const char*	name;
43	Test*		(*create)();
44};
45
46const test_info kTestInfos[] = {
47	{ "BBox",			BoxTest::CreateTest },
48	{ "BButton",		ButtonTest::CreateTest },
49	{ "BCheckBox",		CheckBoxTest::CreateTest },
50	{ "BListView",		ListViewTest::CreateTest },
51	{ "BMenu",			MenuTest::CreateTest },
52	{ "BMenuBar",		MenuBarTest::CreateTest },
53	{ "BMenuField",		MenuFieldTest::CreateTest },
54	{ "BRadioButton",	RadioButtonTest::CreateTest },
55	{ "BScrollBar",		ScrollBarTest::CreateTest },
56	{ "BSlider",		SliderTest::CreateTest },
57	{ "BTextControl",	TextControlTest::CreateTest },
58	{ "BTextView",		TextViewTest::CreateTest },
59	{ NULL, NULL }
60};
61
62
63// helpful operator
64BPoint
65operator+(const BPoint& p, const BSize& size)
66{
67	return BPoint(p.x + size.width, p.y + size.height);
68}
69
70
71// TestWindow
72class TestWindow : public BWindow {
73public:
74	TestWindow(Test* test)
75		: BWindow(BRect(50, 50, 750, 550), "Widget Layout",
76			B_TITLED_WINDOW,
77			B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE | B_NOT_RESIZABLE
78			| B_NOT_ZOOMABLE),
79		  fTest(test)
80	{
81		fViewContainer = new ViewContainer(Bounds());
82		fViewContainer->View::SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
83		AddChild(fViewContainer);
84
85		// container view for the tested BView
86		BRect rect(10, 10, 400, 400);
87		View* view = new View(rect);
88		fViewContainer->View::AddChild(view);
89		view->SetViewColor((rgb_color){200, 200, 240, 255});
90
91		// container for the test's controls
92		fTestControlsView = new View(BRect(410, 10, 690, 400));
93		fTestControlsView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
94		fViewContainer->View::AddChild(fTestControlsView);
95
96		// wrapper view
97		fWrapperView = new WrapperView(fTest->GetView());
98		fWrapperView->SetLocation(BPoint(10, 10));
99		view->AddChild(fWrapperView);
100		fWrapperView->SetSize(fWrapperView->PreferredSize());
101
102		// slider view
103		fSliderView = new TwoDimensionalSliderView(
104			new BMessage(MSG_2D_SLIDER_VALUE_CHANGED), this);
105		fSliderView->SetLocationRange(BPoint(0, 0), BPoint(0, 0));
106		view->AddChild(fSliderView);
107
108		_UpdateSliderConstraints();
109
110		// size views
111		GroupView* sizeViewsGroup = new GroupView(B_VERTICAL, 6);
112		sizeViewsGroup->SetSpacing(0, 8);
113		fViewContainer->View::AddChild(sizeViewsGroup);
114
115		// min
116		_CreateSizeViews(sizeViewsGroup, "min:  ", fMinWidthView,
117			fMinHeightView);
118
119		// max (with checkbox)
120		fUnlimitedMaxSizeCheckBox = new LabeledCheckBox("override",
121			new BMessage(MSG_UNLIMITED_MAX_SIZE_CHANGED), this);
122
123		_CreateSizeViews(sizeViewsGroup, "max:  ", fMaxWidthView,
124			fMaxHeightView, fUnlimitedMaxSizeCheckBox);
125
126		// preferred
127		_CreateSizeViews(sizeViewsGroup, "preferred:  ", fPreferredWidthView,
128			fPreferredHeightView);
129
130		// current
131		_CreateSizeViews(sizeViewsGroup, "current:  ", fCurrentWidthView,
132			fCurrentHeightView);
133
134		sizeViewsGroup->SetFrame(BRect(BPoint(rect.left, rect.bottom + 10),
135			sizeViewsGroup->PreferredSize()));
136
137		_UpdateSizeViews();
138
139		// activate test
140		AddHandler(fTest);
141		fTest->ActivateTest(fTestControlsView);
142	}
143
144	virtual void DispatchMessage(BMessage* message, BHandler* handler)
145	{
146		switch (message->what) {
147			case B_LAYOUT_WINDOW:
148				if (!fWrapperView->GetView()->IsLayoutValid()) {
149					_UpdateSliderConstraints();
150					_UpdateSizeViews();
151				}
152				break;
153		}
154
155		BWindow::DispatchMessage(message, handler);
156	}
157
158	virtual void MessageReceived(BMessage* message)
159	{
160		switch (message->what) {
161			case MSG_2D_SLIDER_VALUE_CHANGED:
162			{
163				BPoint sliderLocation(fSliderView->Location());
164				BPoint wrapperLocation(fWrapperView->Location());
165				BSize size(sliderLocation.x - wrapperLocation.x - 1,
166					sliderLocation.y - wrapperLocation.y - 1);
167				fWrapperView->SetSize(size);
168				_UpdateSizeViews();
169				break;
170			}
171
172			case MSG_UNLIMITED_MAX_SIZE_CHANGED:
173				if (fUnlimitedMaxSizeCheckBox->IsSelected())  {
174					fWrapperView->GetView()->SetExplicitMaxSize(
175						BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
176				} else {
177					fWrapperView->GetView()->SetExplicitMaxSize(
178						BSize(B_SIZE_UNSET, B_SIZE_UNSET));
179				}
180				break;
181
182			default:
183				BWindow::MessageReceived(message);
184				break;
185		}
186	}
187
188private:
189	void _UpdateSliderConstraints()
190	{
191		BPoint wrapperLocation(fWrapperView->Location());
192		BSize minWrapperSize(fWrapperView->MinSize());
193		BSize maxWrapperSize(fWrapperView->MaxSize());
194
195		BPoint minSliderLocation = wrapperLocation + minWrapperSize
196			+ BPoint(1, 1);
197		BPoint maxSliderLocation = wrapperLocation + maxWrapperSize
198			+ BPoint(1, 1);
199
200		BSize sliderSize(fSliderView->Size());
201		BSize parentSize(fSliderView->Parent()->Size());
202		if (maxSliderLocation.x + sliderSize.width > parentSize.width)
203			maxSliderLocation.x = parentSize.width - sliderSize.width;
204		if (maxSliderLocation.y + sliderSize.height > parentSize.height)
205			maxSliderLocation.y = parentSize.height - sliderSize.height;
206
207		fSliderView->SetLocationRange(minSliderLocation, maxSliderLocation);
208	}
209
210	void _CreateSizeViews(View* group, const char* labelText,
211		StringView*& widthView, StringView*& heightView,
212		View* additionalView = NULL)
213	{
214		// label
215		StringView* label = new StringView(labelText);
216		label->SetAlignment(B_ALIGN_RIGHT);
217		group->AddChild(label);
218
219		// width view
220		widthView = new StringView("9999999999.9");
221		widthView->SetAlignment(B_ALIGN_RIGHT);
222		group->AddChild(widthView);
223		widthView->SetExplicitMinSize(widthView->PreferredSize());
224
225		// "," label
226		StringView* labelView = new StringView(",  ");
227		group->AddChild(labelView);
228
229		// height view
230		heightView = new StringView("9999999999.9");
231		heightView->SetAlignment(B_ALIGN_RIGHT);
232		group->AddChild(heightView);
233		heightView->SetExplicitMinSize(heightView->PreferredSize());
234
235		// spacing
236		group->AddChild(new HStrut(20));
237
238		// glue or unlimited max size check box
239		if (additionalView)
240			group->AddChild(additionalView);
241		else
242			group->AddChild(new Glue());
243	}
244
245	void _UpdateSizeView(StringView* view, float size)
246	{
247		char buffer[32];
248		if (size < B_SIZE_UNLIMITED) {
249			sprintf(buffer, "%.1f", size);
250			view->SetString(buffer);
251		} else
252			view->SetString("unlimited");
253	}
254
255	void _UpdateSizeViews(StringView* widthView, StringView* heightView,
256		BSize size)
257	{
258		_UpdateSizeView(widthView, size.width);
259		_UpdateSizeView(heightView, size.height);
260	}
261
262	void _UpdateSizeViews()
263	{
264		_UpdateSizeViews(fMinWidthView, fMinHeightView,
265			fWrapperView->GetView()->MinSize());
266		_UpdateSizeViews(fMaxWidthView, fMaxHeightView,
267			fWrapperView->GetView()->MaxSize());
268		_UpdateSizeViews(fPreferredWidthView, fPreferredHeightView,
269			fWrapperView->GetView()->PreferredSize());
270		_UpdateSizeViews(fCurrentWidthView, fCurrentHeightView,
271			fWrapperView->GetView()->Frame().Size());
272	}
273
274private:
275	Test*						fTest;
276	ViewContainer*				fViewContainer;
277	View*						fTestControlsView;
278	WrapperView*				fWrapperView;
279	TwoDimensionalSliderView*	fSliderView;
280	StringView*					fMinWidthView;
281	StringView*					fMinHeightView;
282	StringView*					fMaxWidthView;
283	StringView*					fMaxHeightView;
284	StringView*					fPreferredWidthView;
285	StringView*					fPreferredHeightView;
286	StringView*					fCurrentWidthView;
287	StringView*					fCurrentHeightView;
288	LabeledCheckBox*			fUnlimitedMaxSizeCheckBox;
289};
290
291
292static void
293print_test_list(bool error)
294{
295	FILE* out = (error ? stderr : stdout);
296
297	fprintf(out, "available tests:\n");
298
299	for (int32 i = 0; kTestInfos[i].name; i++)
300		fprintf(out, "  %s\n", kTestInfos[i].name);
301}
302
303
304int
305main(int argc, const char* const* argv)
306{
307	// get test name
308	const char* testName;
309	if (argc < 2) {
310		fprintf(stderr, "Usage: %s <test name>\n", argv[0]);
311		print_test_list(true);
312		exit(1);
313	}
314	testName = argv[1];
315
316	// create app
317	BApplication app("application/x-vnd.haiku.widget-layout-test");
318
319	// find and create the test
320	Test* test = NULL;
321	for (int32 i = 0; kTestInfos[i].name; i++) {
322		if (strcmp(testName, kTestInfos[i].name) == 0) {
323			test = (kTestInfos[i].create)();
324			break;
325		}
326	}
327
328	if (!test) {
329		fprintf(stderr, "Error: Invalid test name: \"%s\"\n", testName);
330		print_test_list(true);
331		exit(1);
332	}
333
334	// show test window
335	BWindow* window = new TestWindow(test);
336	window->Show();
337
338	app.Run();
339
340	return 0;
341}
342