xref: /haiku/src/apps/mediaplayer/MainWin.cpp (revision 91b9ff3f99ab334db0b4cabc08625245d47f3025)
1 /*
2  * MainWin.cpp - Media Player for the Haiku Operating System
3  *
4  * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  *
19  */
20 #include "MainWin.h"
21 #include "MainApp.h"
22 
23 #include <View.h>
24 #include <Screen.h>
25 #include <Menu.h>
26 #include <MenuBar.h>
27 #include <MenuItem.h>
28 #include <Application.h>
29 #include <Alert.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <Messenger.h>
33 #include <PopUpMenu.h>
34 #include <String.h>
35 #include <Debug.h>
36 #include <math.h>
37 
38 #define NAME "MediaPlayer"
39 #define MIN_WIDTH 250
40 
41 
42 // XXX TODO: why is lround not defined?
43 #define lround(a) ((int)(0.99999 + (a)))
44 
45 enum
46 {
47 	M_DUMMY = 0x100,
48 	M_FILE_OPEN = 0x1000,
49 	M_FILE_NEWPLAYER,
50 	M_FILE_INFO,
51 	M_FILE_ABOUT,
52 	M_FILE_CLOSE,
53 	M_FILE_QUIT,
54 	M_VIEW_50,
55 	M_VIEW_100,
56 	M_VIEW_200,
57 	M_VIEW_300,
58 	M_VIEW_400,
59 	M_TOGGLE_FULLSCREEN,
60 	M_TOGGLE_NO_BORDER,
61 	M_TOGGLE_NO_MENU,
62 	M_TOGGLE_NO_CONTROLS,
63 	M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS,
64 	M_TOGGLE_ALWAYS_ON_TOP,
65 	M_TOGGLE_KEEP_ASPECT_RATIO,
66 	M_PREFERENCES,
67 	M_VOLUME_UP,
68 	M_VOLUME_DOWN,
69 	M_CHANNEL_NEXT,
70 	M_CHANNEL_PREV,
71 	M_ASPECT_100000_1,
72 	M_ASPECT_106666_1,
73 	M_ASPECT_109091_1,
74 	M_ASPECT_141176_1,
75 	M_ASPECT_720_576,
76 	M_ASPECT_704_576,
77 	M_ASPECT_544_576,
78 	M_SELECT_AUDIO_TRACK		= 0x00000800,
79 	M_SELECT_AUDIO_TRACK_END	= 0x00000fff,
80 	M_SELECT_VIDEO_TRACK		= 0x00010000,
81 	M_SELECT_VIDEO_TRACK_END	= 0x000fffff,
82 };
83 
84 //#define printf(a...)
85 
86 
87 MainWin::MainWin()
88  :	BWindow(BRect(100,100,350,300), NAME, B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS /* | B_WILL_ACCEPT_FIRST_CLICK */)
89  ,  fFilePanel(NULL)
90  ,	fHasFile(false)
91  ,	fHasVideo(false)
92  ,	fController(new Controller)
93  ,	fIsFullscreen(false)
94  ,	fKeepAspectRatio(true)
95  ,	fAlwaysOnTop(false)
96  ,	fNoMenu(false)
97  ,	fNoBorder(false)
98  ,	fNoControls(false)
99  ,	fSourceWidth(0)
100  ,	fSourceHeight(0)
101  ,	fWidthScale(1.0)
102  ,	fHeightScale(1.0)
103  ,	fMouseDownTracking(false)
104 {
105 	static int pos = 0;
106 	MoveBy(pos * 25, pos * 25);
107 	pos = (pos + 1) % 15;
108 
109 	BRect rect = Bounds();
110 
111 	// background
112 	fBackground = new BView(rect, "background", B_FOLLOW_ALL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
113 	fBackground->SetViewColor(0,0,0);
114 	AddChild(fBackground);
115 
116 	// menu
117 	fMenuBar = new BMenuBar(fBackground->Bounds(), "menu");
118 	CreateMenu();
119 	fBackground->AddChild(fMenuBar);
120 	fMenuBar->ResizeToPreferred();
121 	fMenuBarHeight = (int)fMenuBar->Frame().Height() + 1;
122 	fMenuBar->SetResizingMode(B_FOLLOW_NONE);
123 
124 	// video view
125 	rect = BRect(0, fMenuBarHeight, fBackground->Bounds().right, fMenuBarHeight + 10);
126 	fVideoView = new VideoView(rect, "video display", B_FOLLOW_NONE, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
127 	fBackground->AddChild(fVideoView);
128 
129 	// controls
130 	rect = BRect(0, fMenuBarHeight + 11, fBackground->Bounds().right, fBackground->Bounds().bottom);
131 	fControls = new ControllerView(rect, fController);
132 	fBackground->AddChild(fControls);
133 	fControls->ResizeToPreferred();
134 	fControlsHeight = (int)fControls->Frame().Height() + 1;
135 	fControlsWidth = (int)fControls->Frame().Width() + 1;
136 	fControls->SetResizingMode(B_FOLLOW_NONE);
137 //	fControls->MoveTo(0, fBackground->Bounds().bottom - fControlsHeight + 1);
138 
139 //	fVideoView->ResizeTo(fBackground->Bounds().Width(), fBackground->Bounds().Height() - fMenuBarHeight - fControlsHeight);
140 
141 	fController->SetVideoView(fVideoView);
142 	fVideoView->IsOverlaySupported();
143 
144 	printf("fMenuBarHeight %d\n", fMenuBarHeight);
145 	printf("fControlsHeight %d\n", fControlsHeight);
146 	printf("fControlsWidth %d\n", fControlsWidth);
147 
148 	SetupWindow();
149 
150 	Show();
151 }
152 
153 
154 MainWin::~MainWin()
155 {
156 	printf("MainWin::~MainWin\n");
157 	delete fController;
158 	delete fFilePanel;
159 }
160 
161 
162 void
163 MainWin::OpenFile(const entry_ref &ref)
164 {
165 	printf("MainWin::OpenFile\n");
166 
167 	status_t err = fController->SetTo(ref);
168 	if (err != B_OK) {
169 		char s[300];
170 		sprintf(s, "Can't open file\n\n%s\n\nError 0x%08lx\n(%s)\n",
171 			ref.name, err, strerror(err));
172 		(new BAlert("error", s, "OK"))->Go();
173 		fHasFile = false;
174 		fHasVideo = false;
175 		SetTitle(NAME);
176 	} else {
177 		fHasFile = true;
178 		fHasVideo = fController->VideoTrackCount() != 0;
179 		SetTitle(ref.name);
180 	}
181 	SetupWindow();
182 }
183 
184 void
185 MainWin::SetupWindow()
186 {
187 	printf("MainWin::SetupWindow\n");
188 
189 	// Pupulate the track menus
190 	SetupTrackMenus();
191 	// Enable both if a file was loaded
192 	fAudioMenu->SetEnabled(fHasFile);
193 	fVideoMenu->SetEnabled(fHasFile);
194 	// Select first track (might be "none") in both
195 	fAudioMenu->ItemAt(0)->SetMarked(true);
196 	fVideoMenu->ItemAt(0)->SetMarked(true);
197 
198 	if (fHasVideo) {
199 		fSourceWidth = 320;
200 		fSourceHeight = 240;
201 		fWidthScale = 1.24;
202 		fHeightScale = 1.35;
203 	} else {
204 		fSourceWidth = 0;
205 		fSourceHeight = 0;
206 		fWidthScale = 1.0;
207 		fHeightScale = 1.0;
208 	}
209 
210 	ResizeWindow(100);
211 
212 	fVideoView->MakeFocus();
213 }
214 
215 
216 void
217 MainWin::ResizeWindow(int percent)
218 {
219 	int video_width;
220 	int video_height;
221 
222 	// Get required window size
223 	video_width = lround(fSourceWidth * fWidthScale);
224 	video_height = lround(fSourceHeight * fHeightScale);
225 
226 	video_width = (video_width * percent) / 100;
227 	video_height = (video_height * percent) / 100;
228 
229 	// Calculate and set the initial window size
230 	int width = max_c(fControlsWidth, video_width);
231 	int height = (fNoMenu ? 0 : fMenuBarHeight) + (fNoControls ? 0 : fControlsHeight) + video_height;
232 	SetWindowSizeLimits();
233 	ResizeTo(width - 1, height - 1);
234 }
235 
236 
237 void
238 MainWin::SetWindowSizeLimits()
239 {
240 	int min_width = fNoControls  ? MIN_WIDTH : fControlsWidth;
241 	int min_height = (fNoMenu ? 0 : fMenuBarHeight) + (fNoControls ? 0 : fControlsHeight);
242 
243 	SetSizeLimits(min_width - 1, 32000, min_height - 1, fHasVideo ? 32000 : min_height - 1);
244 }
245 
246 
247 void
248 MainWin::CreateMenu()
249 {
250 	fFileMenu = new BMenu(NAME);
251 	fViewMenu = new BMenu("View");
252 	fSettingsMenu = new BMenu("Settings");
253 	fAudioMenu = new BMenu("Audio Track");
254 	fVideoMenu = new BMenu("Video Track");
255 	fDebugMenu = new BMenu("Debug");
256 
257 	fMenuBar->AddItem(fFileMenu);
258 	fMenuBar->AddItem(fViewMenu);
259 	fMenuBar->AddItem(fSettingsMenu);
260 	fMenuBar->AddItem(fDebugMenu);
261 
262 	fFileMenu->AddItem(new BMenuItem("New Player", new BMessage(M_FILE_NEWPLAYER), 'N', B_COMMAND_KEY));
263 	fFileMenu->AddSeparatorItem();
264 	fFileMenu->AddItem(new BMenuItem("Open File"B_UTF8_ELLIPSIS, new BMessage(M_FILE_OPEN), 'O', B_COMMAND_KEY));
265 	fFileMenu->AddItem(new BMenuItem("File Info"B_UTF8_ELLIPSIS, new BMessage(M_FILE_INFO), 'I', B_COMMAND_KEY));
266 	fFileMenu->AddSeparatorItem();
267 	fFileMenu->AddItem(new BMenuItem("About", new BMessage(M_FILE_ABOUT), 'A', B_COMMAND_KEY));
268 	fFileMenu->AddSeparatorItem();
269 	fFileMenu->AddItem(new BMenuItem("Close", new BMessage(M_FILE_CLOSE), 'W', B_COMMAND_KEY));
270 	fFileMenu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q', B_COMMAND_KEY));
271 
272 	fViewMenu->AddItem(new BMenuItem("50% scale", new BMessage(M_VIEW_50), '0', B_COMMAND_KEY));
273 	fViewMenu->AddItem(new BMenuItem("100% scale", new BMessage(M_VIEW_100), '1', B_COMMAND_KEY));
274 	fViewMenu->AddItem(new BMenuItem("200% scale", new BMessage(M_VIEW_200), '2', B_COMMAND_KEY));
275 	fViewMenu->AddItem(new BMenuItem("300% scale", new BMessage(M_VIEW_300), '3', B_COMMAND_KEY));
276 	fViewMenu->AddItem(new BMenuItem("400% scale", new BMessage(M_VIEW_400), '4', B_COMMAND_KEY));
277 	fViewMenu->AddSeparatorItem();
278 	fViewMenu->AddItem(new BMenuItem("Full Screen", new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
279 //	fViewMenu->SetRadioMode(true);
280 //	fViewMenu->AddSeparatorItem();
281 //	fViewMenu->AddItem(new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
282 
283 	fSettingsMenu->AddItem(fAudioMenu);
284 	fSettingsMenu->AddItem(fVideoMenu);
285 	fSettingsMenu->AddSeparatorItem();
286 	fSettingsMenu->AddItem(new BMenuItem("No Menu", new BMessage(M_TOGGLE_NO_MENU), 'M', B_COMMAND_KEY));
287 	fSettingsMenu->AddItem(new BMenuItem("No Border", new BMessage(M_TOGGLE_NO_BORDER), 'B', B_COMMAND_KEY));
288 	fSettingsMenu->AddItem(new BMenuItem("No Controls", new BMessage(M_TOGGLE_NO_CONTROLS), 'C', B_COMMAND_KEY));
289 	fSettingsMenu->AddItem(new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
290 	fSettingsMenu->AddItem(new BMenuItem("Keep Aspect Ratio", new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
291 	fSettingsMenu->AddSeparatorItem();
292 	fSettingsMenu->AddItem(new BMenuItem("Preferences"B_UTF8_ELLIPSIS, new BMessage(M_PREFERENCES), 'P', B_COMMAND_KEY));
293 
294 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", new BMessage(M_ASPECT_100000_1)));
295 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", new BMessage(M_ASPECT_106666_1)));
296 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.09091:1", new BMessage(M_ASPECT_109091_1)));
297 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.41176:1", new BMessage(M_ASPECT_141176_1)));
298 	fDebugMenu->AddItem(new BMenuItem("force 720 x 576, display aspect 4:3", new BMessage(M_ASPECT_720_576)));
299 	fDebugMenu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", new BMessage(M_ASPECT_704_576)));
300 	fDebugMenu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", new BMessage(M_ASPECT_544_576)));
301 
302 	fAudioMenu->SetRadioMode(true);
303 	fVideoMenu->SetRadioMode(true);
304 /*
305 	fSettingsMenu->ItemAt(3)->SetMarked(fIsFullscreen);
306 	fSettingsMenu->ItemAt(5)->SetMarked(fNoMenu);
307 	fSettingsMenu->ItemAt(6)->SetMarked(fNoBorder);
308 	fSettingsMenu->ItemAt(7)->SetMarked(fAlwaysOnTop);
309 	fSettingsMenu->ItemAt(8)->SetMarked(fKeepAspectRatio);
310 	fSettingsMenu->ItemAt(10)->SetEnabled(false); // XXX disable unused preference menu
311 */
312 }
313 
314 
315 void
316 MainWin::SetupTrackMenus()
317 {
318 	fAudioMenu->RemoveItems(0, fAudioMenu->CountItems(), true);
319 	fVideoMenu->RemoveItems(0, fVideoMenu->CountItems(), true);
320 
321 	int c, i;
322 	char s[100];
323 
324 	c = fController->AudioTrackCount();
325 	for (i = 0; i < c; i++) {
326 		sprintf(s, "Track %d", i + 1);
327 		fAudioMenu->AddItem(new BMenuItem(s, new BMessage(M_SELECT_AUDIO_TRACK + i)));
328 	}
329 	if (!c)
330 		fAudioMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY)));
331 
332 	c = fController->VideoTrackCount();
333 	for (i = 0; i < c; i++) {
334 		sprintf(s, "Track %d", i + 1);
335 		fVideoMenu->AddItem(new BMenuItem(s, new BMessage(M_SELECT_VIDEO_TRACK + i)));
336 	}
337 	if (!c)
338 		fVideoMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY)));
339 }
340 
341 
342 bool
343 MainWin::QuitRequested()
344 {
345 	be_app->PostMessage(B_QUIT_REQUESTED);
346 	return true;
347 }
348 
349 
350 void
351 MainWin::MouseDown(BMessage *msg)
352 {
353 	BPoint screen_where;
354 	uint32 buttons = msg->FindInt32("buttons");
355 
356 	// On Zeta, only "screen_where" is relyable, "where" and "be:view_where" seem to be broken
357 	if (B_OK != msg->FindPoint("screen_where", &screen_where)) {
358 		// Workaround for BeOS R5, it has no "screen_where"
359 		fVideoView->GetMouse(&screen_where, &buttons, false);
360 		fVideoView->ConvertToScreen(&screen_where);
361 	}
362 
363 //	msg->PrintToStream();
364 
365 //	if (1 == msg->FindInt32("buttons") && msg->FindInt32("clicks") == 1) {
366 
367 	if (1 == buttons && msg->FindInt32("clicks") % 2 == 0) {
368 		BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1, screen_where.y + 1);
369 		if (r.Contains(fMouseDownMousePos)) {
370 			PostMessage(M_TOGGLE_FULLSCREEN);
371 			return;
372 		}
373 	}
374 
375 	if (2 == buttons && msg->FindInt32("clicks") % 2 == 0) {
376 		BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1, screen_where.y + 1);
377 		if (r.Contains(fMouseDownMousePos)) {
378 			PostMessage(M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS);
379 			return;
380 		}
381 	}
382 
383 /*
384 		// very broken in Zeta:
385 		fMouseDownMousePos = fVideoView->ConvertToScreen(msg->FindPoint("where"));
386 */
387 	fMouseDownMousePos = screen_where;
388 	fMouseDownWindowPos = Frame().LeftTop();
389 
390 	if (buttons == 1 && !fIsFullscreen) {
391 		// start mouse tracking
392 		fVideoView->SetMouseEventMask(B_POINTER_EVENTS | B_NO_POINTER_HISTORY /* | B_LOCK_WINDOW_FOCUS */);
393 		fMouseDownTracking = true;
394 	}
395 
396 	// pop up a context menu if right mouse button is down for 200 ms
397 
398 	if ((buttons & 2) == 0)
399 		return;
400 	bigtime_t start = system_time();
401 	bigtime_t delay = 200000;
402 	BPoint location;
403 	do {
404 		fVideoView->GetMouse(&location, &buttons);
405 		if ((buttons & 2) == 0)
406 			break;
407 		snooze(1000);
408 	} while (system_time() - start < delay);
409 
410 	if (buttons & 2)
411 		ShowContextMenu(screen_where);
412 }
413 
414 
415 void
416 MainWin::MouseMoved(BMessage *msg)
417 {
418 //	msg->PrintToStream();
419 
420 	BPoint mousePos;
421 	uint32 buttons = msg->FindInt32("buttons");
422 
423 	if (1 == buttons && fMouseDownTracking && !fIsFullscreen) {
424 /*
425 		// very broken in Zeta:
426 		BPoint mousePos = msg->FindPoint("where");
427 		printf("view where: %.0f, %.0f => ", mousePos.x, mousePos.y);
428 		fVideoView->ConvertToScreen(&mousePos);
429 */
430 		// On Zeta, only "screen_where" is relyable, "where" and "be:view_where" seem to be broken
431 		if (B_OK != msg->FindPoint("screen_where", &mousePos)) {
432 			// Workaround for BeOS R5, it has no "screen_where"
433 			fVideoView->GetMouse(&mousePos, &buttons, false);
434 			fVideoView->ConvertToScreen(&mousePos);
435 		}
436 //		printf("screen where: %.0f, %.0f => ", mousePos.x, mousePos.y);
437 		float delta_x = mousePos.x - fMouseDownMousePos.x;
438 		float delta_y = mousePos.y - fMouseDownMousePos.y;
439 		float x = fMouseDownWindowPos.x + delta_x;
440 		float y = fMouseDownWindowPos.y + delta_y;
441 //		printf("move window to %.0f, %.0f\n", x, y);
442 		MoveTo(x, y);
443 	}
444 }
445 
446 
447 void
448 MainWin::MouseUp(BMessage *msg)
449 {
450 //	msg->PrintToStream();
451 	fMouseDownTracking = false;
452 }
453 
454 
455 void
456 MainWin::ShowContextMenu(const BPoint &screen_point)
457 {
458 	printf("Show context menu\n");
459 	BPopUpMenu *menu = new BPopUpMenu("context menu", false, false);
460 	BMenuItem *item;
461 	menu->AddItem(item = new BMenuItem("Full Screen", new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
462 	item->SetMarked(fIsFullscreen);
463 	menu->AddSeparatorItem();
464 	menu->AddItem(item = new BMenuItem("No Menu", new BMessage(M_TOGGLE_NO_MENU), 'M', B_COMMAND_KEY));
465 	item->SetMarked(fNoMenu);
466 	menu->AddItem(item = new BMenuItem("No Border", new BMessage(M_TOGGLE_NO_BORDER), 'B', B_COMMAND_KEY));
467 	item->SetMarked(fNoBorder);
468 	menu->AddItem(item = new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
469 	item->SetMarked(fAlwaysOnTop);
470 	menu->AddItem(item = new BMenuItem("Keep Aspect Ratio", new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
471 	item->SetMarked(fKeepAspectRatio);
472 	menu->AddSeparatorItem();
473 	menu->AddItem(new BMenuItem("About", new BMessage(M_FILE_ABOUT), 'A', B_COMMAND_KEY));
474 	menu->AddSeparatorItem();
475 	menu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q', B_COMMAND_KEY));
476 
477 	menu->AddSeparatorItem();
478 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", new BMessage(M_ASPECT_100000_1)));
479 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", new BMessage(M_ASPECT_106666_1)));
480 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.09091:1", new BMessage(M_ASPECT_109091_1)));
481 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.41176:1", new BMessage(M_ASPECT_141176_1)));
482 	menu->AddItem(new BMenuItem("force 720 x 576, display aspect 4:3", new BMessage(M_ASPECT_720_576)));
483 	menu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", new BMessage(M_ASPECT_704_576)));
484 	menu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", new BMessage(M_ASPECT_544_576)));
485 
486 	menu->SetTargetForItems(this);
487 	BRect r(screen_point.x - 5, screen_point.y - 5, screen_point.x + 5, screen_point.y + 5);
488 	menu->Go(screen_point, true, true, r, true);
489 }
490 
491 
492 void
493 MainWin::VideoFormatChange(int width, int height, float width_scale, float height_scale)
494 {
495 	// called when video format or aspect ratio changes
496 
497 	printf("VideoFormatChange enter: width %d, height %d, width_scale %.6f, height_scale %.6f\n", width, height, width_scale, height_scale);
498 
499 	if (width_scale < 1.0 && height_scale >= 1.0) {
500 		width_scale  = 1.0 / width_scale;
501 		height_scale = 1.0 / height_scale;
502 		printf("inverting! new values: width_scale %.6f, height_scale %.6f\n", width_scale, height_scale);
503 	}
504 
505  	fSourceWidth  = width;
506  	fSourceHeight = height;
507  	fWidthScale   = width_scale;
508  	fHeightScale  = height_scale;
509 
510  	FrameResized(Bounds().Width(), Bounds().Height());
511 
512 	printf("VideoFormatChange leave\n");
513 }
514 
515 
516 void
517 MainWin::Zoom(BPoint rec_position, float rec_width, float rec_height)
518 {
519 	PostMessage(M_TOGGLE_FULLSCREEN);
520 }
521 
522 
523 void
524 MainWin::FrameResized(float new_width, float new_height)
525 {
526 	if (new_width != Bounds().Width() || new_height != Bounds().Height()) {
527 		debugger("size wrong\n");
528 	}
529 
530 	bool no_menu = fNoMenu || fIsFullscreen;
531 	bool no_controls = fNoControls || fIsFullscreen;
532 
533 	printf("FrameResized enter: new_width %.0f, new_height %.0f\n", new_width, new_height);
534 
535 	int max_video_width  = int(new_width) + 1;
536 	int max_video_height = int(new_height) + 1 - (no_menu  ? 0 : fMenuBarHeight) - (no_controls ? 0 : fControlsHeight);
537 
538 	ASSERT(max_video_height >= 0);
539 
540 	int y = 0;
541 
542 	if (no_menu) {
543 		if (!fMenuBar->IsHidden())
544 			fMenuBar->Hide();
545 	} else {
546 //		fMenuBar->MoveTo(0, y);
547 		fMenuBar->ResizeTo(new_width, fMenuBarHeight - 1);
548 		if (fMenuBar->IsHidden())
549 			fMenuBar->Show();
550 		y += fMenuBarHeight;
551 	}
552 
553 	if (max_video_height == 0) {
554 		if (!fVideoView->IsHidden())
555 			fVideoView->Hide();
556 	} else {
557 //		fVideoView->MoveTo(0, y);
558 //		fVideoView->ResizeTo(max_video_width - 1, max_video_height - 1);
559 		ResizeVideoView(0, y, max_video_width, max_video_height);
560 		if (fVideoView->IsHidden())
561 			fVideoView->Show();
562 		y += max_video_height;
563 	}
564 
565 	if (no_controls) {
566 		if (!fControls->IsHidden())
567 			fControls->Hide();
568 	} else {
569 		fControls->MoveTo(0, y);
570 		fControls->ResizeTo(new_width, fControlsHeight - 1);
571 		if (fControls->IsHidden())
572 			fControls->Show();
573 //		y += fControlsHeight;
574 	}
575 
576 	printf("FrameResized leave\n");
577 }
578 
579 
580 void
581 MainWin::ShowFileInfo()
582 {
583 }
584 
585 
586 void
587 MainWin::ResizeVideoView(int x, int y, int width, int height)
588 {
589 	printf("ResizeVideoView: %d,%d, width %d, height %d\n", x, y, width, height);
590 
591 	if (fKeepAspectRatio) {
592 		// Keep aspect ratio, place video view inside
593 		// the background area (may create black bars).
594 		float scaled_width  = fSourceWidth * fWidthScale;
595 		float scaled_height = fSourceHeight * fHeightScale;
596 		float factor = min_c(width / scaled_width, height / scaled_height);
597 		int render_width = lround(scaled_width * factor);
598 		int render_height = lround(scaled_height * factor);
599 		if (render_width > width)
600 			render_width = width;
601 		if (render_height > height)
602 			render_height = height;
603 
604 		int x_ofs = x + (width - render_width) / 2;
605 		int y_ofs = y + (height - render_height) / 2;
606 
607 		fVideoView->MoveTo(x_ofs, y_ofs);
608 		fVideoView->ResizeTo(render_width - 1, render_height - 1);
609 
610 	} else {
611 		fVideoView->MoveTo(x, y);
612 		fVideoView->ResizeTo(width - 1, height - 1);
613 	}
614 }
615 
616 
617 void
618 MainWin::ToggleNoBorderNoMenu()
619 {
620 	if (!fNoMenu && !fNoBorder && !fNoControls) {
621 		PostMessage(M_TOGGLE_NO_MENU);
622 		PostMessage(M_TOGGLE_NO_BORDER);
623 		PostMessage(M_TOGGLE_NO_CONTROLS);
624 	} else {
625 		if (!fNoMenu)
626 			PostMessage(M_TOGGLE_NO_MENU);
627 		if (!fNoBorder)
628 			PostMessage(M_TOGGLE_NO_BORDER);
629 		if (!fNoControls)
630 			PostMessage(M_TOGGLE_NO_CONTROLS);
631 	}
632 }
633 
634 
635 void
636 MainWin::ToggleFullscreen()
637 {
638 	printf("ToggleFullscreen enter\n");
639 
640 	if (!fHasVideo) {
641 		printf("ToggleFullscreen - ignoring, as we don't have a video\n");
642 		return;
643 	}
644 
645 	fIsFullscreen = !fIsFullscreen;
646 
647 	if (fIsFullscreen) {
648 		// switch to fullscreen
649 
650 		fSavedFrame = Frame();
651 		printf("saving current frame: %d %d %d %d\n", int(fSavedFrame.left), int(fSavedFrame.top), int(fSavedFrame.right), int(fSavedFrame.bottom));
652 		BScreen screen(this);
653 		BRect rect(screen.Frame());
654 
655 		Hide();
656 		MoveTo(rect.left, rect.top);
657 		ResizeTo(rect.Width(), rect.Height());
658 		Show();
659 
660 	} else {
661 		// switch back from full screen mode
662 
663 		Hide();
664 		MoveTo(fSavedFrame.left, fSavedFrame.top);
665 		ResizeTo(fSavedFrame.Width(), fSavedFrame.Height());
666 		Show();
667 	}
668 
669 	printf("ToggleFullscreen leave\n");
670 }
671 
672 void
673 MainWin::ToggleNoControls()
674 {
675 	printf("ToggleNoControls enter\n");
676 
677 	if (fIsFullscreen) {
678 		// fullscreen is always without menu
679 		printf("ToggleNoControls leave, doing nothing, we are fullscreen\n");
680 		return;
681 	}
682 
683 	fNoControls = !fNoControls;
684 	SetWindowSizeLimits();
685 
686 	if (fNoControls) {
687 		ResizeBy(0, - fControlsHeight);
688 	} else {
689 		ResizeBy(0, fControlsHeight);
690 	}
691 
692 	printf("ToggleNoControls leave\n");
693 }
694 
695 void
696 MainWin::ToggleNoMenu()
697 {
698 	printf("ToggleNoMenu enter\n");
699 
700 	if (fIsFullscreen) {
701 		// fullscreen is always without menu
702 		printf("ToggleNoMenu leave, doing nothing, we are fullscreen\n");
703 		return;
704 	}
705 
706 	fNoMenu = !fNoMenu;
707 	SetWindowSizeLimits();
708 
709 	if (fNoMenu) {
710 		MoveBy(0, fMenuBarHeight);
711 		ResizeBy(0, - fMenuBarHeight);
712 	} else {
713 		MoveBy(0, - fMenuBarHeight);
714 		ResizeBy(0, fMenuBarHeight);
715 	}
716 
717 	printf("ToggleNoMenu leave\n");
718 }
719 
720 
721 void
722 MainWin::ToggleNoBorder()
723 {
724 	printf("ToggleNoBorder enter\n");
725 	fNoBorder = !fNoBorder;
726 	SetLook(fNoBorder ? B_BORDERED_WINDOW_LOOK : B_TITLED_WINDOW_LOOK);
727 	printf("ToggleNoBorder leave\n");
728 }
729 
730 
731 void
732 MainWin::ToggleAlwaysOnTop()
733 {
734 	printf("ToggleAlwaysOnTop enter\n");
735 	fAlwaysOnTop = !fAlwaysOnTop;
736 	SetFeel(fAlwaysOnTop ? B_FLOATING_ALL_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL);
737 	printf("ToggleAlwaysOnTop leave\n");
738 }
739 
740 
741 void
742 MainWin::ToggleKeepAspectRatio()
743 {
744 	printf("ToggleKeepAspectRatio enter\n");
745 	fKeepAspectRatio = !fKeepAspectRatio;
746 	FrameResized(Bounds().Width(), Bounds().Height());
747 	printf("ToggleKeepAspectRatio leave\n");
748 }
749 
750 
751 void
752 MainWin::RefsReceived(BMessage *msg)
753 {
754 	printf("MainWin::RefsReceived\n");
755 	// the first file is played in this window,
756 	// if additional files (refs) are included,
757 	// more windows are launched
758 
759 	entry_ref ref;
760 	int n = 0;
761 	for (int i = 0; B_OK == msg->FindRef("refs", i, &ref); i++) {
762 		BEntry entry(&ref, true);
763 		if (!entry.Exists() || !entry.IsFile())
764 			continue;
765 		if (n == 0) {
766 			OpenFile(ref);
767 		} else {
768 			BMessage m(B_REFS_RECEIVED);
769 			m.AddRef("refs", &ref);
770 			gMainApp->NewWindow()->PostMessage(&m);
771 		}
772 		n++;
773 	}
774 }
775 
776 
777 /* Trap keys that are about to be send to background or renderer view.
778  * Return B_OK if it shouldn't be passed to the view
779  */
780 status_t
781 MainWin::KeyDown(BMessage *msg)
782 {
783 //	msg->PrintToStream();
784 
785 	uint32 key		 = msg->FindInt32("key");
786 	uint32 raw_char  = msg->FindInt32("raw_char");
787 	uint32 modifiers = msg->FindInt32("modifiers");
788 
789 	printf("key 0x%lx, raw_char 0x%lx, modifiers 0x%lx\n", key, raw_char, modifiers);
790 
791 	switch (raw_char) {
792 		case B_SPACE:
793 			PostMessage(M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS);
794 			return B_OK;
795 
796 		case B_ESCAPE:
797 			if (fIsFullscreen) {
798 				PostMessage(M_TOGGLE_FULLSCREEN);
799 				return B_OK;
800 			} else
801 				break;
802 
803 		case B_ENTER:		// Enter / Return
804 			if (modifiers & B_COMMAND_KEY) {
805 				PostMessage(M_TOGGLE_FULLSCREEN);
806 				return B_OK;
807 			} else
808 				break;
809 
810 		case B_TAB:
811 			if ((modifiers & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY | B_MENU_KEY)) == 0) {
812 				PostMessage(M_TOGGLE_FULLSCREEN);
813 				return B_OK;
814 			} else
815 				break;
816 
817 		case B_UP_ARROW:
818 			if (modifiers & B_COMMAND_KEY) {
819 				PostMessage(M_CHANNEL_NEXT);
820 			} else {
821 				PostMessage(M_VOLUME_UP);
822 			}
823 			return B_OK;
824 
825 		case B_DOWN_ARROW:
826 			if (modifiers & B_COMMAND_KEY) {
827 				PostMessage(M_CHANNEL_PREV);
828 			} else {
829 				PostMessage(M_VOLUME_DOWN);
830 			}
831 			return B_OK;
832 
833 		case B_RIGHT_ARROW:
834 			if (modifiers & B_COMMAND_KEY) {
835 				PostMessage(M_VOLUME_UP);
836 			} else {
837 				PostMessage(M_CHANNEL_NEXT);
838 			}
839 			return B_OK;
840 
841 		case B_LEFT_ARROW:
842 			if (modifiers & B_COMMAND_KEY) {
843 				PostMessage(M_VOLUME_DOWN);
844 			} else {
845 				PostMessage(M_CHANNEL_PREV);
846 			}
847 			return B_OK;
848 
849 		case B_PAGE_UP:
850 			PostMessage(M_CHANNEL_NEXT);
851 			return B_OK;
852 
853 		case B_PAGE_DOWN:
854 			PostMessage(M_CHANNEL_PREV);
855 			return B_OK;
856 	}
857 
858 	switch (key) {
859 		case 0x3a:  		// numeric keypad +
860 			if ((modifiers & B_COMMAND_KEY) == 0) {
861 				printf("if\n");
862 				PostMessage(M_VOLUME_UP);
863 				return B_OK;
864 			} else {
865 				printf("else\n");
866 				break;
867 			}
868 
869 		case 0x25:  		// numeric keypad -
870 			if ((modifiers & B_COMMAND_KEY) == 0) {
871 				PostMessage(M_VOLUME_DOWN);
872 				return B_OK;
873 			} else {
874 				break;
875 			}
876 
877 		case 0x38:			// numeric keypad up arrow
878 			PostMessage(M_VOLUME_UP);
879 			return B_OK;
880 
881 		case 0x59:			// numeric keypad down arrow
882 			PostMessage(M_VOLUME_DOWN);
883 			return B_OK;
884 
885 		case 0x39:			// numeric keypad page up
886 		case 0x4a:			// numeric keypad right arrow
887 			PostMessage(M_CHANNEL_NEXT);
888 			return B_OK;
889 
890 		case 0x5a:			// numeric keypad page down
891 		case 0x48:			// numeric keypad left arrow
892 			PostMessage(M_CHANNEL_PREV);
893 			return B_OK;
894 	}
895 
896 	return B_ERROR;
897 }
898 
899 
900 void
901 MainWin::DispatchMessage(BMessage *msg, BHandler *handler)
902 {
903 	if ((msg->what == B_MOUSE_DOWN) && (handler == fBackground || handler == fVideoView))
904 		MouseDown(msg);
905 	if ((msg->what == B_MOUSE_MOVED) && (handler == fBackground || handler == fVideoView))
906 		MouseMoved(msg);
907 	if ((msg->what == B_MOUSE_UP) && (handler == fBackground || handler == fVideoView))
908 		MouseUp(msg);
909 
910 	if ((msg->what == B_KEY_DOWN) && (handler == fBackground || handler == fVideoView)) {
911 
912 		// special case for PrintScreen key
913 		if (msg->FindInt32("key") == B_PRINT_KEY) {
914 			fVideoView->OverlayScreenshotPrepare();
915 			BWindow::DispatchMessage(msg, handler);
916 			fVideoView->OverlayScreenshotCleanup();
917 			return;
918 		}
919 
920 		// every other key gets dispatched to our KeyDown first
921 		if (KeyDown(msg) == B_OK) {
922 			// it got handled, don't pass it on
923 			return;
924 		}
925 	}
926 
927 	BWindow::DispatchMessage(msg, handler);
928 }
929 
930 
931 void
932 MainWin::MessageReceived(BMessage *msg)
933 {
934 	switch (msg->what) {
935 		case B_REFS_RECEIVED:
936 			printf("MainWin::MessageReceived: B_REFS_RECEIVED\n");
937 			RefsReceived(msg);
938 			break;
939 		case B_SIMPLE_DATA:
940 			printf("MainWin::MessageReceived: B_SIMPLE_DATA\n");
941 			if (msg->HasRef("refs"))
942 				RefsReceived(msg);
943 			break;
944 		case M_FILE_NEWPLAYER:
945 			gMainApp->NewWindow();
946 			break;
947 		case M_FILE_OPEN:
948 			if (!fFilePanel) {
949 				fFilePanel = new BFilePanel();
950 				fFilePanel->SetTarget(BMessenger(0, this));
951 				fFilePanel->SetPanelDirectory("/boot/home/");
952 			}
953 			fFilePanel->Show();
954 			break;
955 		case M_FILE_INFO:
956 			ShowFileInfo();
957 			break;
958 		case M_FILE_ABOUT:
959 			BAlert *alert;
960 			alert = new BAlert("about", NAME"\n\n Written by Marcus Overhagen","Thanks");
961 			if (fAlwaysOnTop) {
962 				ToggleAlwaysOnTop();
963 				alert->Go();
964 				ToggleAlwaysOnTop();
965 			} else {
966 				alert->Go();
967 			}
968 			break;
969 		case M_FILE_CLOSE:
970 			PostMessage(B_QUIT_REQUESTED);
971 			break;
972 		case M_FILE_QUIT:
973 			be_app->PostMessage(B_QUIT_REQUESTED);
974 			break;
975 
976 		case M_TOGGLE_FULLSCREEN:
977 			ToggleFullscreen();
978 //			fSettingsMenu->ItemAt(1)->SetMarked(fIsFullscreen);
979 			break;
980 
981 		case M_TOGGLE_NO_MENU:
982 			ToggleNoMenu();
983 //			fSettingsMenu->ItemAt(3)->SetMarked(fNoMenu);
984 			break;
985 
986 		case M_TOGGLE_NO_CONTROLS:
987 			ToggleNoControls();
988 //			fSettingsMenu->ItemAt(3)->SetMarked(fNoControls);
989 			break;
990 
991 		case M_TOGGLE_NO_BORDER:
992 			ToggleNoBorder();
993 //			fSettingsMenu->ItemAt(4)->SetMarked(fNoBorder);
994 			break;
995 
996 		case M_TOGGLE_ALWAYS_ON_TOP:
997 			ToggleAlwaysOnTop();
998 //			fSettingsMenu->ItemAt(5)->SetMarked(fAlwaysOnTop);
999 			break;
1000 
1001 		case M_TOGGLE_KEEP_ASPECT_RATIO:
1002 			ToggleKeepAspectRatio();
1003 //			fSettingsMenu->ItemAt(6)->SetMarked(fKeepAspectRatio);
1004 			break;
1005 
1006 		case M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS:
1007 			ToggleNoBorderNoMenu();
1008 			break;
1009 
1010 		case M_VIEW_50:
1011 			if (!fHasVideo)
1012 				break;
1013 			if (fIsFullscreen)
1014 				ToggleFullscreen();
1015 			ResizeWindow(50);
1016 			break;
1017 
1018 		case M_VIEW_100:
1019 			if (!fHasVideo)
1020 				break;
1021 			if (fIsFullscreen)
1022 				ToggleFullscreen();
1023 			ResizeWindow(100);
1024 			break;
1025 
1026 		case M_VIEW_200:
1027 			if (!fHasVideo)
1028 				break;
1029 			if (fIsFullscreen)
1030 				ToggleFullscreen();
1031 			ResizeWindow(200);
1032 			break;
1033 
1034 		case M_VIEW_300:
1035 			if (!fHasVideo)
1036 				break;
1037 			if (fIsFullscreen)
1038 				ToggleFullscreen();
1039 			ResizeWindow(300);
1040 			break;
1041 
1042 		case M_VIEW_400:
1043 			if (!fHasVideo)
1044 				break;
1045 			if (fIsFullscreen)
1046 				ToggleFullscreen();
1047 			ResizeWindow(400);
1048 			break;
1049 
1050 /*
1051 
1052 		case B_ACQUIRE_OVERLAY_LOCK:
1053 			printf("B_ACQUIRE_OVERLAY_LOCK\n");
1054 			fVideoView->OverlayLockAcquire();
1055 			break;
1056 
1057 		case B_RELEASE_OVERLAY_LOCK:
1058 			printf("B_RELEASE_OVERLAY_LOCK\n");
1059 			fVideoView->OverlayLockRelease();
1060 			break;
1061 
1062 		case B_MOUSE_WHEEL_CHANGED:
1063 		{
1064 			printf("B_MOUSE_WHEEL_CHANGED\n");
1065 			float dx = msg->FindFloat("be:wheel_delta_x");
1066 			float dy = msg->FindFloat("be:wheel_delta_y");
1067 			bool inv = modifiers() & B_COMMAND_KEY;
1068 			if (dx > 0.1)	PostMessage(inv ? M_VOLUME_DOWN : M_CHANNEL_PREV);
1069 			if (dx < -0.1)	PostMessage(inv ? M_VOLUME_UP : M_CHANNEL_NEXT);
1070 			if (dy > 0.1)	PostMessage(inv ? M_CHANNEL_PREV : M_VOLUME_DOWN);
1071 			if (dy < -0.1)	PostMessage(inv ? M_CHANNEL_NEXT : M_VOLUME_UP);
1072 			break;
1073 		}
1074 
1075 		case M_CHANNEL_NEXT:
1076 		{
1077 			printf("M_CHANNEL_NEXT\n");
1078 			int chan = fController->CurrentChannel();
1079 			if (chan != -1) {
1080 				chan++;
1081 				if (chan < fController->ChannelCount())
1082 					SelectChannel(chan);
1083 			}
1084 			break;
1085 		}
1086 
1087 		case M_CHANNEL_PREV:
1088 		{
1089 			printf("M_CHANNEL_PREV\n");
1090 			int chan = fController->CurrentChannel();
1091 			if (chan != -1) {
1092 				chan--;
1093 				if (chan >= 0)
1094 					SelectChannel(chan);
1095 			}
1096 			break;
1097 		}
1098 
1099 		case M_VOLUME_UP:
1100 			printf("M_VOLUME_UP\n");
1101 			fController->VolumeUp();
1102 			break;
1103 
1104 		case M_VOLUME_DOWN:
1105 			printf("M_VOLUME_DOWN\n");
1106 			fController->VolumeDown();
1107 			break;
1108 */
1109 
1110 		case M_ASPECT_100000_1:
1111 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.0, 1.0);
1112 			break;
1113 
1114 		case M_ASPECT_106666_1:
1115 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.06666, 1.0);
1116 			break;
1117 
1118 		case M_ASPECT_109091_1:
1119 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.09091, 1.0);
1120 			break;
1121 
1122 		case M_ASPECT_141176_1:
1123 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.41176, 1.0);
1124 			break;
1125 
1126 		case M_ASPECT_720_576:
1127 			VideoFormatChange(720, 576, 1.06666, 1.0);
1128 			break;
1129 
1130 		case M_ASPECT_704_576:
1131 			VideoFormatChange(704, 576, 1.09091, 1.0);
1132 			break;
1133 
1134 		case M_ASPECT_544_576:
1135 			VideoFormatChange(544, 576, 1.41176, 1.0);
1136 			break;
1137 /*
1138 		case M_PREFERENCES:
1139 			break;
1140 
1141 		default:
1142 			if (msg->what >= M_SELECT_CHANNEL && msg->what <= M_SELECT_CHANNEL_END) {
1143 				SelectChannel(msg->what - M_SELECT_CHANNEL);
1144 				break;
1145 			}
1146 			if (msg->what >= M_SELECT_INTERFACE && msg->what <= M_SELECT_INTERFACE_END) {
1147 				SelectInterface(msg->what - M_SELECT_INTERFACE - 1);
1148 				break;
1149 			}
1150 */
1151 	}
1152 }
1153