1/*
2 * Copyright 2005-2009, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Axel D��rfler, axeld@pinc-software.de
7 */
8
9
10#include <Alert.h>
11#include <Application.h>
12#include <Button.h>
13#include <MenuField.h>
14#include <MenuItem.h>
15#include <PopUpMenu.h>
16#include <String.h>
17#include <Window.h>
18
19#include <WindowPrivate.h>
20
21#include <stdio.h>
22#include <string.h>
23
24
25const uint32 kMsgUpdateLook = 'uplk';
26const uint32 kMsgUpdateFeel = 'upfe';
27const uint32 kMsgUpdateFlags = 'upfl';
28
29const uint32 kMsgAddWindow = 'adwn';
30const uint32 kMsgAddSubsetWindow = 'adsw';
31
32
33int32 gNormalWindowCount = 0;
34
35
36class Window : public BWindow {
37	public:
38		Window(BRect frame, window_look look, window_feel feel);
39		virtual ~Window();
40
41		virtual void MessageReceived(BMessage* message);
42		virtual bool QuitRequested();
43
44	private:
45		BMessage* AddWindowMessage(window_look look, window_feel feel);
46		BString TitleForFeel(window_feel feel);
47		void _UpdateFlagsMenuLabel();
48
49		BMenuField*	fFlagsField;
50};
51
52
53Window::Window(BRect frame, window_look look, window_feel feel)
54	: BWindow(frame, TitleForFeel(feel).String(), look, feel,
55			B_ASYNCHRONOUS_CONTROLS)
56{
57	BRect rect(Bounds());
58	BView *view = new BView(rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW);
59	view->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
60	AddChild(view);
61
62	if (!IsModal() && !IsFloating())
63		gNormalWindowCount++;
64
65	float labelWidth = view->StringWidth("Flags:") + 5.f;
66
67	BPopUpMenu* menu = new BPopUpMenu("looks");
68	const struct { const char* name; int32 look; } looks[] = {
69		{"Titled", B_TITLED_WINDOW_LOOK}, {"Document", B_DOCUMENT_WINDOW_LOOK},
70		{"Floating", B_FLOATING_WINDOW_LOOK}, {"Modal", B_MODAL_WINDOW_LOOK},
71		{"Bordered", B_BORDERED_WINDOW_LOOK}, {"No Border", B_NO_BORDER_WINDOW_LOOK},
72		{"Left Titled", kLeftTitledWindowLook}, {"Desktop", kDesktopWindowLook}
73	};
74	for (uint32 i = 0; i < sizeof(looks) / sizeof(looks[0]); i++) {
75		BMessage* message = new BMessage(kMsgUpdateLook);
76		message->AddInt32("look", looks[i].look);
77		BMenuItem* item = new BMenuItem(looks[i].name, message);
78		if (looks[i].look == (int32)Look())
79			item->SetMarked(true);
80
81		menu->AddItem(item);
82	}
83
84	rect.InsetBy(10, 10);
85	BMenuField* menuField = new BMenuField(rect, "look", "Look:", menu);
86	menuField->ResizeToPreferred();
87	menuField->SetDivider(labelWidth);
88	view->AddChild(menuField);
89
90	menu = new BPopUpMenu("feels");
91	const struct { const char* name; int32 feel; } feels[] = {
92		{"Normal", B_NORMAL_WINDOW_FEEL},
93		{"Modal Subset", B_MODAL_SUBSET_WINDOW_FEEL},
94		{"App Modal", B_MODAL_APP_WINDOW_FEEL},
95		{"All Modal", B_MODAL_ALL_WINDOW_FEEL},
96		{"Floating Subset", B_FLOATING_SUBSET_WINDOW_FEEL},
97		{"App Floating", B_FLOATING_APP_WINDOW_FEEL},
98		{"All Floating", B_FLOATING_ALL_WINDOW_FEEL},
99		{"Menu", kMenuWindowFeel},
100		{"WindowScreen", kWindowScreenFeel},
101		{"Desktop", kDesktopWindowFeel},
102	};
103	for (uint32 i = 0; i < sizeof(feels) / sizeof(feels[0]); i++) {
104		BMessage* message = new BMessage(kMsgUpdateFeel);
105		message->AddInt32("feel", feels[i].feel);
106		BMenuItem* item = new BMenuItem(feels[i].name, message);
107		if (feels[i].feel == (int32)Feel())
108			item->SetMarked(true);
109
110		menu->AddItem(item);
111	}
112
113	rect.OffsetBy(0, menuField->Bounds().Height() + 10);
114	menuField = new BMenuField(rect, "feel", "Feel:", menu);
115	menuField->ResizeToPreferred();
116	menuField->SetDivider(labelWidth);
117	view->AddChild(menuField);
118
119	menu = new BPopUpMenu("none", false, false);
120	const struct { const char* name; uint32 flag; } flags[] = {
121		{"Not Zoomable", B_NOT_ZOOMABLE},
122		{"Not Closable", B_NOT_CLOSABLE},
123		{"Not Movable", B_NOT_MOVABLE},
124		{"Not Horizontally Resizable", B_NOT_H_RESIZABLE},
125		{"Not Vertically Resizable", B_NOT_V_RESIZABLE},
126		{"Outline Resize", B_OUTLINE_RESIZE},
127		{"Accept First Click", B_WILL_ACCEPT_FIRST_CLICK},
128		{"Not Anchored On Activate", B_NOT_ANCHORED_ON_ACTIVATE},
129		{"Avoid Front", B_AVOID_FRONT},
130#if defined(__HAIKU__) || defined(HAIKU_TARGET_PLATFORM_LIBBE_TEST)
131		{"Same Position In All Workspaces", B_SAME_POSITION_IN_ALL_WORKSPACES},
132#endif
133	};
134	for (uint32 i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
135		BMessage* message = new BMessage(kMsgUpdateFlags);
136		message->AddInt32("flag", flags[i].flag);
137		BMenuItem* item = new BMenuItem(flags[i].name, message);
138
139		menu->AddItem(item);
140	}
141
142	rect.OffsetBy(0, menuField->Bounds().Height() + 10);
143	fFlagsField = new BMenuField(rect, "flags", "Flags:", menu);
144	fFlagsField->ResizeToPreferred();
145	fFlagsField->SetDivider(labelWidth);
146	view->AddChild(fFlagsField);
147
148	// normal
149
150	rect.OffsetBy(0, menuField->Bounds().Height() + 10);
151	BButton* button = new BButton(rect, "normal", "Add Normal Window",
152		AddWindowMessage(B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL),
153		B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
154		B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE);
155	float width, height;
156	button->GetPreferredSize(&width, &height);
157	button->ResizeTo(rect.Width(), height);
158	view->AddChild(button);
159
160	// modal
161
162	rect = button->Frame();
163	rect.OffsetBy(0, rect.Height() + 5);
164	button = new BButton(rect, "modal_subset", "Add Modal Subset",
165		AddWindowMessage(B_MODAL_WINDOW_LOOK, B_MODAL_SUBSET_WINDOW_FEEL),
166		B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
167		B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE);
168	view->AddChild(button);
169
170	rect.OffsetBy(0, rect.Height() + 5);
171	button = new BButton(rect, "app_modal", "Add Application Modal",
172		AddWindowMessage(B_MODAL_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL),
173		B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
174		B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE);
175	view->AddChild(button);
176
177	rect.OffsetBy(0, rect.Height() + 5);
178	button = new BButton(rect, "all_modal", "Add All Modal",
179		AddWindowMessage(B_MODAL_WINDOW_LOOK, B_MODAL_ALL_WINDOW_FEEL),
180		B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
181		B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE);
182	view->AddChild(button);
183
184	// floating
185
186	rect = button->Frame();
187	rect.OffsetBy(0, rect.Height() + 5);
188	button = new BButton(rect, "floating_subset", "Add Floating Subset",
189		AddWindowMessage(B_FLOATING_WINDOW_LOOK, B_FLOATING_SUBSET_WINDOW_FEEL),
190		B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
191		B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE);
192	view->AddChild(button);
193
194	rect.OffsetBy(0, rect.Height() + 5);
195	button = new BButton(rect, "app_floating", "Add Application Floating",
196		AddWindowMessage(B_FLOATING_WINDOW_LOOK, B_FLOATING_APP_WINDOW_FEEL),
197		B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
198		B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE);
199	view->AddChild(button);
200
201	rect.OffsetBy(0, rect.Height() + 5);
202	button = new BButton(rect, "all_floating", "Add All Floating",
203		AddWindowMessage(B_FLOATING_WINDOW_LOOK, B_FLOATING_ALL_WINDOW_FEEL),
204		B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
205		B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE);
206	view->AddChild(button);
207
208	// close
209
210	rect.OffsetBy(0, rect.Height() + 15);
211	button = new BButton(rect, "close", "Close Window",
212		new BMessage(B_QUIT_REQUESTED), B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
213		B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE);
214	button->ResizeToPreferred();
215	button->MoveTo((rect.Width() - button->Bounds().Width()) / 2, rect.top);
216	view->AddChild(button);
217
218	ResizeTo(Bounds().Width(), button->Frame().bottom + 10);
219}
220
221
222Window::~Window()
223{
224}
225
226
227void
228Window::MessageReceived(BMessage* message)
229{
230	switch (message->what) {
231		case kMsgUpdateLook:
232		{
233			int32 look;
234			if (message->FindInt32("look", &look) != B_OK)
235				break;
236
237			SetLook((window_look)look);
238			break;
239		}
240
241		case kMsgUpdateFeel:
242		{
243			int32 feel;
244			if (message->FindInt32("feel", &feel) != B_OK)
245				break;
246
247			if (!IsModal() && !IsFloating())
248				gNormalWindowCount--;
249
250			SetFeel((window_feel)feel);
251			SetTitle(TitleForFeel((window_feel)feel).String());
252
253			if (!IsModal() && !IsFloating())
254				gNormalWindowCount++;
255			break;
256		}
257
258		case kMsgUpdateFlags:
259		{
260			uint32 flag;
261			if (message->FindInt32("flag", (int32*)&flag) != B_OK)
262				break;
263
264			BMenuItem* item;
265			if (message->FindPointer("source", (void**)&item) != B_OK)
266				break;
267
268			item->SetMarked(!item->IsMarked());
269
270			uint32 flags = Flags();
271			if (item->IsMarked())
272				flags |= flag;
273			else
274				flags &= ~flag;
275
276			SetFlags(flags);
277			_UpdateFlagsMenuLabel();
278			break;
279		}
280
281		case kMsgAddWindow:
282		case kMsgAddSubsetWindow:
283		{
284			int32 look, feel;
285			if (message->FindInt32("look", &look) != B_OK
286				|| message->FindInt32("feel", &feel) != B_OK)
287				break;
288
289			BWindow* window = new Window(Frame().OffsetByCopy(20, 20),
290				(window_look)look, (window_feel)feel);
291
292			if (message->what == kMsgAddSubsetWindow) {
293				status_t status = window->AddToSubset(this);
294				if (status != B_OK) {
295					char text[512];
296					snprintf(text, sizeof(text),
297						"Window could not be added to subset:\n\n\%s", strerror(status));
298					(new BAlert("Alert", text, "OK"))->Go(NULL);
299
300					delete window;
301					break;
302				}
303			}
304
305			window->Show();
306			break;
307		}
308
309		default:
310			BWindow::MessageReceived(message);
311	}
312}
313
314
315bool
316Window::QuitRequested()
317{
318	if (!IsModal() && !IsFloating())
319		gNormalWindowCount--;
320
321	if (gNormalWindowCount < 1)
322		be_app->PostMessage(B_QUIT_REQUESTED);
323
324	return true;
325}
326
327
328BMessage*
329Window::AddWindowMessage(window_look look, window_feel feel)
330{
331	BMessage* message = new BMessage(kMsgAddWindow);
332
333	if (feel == B_FLOATING_SUBSET_WINDOW_FEEL
334		|| feel == B_MODAL_SUBSET_WINDOW_FEEL)
335		message->what = kMsgAddSubsetWindow;
336
337	message->AddInt32("look", look);
338	message->AddInt32("feel", feel);
339
340	return message;
341}
342
343
344BString
345Window::TitleForFeel(window_feel feel)
346{
347	BString title = "Look&Feel - ";
348
349	switch ((uint32)feel) {
350		case B_NORMAL_WINDOW_FEEL:
351			title += "Normal";
352			break;
353
354		// modal feels
355
356		case B_MODAL_SUBSET_WINDOW_FEEL:
357			title += "Modal Subset";
358			break;
359		case B_MODAL_APP_WINDOW_FEEL:
360			title += "Application Modal";
361			break;
362		case B_MODAL_ALL_WINDOW_FEEL:
363			title += "All Modal";
364			break;
365
366		// floating feels
367
368		case B_FLOATING_SUBSET_WINDOW_FEEL:
369			title += "Floating Subset";
370			break;
371		case B_FLOATING_APP_WINDOW_FEEL:
372			title += "Application Floating";
373			break;
374		case B_FLOATING_ALL_WINDOW_FEEL:
375			title += "All Floating";
376			break;
377
378		// special/private feels
379
380		case kMenuWindowFeel:
381			title += "Menu";
382			break;
383		case kWindowScreenFeel:
384			title += "WindowScreen";
385			break;
386		case kDesktopWindowFeel:
387			title += "Desktop";
388			break;
389	}
390
391	return title;
392}
393
394
395void
396Window::_UpdateFlagsMenuLabel()
397{
398	BString label;
399	BMenu* menu = fFlagsField->Menu();
400
401	for (int32 i = 0; i < menu->CountItems(); i++) {
402		BMenuItem* item = menu->ItemAt(i);
403
404		if (item->IsMarked()) {
405			if (label != "")
406				label += " + ";
407			label += item->Label();
408		}
409	}
410
411	if (label == "")
412		label = "none";
413
414	menu->Superitem()->SetLabel(label.String());
415}
416
417
418//	#pragma mark -
419
420
421class Application : public BApplication {
422	public:
423		Application();
424
425		virtual void ReadyToRun();
426};
427
428
429Application::Application()
430	: BApplication("application/x-vnd.haiku-looknfeel")
431{
432}
433
434
435void
436Application::ReadyToRun()
437{
438	Window *window = new Window(BRect(100, 100, 400, 420),
439		B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL);
440	window->Show();
441}
442
443
444//	#pragma mark -
445
446
447int
448main(int argc, char **argv)
449{
450	Application app;// app;
451
452	app.Run();
453	return 0;
454}
455