xref: /haiku/src/tests/servers/app/transformation/main.cpp (revision 5e96d7d537fbec23bad4ae9b4c8e7b02e769f0c6)
1 /*
2  * Copyright 2014 Stephan Aßmus <superstippi@gmx.de>
3  * All rights reserved. Distributed under the terms of the MIT license.
4  */
5 
6 
7 #include <algorithm>
8 #include <stdio.h>
9 #include <string.h>
10 
11 #include <Application.h>
12 #include <Bitmap.h>
13 #include <GradientLinear.h>
14 #include <Message.h>
15 #include <Picture.h>
16 #include <LayoutBuilder.h>
17 #include <List.h>
18 #include <PopUpMenu.h>
19 #include <Resources.h>
20 #include <Roster.h>
21 #include <ScrollView.h>
22 #include <String.h>
23 #include <StringView.h>
24 #include <View.h>
25 #include <Window.h>
26 
27 
28 static const char* kAppSignature = "application/x.vnd-Haiku.Transformation";
29 
30 
31 class Test {
32 public:
33 								Test(const char* name);
34 	virtual						~Test();
35 
36 			const char*			Name() const
37 									{ return fName.String(); }
38 
39 	virtual	void				Draw(BView* view, BRect updateRect) = 0;
40 
41 private:
42 			BString				fName;
43 };
44 
45 
46 Test::Test(const char* name)
47 	:
48 	fName(name)
49 {
50 }
51 
52 
53 Test::~Test()
54 {
55 }
56 
57 
58 // #pragma mark - TestView
59 
60 
61 class TestView : public BView {
62 public:
63 								TestView();
64 	virtual						~TestView();
65 
66 	virtual	void				Draw(BRect updateRect);
67 
68 			void				SetTest(Test* test);
69 
70 private:
71 			Test*				fTest;
72 };
73 
74 
75 TestView::TestView()
76 	:
77 	BView(NULL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
78 	fTest(NULL)
79 {
80 }
81 
82 
83 TestView::~TestView()
84 {
85 }
86 
87 
88 void
89 TestView::Draw(BRect updateRect)
90 {
91 	if (fTest != NULL)
92 		fTest->Draw(this, updateRect);
93 }
94 
95 
96 void
97 TestView::SetTest(Test* test)
98 {
99 	fTest = test;
100 	Invalidate();
101 }
102 
103 
104 // #pragma mark - TestWindow
105 
106 
107 enum {
108 	MSG_SELECT_TEST	= 'stst'
109 };
110 
111 
112 class TestWindow : public BWindow {
113 public:
114 								TestWindow();
115 	virtual						~TestWindow();
116 
117 	virtual	void				MessageReceived(BMessage* message);
118 
119 			void				AddTest(Test* test);
120 			void				SetToTest(int32 index);
121 
122 private:
123 			TestView*			fTestView;
124 
125 			BMenuField*			fTestSelectionField;
126 
127 			BList				fTests;
128 };
129 
130 
131 TestWindow::TestWindow()
132 	:
133 	BWindow(BRect(50.0, 50.0, 450.0, 250.0), "Transformations Test",
134 		B_DOCUMENT_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE
135 			| B_AUTO_UPDATE_SIZE_LIMITS)
136 {
137 	fTestView = new TestView();
138 
139 	BScrollView* scrollView = new BScrollView("scroll", fTestView, 0, true,
140 		true);
141 
142 	fTestSelectionField = new BMenuField("test selection",
143 		"Select test:", new BPopUpMenu("select"));
144 
145 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f)
146 		.AddGroup(B_HORIZONTAL)
147 			.Add(fTestSelectionField)
148 			.AddGlue()
149 			.SetInsets(B_USE_DEFAULT_SPACING)
150 		.End()
151 		.Add(scrollView)
152 	;
153 }
154 
155 
156 TestWindow::~TestWindow()
157 {
158 	for (int32 i = fTests.CountItems() - 1; i >= 0; i++)
159 		delete (Test*)fTests.ItemAt(i);
160 }
161 
162 
163 void
164 TestWindow::MessageReceived(BMessage* message)
165 {
166 	switch (message->what) {
167 		case MSG_SELECT_TEST:
168 		{
169 			int32 index;
170 			if (message->FindInt32("index", &index) == B_OK)
171 				SetToTest(index);
172 			break;
173 		}
174 
175 		default:
176 			BWindow::MessageReceived(message);
177 	}
178 }
179 
180 
181 void
182 TestWindow::AddTest(Test* test)
183 {
184 	if (test == NULL || fTests.HasItem(test))
185 		return;
186 
187 	if (!fTests.AddItem(test)) {
188 		delete test;
189 		return;
190 	}
191 
192 	BMessage* message = new BMessage(MSG_SELECT_TEST);
193 	message->AddInt32("index", fTests.CountItems() - 1);
194 
195 	BMenuItem* item = new BMenuItem(test->Name(), message);
196 	if (!fTestSelectionField->Menu()->AddItem(item)) {
197 		fTests.RemoveItem(fTests.CountItems() - 1);
198 		delete test;
199 		delete item;
200 		return;
201 	}
202 
203 	if (fTests.CountItems() == 1)
204 		SetToTest(0);
205 }
206 
207 
208 void
209 TestWindow::SetToTest(int32 index)
210 {
211 	Test* test = (Test*)fTests.ItemAt(index);
212 	if (test == NULL)
213 		return;
214 
215 	fTestSelectionField->Menu()->ItemAt(index)->SetMarked(true);
216 
217 	fTestView->SetTest(test);
218 }
219 
220 
221 // #pragma mark - Test1
222 
223 
224 class RectsTest : public Test {
225 public:
226 	RectsTest()
227 		:
228 		Test("Rects")
229 	{
230 	}
231 
232 	virtual void Draw(BView* view, BRect updateRect)
233 	{
234 		view->DrawString("Rects", BPoint(20, 30));
235 
236 		view->SetDrawingMode(B_OP_ALPHA);
237 		view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
238 
239 		BRect rect(view->Bounds());
240 		rect.InsetBy(rect.Width() / 3, rect.Height() / 3);
241 		BPoint center(
242 			rect.left + rect.Width() / 2,
243 			rect.top + rect.Height() / 2);
244 
245 		for (int32 i = 0; i < 360; i += 40) {
246 			BAffineTransform transform;
247 			transform.RotateBy(center, i * M_PI / 180.0);
248 			view->SetTransform(transform);
249 
250 			view->SetHighColor(51, 151, 255, 20);
251 			view->FillRect(rect);
252 
253 			view->SetHighColor(51, 255, 151, 180);
254 			view->DrawString("Rect", center);
255 		}
256 	}
257 };
258 
259 
260 // #pragma mark - BitmapTest
261 
262 
263 class BitmapTest : public Test {
264 public:
265 	BitmapTest()
266 		:
267 		Test("Bitmap"),
268 		fBitmap(_LoadBitmap(555))
269 	{
270 	}
271 
272 	virtual void Draw(BView* view, BRect updateRect)
273 	{
274 		BRect rect(view->Bounds());
275 
276 		if (fBitmap == NULL) {
277 			view->SetHighColor(255, 0, 0);
278 			view->FillRect(rect);
279 			view->SetHighColor(0, 0, 0);
280 			view->DrawString("Failed to load the bitmap.", BPoint(20, 20));
281 			return;
282 		}
283 
284 		rect.left = (rect.Width() - fBitmap->Bounds().Width()) / 2;
285 		rect.top = (rect.Height() - fBitmap->Bounds().Height()) / 2;
286 		rect.right = rect.left + fBitmap->Bounds().Width();
287 		rect.bottom = rect.top + fBitmap->Bounds().Height();
288 
289 		BPoint center(
290 			rect.left + rect.Width() / 2,
291 			rect.top + rect.Height() / 2);
292 
293 		BPicture picture;
294 		view->BeginPicture(&picture);
295 		view->SetDrawingMode(B_OP_ALPHA);
296 		view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
297 		BFont font;
298 		view->GetFont(&font);
299 		font.SetSize(70);
300 		view->SetFont(&font);
301 		view->SetHighColor(0, 0, 0, 80);
302 		view->FillRect(view->Bounds());
303 		view->SetHighColor(0, 0, 0, 255);
304 		view->DrawString("CLIPPING", BPoint(0, center.y + 35));
305 		view->EndPicture();
306 
307 		view->ClipToPicture(&picture);
308 
309 		BAffineTransform transform;
310 			transform.RotateBy(center, 30 * M_PI / 180.0);
311 			view->SetTransform(transform);
312 
313 		view->DrawBitmap(fBitmap, fBitmap->Bounds(), rect);
314 	}
315 
316 private:
317 	status_t
318 	_GetAppResources(BResources& resources) const
319 	{
320 		app_info info;
321 		status_t status = be_app->GetAppInfo(&info);
322 		if (status != B_OK)
323 			return status;
324 
325 		return resources.SetTo(&info.ref);
326 	}
327 
328 
329 	BBitmap* _LoadBitmap(int resourceID) const
330 	{
331 		BResources resources;
332 		status_t status = _GetAppResources(resources);
333 		if (status != B_OK)
334 			return NULL;
335 
336 		size_t dataSize;
337 		const void* data = resources.LoadResource(B_MESSAGE_TYPE, resourceID,
338 			&dataSize);
339 		if (data == NULL)
340 			return NULL;
341 
342 		BMemoryIO stream(data, dataSize);
343 
344 		// Try to read as an archived bitmap.
345 		BMessage archive;
346 		status = archive.Unflatten(&stream);
347 		if (status != B_OK)
348 			return NULL;
349 
350 		BBitmap* bitmap = new BBitmap(&archive);
351 
352 		status = bitmap->InitCheck();
353 		if (status != B_OK) {
354 			delete bitmap;
355 			bitmap = NULL;
356 		}
357 
358 		return bitmap;
359 	}
360 
361 private:
362 	BBitmap*	fBitmap;
363 };
364 
365 
366 // #pragma mark - Gradient
367 
368 
369 class GradientTest : public Test {
370 public:
371 	GradientTest()
372 		:
373 		Test("Gradient")
374 	{
375 	}
376 
377 	virtual void Draw(BView* view, BRect updateRect)
378 	{
379 		BRect rect(view->Bounds());
380 		rect.InsetBy(rect.Width() / 3, rect.Height() / 3);
381 		BPoint center(
382 			rect.left + rect.Width() / 2,
383 			rect.top + rect.Height() / 2);
384 
385 		BAffineTransform transform;
386 		transform.RotateBy(center, 30.0 * M_PI / 180.0);
387 		view->SetTransform(transform);
388 
389 		rgb_color top = (rgb_color){ 255, 255, 0, 255 };
390 		rgb_color bottom = (rgb_color){ 0, 255, 255, 255 };
391 
392 		BGradientLinear gradient;
393 		gradient.AddColor(top, 0.0f);
394 		gradient.AddColor(bottom, 255.0f);
395 		gradient.SetStart(rect.LeftTop());
396 		gradient.SetEnd(rect.LeftBottom());
397 
398 		float radius = std::min(rect.Width() / 5, rect.Height() / 5);
399 
400 		view->FillRoundRect(rect, radius, radius, gradient);
401 	}
402 };
403 
404 
405 // #pragma mark - NestedStates
406 
407 
408 class NestedStatesTest : public Test {
409 public:
410 	NestedStatesTest()
411 		:
412 		Test("Nested view states")
413 	{
414 	}
415 
416 	virtual void Draw(BView* view, BRect updateRect)
417 	{
418 		BAffineTransform transform;
419 		transform.RotateBy(BPoint(100, 100), 30.0 * M_PI / 180.0);
420 		view->SetTransform(transform);
421 
422 		rgb_color top = (rgb_color){ 255, 0, 0, 255 };
423 		rgb_color bottom = (rgb_color){ 255, 255, 0, 255 };
424 
425 		BRect rect(20, 20, 120, 120);
426 
427 		BGradientLinear gradient;
428 		gradient.AddColor(top, 0.0f);
429 		gradient.AddColor(bottom, 255.0f);
430 		gradient.SetStart(rect.LeftTop());
431 		gradient.SetEnd(rect.LeftBottom());
432 
433 		view->FillRoundRect(rect, 20, 20, gradient);
434 
435 		view->PushState();
436 		// Should be in the same place!
437 		view->StrokeRoundRect(rect, 20, 20);
438 
439 		// Now rotated by another 30 degree
440 		view->SetTransform(transform);
441 
442 		view->SetDrawingMode(B_OP_ALPHA);
443 		view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
444 		view->SetHighColor(0, 0, 255, 120);
445 		view->FillRoundRect(rect, 20, 20);
446 
447 		view->PopState();
448 	}
449 };
450 
451 
452 // #pragma mark -
453 
454 
455 int
456 main(int argc, char** argv)
457 {
458 	BApplication app(kAppSignature);
459 
460 	TestWindow* window = new TestWindow();
461 
462 	window->AddTest(new RectsTest());
463 	window->AddTest(new BitmapTest());
464 	window->AddTest(new GradientTest());
465 	window->AddTest(new NestedStatesTest());
466 
467 	window->SetToTest(3);
468 	window->Show();
469 
470 	app.Run();
471 	return 0;
472 }
473