xref: /haiku/src/apps/mediaplayer/MainWin.cpp (revision 09464bc90b61f0c038cd92e3894921c64caedf9a)
1 /*
2  * MainWin.cpp - Media Player for the Haiku Operating System
3  *
4  * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
5  * Copyright (C) 2007 Stephan Aßmus <superstippi@gmx.de>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  */
21 #include "MainWin.h"
22 
23 #include <math.h>
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include <Alert.h>
28 #include <Application.h>
29 #include <Autolock.h>
30 #include <Debug.h>
31 #include <Menu.h>
32 #include <MenuBar.h>
33 #include <MenuItem.h>
34 #include <Messenger.h>
35 #include <PopUpMenu.h>
36 #include <Screen.h>
37 #include <String.h>
38 #include <View.h>
39 
40 #include "ControllerObserver.h"
41 #include "MainApp.h"
42 #include "PlaylistObserver.h"
43 #include "PlaylistWindow.h"
44 
45 #define NAME "MediaPlayer"
46 #define MIN_WIDTH 250
47 
48 
49 // XXX TODO: why is lround not defined?
50 #define lround(a) ((int)(0.99999 + (a)))
51 
52 enum {
53 	M_DUMMY = 0x100,
54 	M_FILE_OPEN = 0x1000,
55 	M_FILE_NEWPLAYER,
56 	M_FILE_INFO,
57 	M_FILE_PLAYLIST,
58 	M_FILE_CLOSE,
59 	M_FILE_QUIT,
60 	M_VIEW_50,
61 	M_VIEW_100,
62 	M_VIEW_200,
63 	M_VIEW_300,
64 	M_VIEW_400,
65 	M_TOGGLE_FULLSCREEN,
66 	M_TOGGLE_NO_BORDER,
67 	M_TOGGLE_NO_MENU,
68 	M_TOGGLE_NO_CONTROLS,
69 	M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS,
70 	M_TOGGLE_ALWAYS_ON_TOP,
71 	M_TOGGLE_KEEP_ASPECT_RATIO,
72 	M_PREFERENCES,
73 	M_VOLUME_UP,
74 	M_VOLUME_DOWN,
75 	M_CHANNEL_NEXT,
76 	M_CHANNEL_PREV,
77 	M_ASPECT_100000_1,
78 	M_ASPECT_106666_1,
79 	M_ASPECT_109091_1,
80 	M_ASPECT_141176_1,
81 	M_ASPECT_720_576,
82 	M_ASPECT_704_576,
83 	M_ASPECT_544_576,
84 	M_SELECT_AUDIO_TRACK		= 0x00000800,
85 	M_SELECT_AUDIO_TRACK_END	= 0x00000fff,
86 	M_SELECT_VIDEO_TRACK		= 0x00010000,
87 	M_SELECT_VIDEO_TRACK_END	= 0x000fffff,
88 
89 	M_SET_PLAYLIST_POSITION
90 };
91 
92 //#define printf(a...)
93 
94 
95 MainWin::MainWin()
96  :	BWindow(BRect(100,100,350,300), NAME, B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS /* | B_WILL_ACCEPT_FIRST_CLICK */)
97  ,  fFilePanel(NULL)
98  ,	fInfoWin(NULL)
99  ,	fPlaylistWindow(NULL)
100  ,	fHasFile(false)
101  ,	fHasVideo(false)
102  ,	fHasAudio(false)
103  ,	fPlaylist(new Playlist)
104  ,	fPlaylistObserver(new PlaylistObserver(this))
105  ,	fController(new Controller)
106  ,	fControllerObserver(new ControllerObserver(this,
107  		OBSERVE_FILE_CHANGES | OBSERVE_TRACK_CHANGES
108  			| OBSERVE_PLAYBACK_STATE_CHANGES | OBSERVE_POSITION_CHANGES))
109  ,	fIsFullscreen(false)
110  ,	fKeepAspectRatio(true)
111  ,	fAlwaysOnTop(false)
112  ,	fNoMenu(false)
113  ,	fNoBorder(false)
114  ,	fNoControls(false)
115  ,	fSourceWidth(0)
116  ,	fSourceHeight(0)
117  ,	fWidthScale(1.0)
118  ,	fHeightScale(1.0)
119  ,	fMouseDownTracking(false)
120 {
121 	static int pos = 0;
122 	MoveBy(pos * 25, pos * 25);
123 	pos = (pos + 1) % 15;
124 
125 	BRect rect = Bounds();
126 
127 	// background
128 	fBackground = new BView(rect, "background", B_FOLLOW_ALL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
129 	fBackground->SetViewColor(0,0,0);
130 	AddChild(fBackground);
131 
132 	// menu
133 	fMenuBar = new BMenuBar(fBackground->Bounds(), "menu");
134 	_CreateMenu();
135 	fBackground->AddChild(fMenuBar);
136 	fMenuBar->ResizeToPreferred();
137 	fMenuBarWidth = (int)fMenuBar->Frame().Width() + 1;
138 	fMenuBarHeight = (int)fMenuBar->Frame().Height() + 1;
139 	fMenuBar->SetResizingMode(B_FOLLOW_NONE);
140 
141 	// video view
142 	rect = BRect(0, fMenuBarHeight, fBackground->Bounds().right, fMenuBarHeight + 10);
143 	fVideoView = new VideoView(rect, "video display", B_FOLLOW_NONE, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
144 	fBackground->AddChild(fVideoView);
145 
146 	// controls
147 	rect = BRect(0, fMenuBarHeight + 11, fBackground->Bounds().right, fBackground->Bounds().bottom);
148 	fControls = new ControllerView(rect, fController, fPlaylist);
149 	fBackground->AddChild(fControls);
150 	fControls->ResizeToPreferred();
151 	fControlsHeight = (int)fControls->Frame().Height() + 1;
152 	fControlsWidth = (int)fControls->Frame().Width() + 1;
153 	fControls->SetResizingMode(B_FOLLOW_BOTTOM | B_FOLLOW_LEFT_RIGHT);
154 //	fControls->MoveTo(0, fBackground->Bounds().bottom - fControlsHeight + 1);
155 
156 //	fVideoView->ResizeTo(fBackground->Bounds().Width(), fBackground->Bounds().Height() - fMenuBarHeight - fControlsHeight);
157 
158 	fPlaylist->AddListener(fPlaylistObserver);
159 	fController->SetVideoView(fVideoView);
160 	fController->AddListener(fControllerObserver);
161 	fVideoView->IsOverlaySupported();
162 
163 //	printf("fMenuBarHeight %d\n", fMenuBarHeight);
164 //	printf("fControlsHeight %d\n", fControlsHeight);
165 //	printf("fControlsWidth %d\n", fControlsWidth);
166 
167 	_SetupWindow();
168 
169 	Show();
170 }
171 
172 
173 MainWin::~MainWin()
174 {
175 	printf("MainWin::~MainWin\n");
176 
177 	fPlaylist->RemoveListener(fPlaylistObserver);
178 	fController->RemoveListener(fControllerObserver);
179 
180 	// give the views a chance to detach from any notifiers
181 	// before we delete them
182 	fBackground->RemoveSelf();
183 	delete fBackground;
184 
185 	if (fInfoWin) {
186 		fInfoWin->Lock();
187 		fInfoWin->Quit();
188 	}
189 	if (fPlaylistWindow) {
190 		fPlaylistWindow->Lock();
191 		fPlaylistWindow->Quit();
192 	}
193 
194 	delete fPlaylist;
195 	delete fController;
196 	delete fFilePanel;
197 }
198 
199 
200 // #pragma mark -
201 
202 
203 void
204 MainWin::FrameResized(float new_width, float new_height)
205 {
206 	if (new_width != Bounds().Width() || new_height != Bounds().Height()) {
207 		debugger("size wrong\n");
208 	}
209 
210 	bool no_menu = fNoMenu || fIsFullscreen;
211 	bool no_controls = fNoControls || fIsFullscreen;
212 
213 	printf("FrameResized enter: new_width %.0f, new_height %.0f\n", new_width, new_height);
214 
215 	int max_video_width  = int(new_width) + 1;
216 	int max_video_height = int(new_height) + 1 - (no_menu  ? 0 : fMenuBarHeight) - (no_controls ? 0 : fControlsHeight);
217 
218 	ASSERT(max_video_height >= 0);
219 
220 	int y = 0;
221 
222 	if (no_menu) {
223 		if (!fMenuBar->IsHidden())
224 			fMenuBar->Hide();
225 	} else {
226 //		fMenuBar->MoveTo(0, y);
227 		fMenuBar->ResizeTo(new_width, fMenuBarHeight - 1);
228 		if (fMenuBar->IsHidden())
229 			fMenuBar->Show();
230 		y += fMenuBarHeight;
231 	}
232 
233 	if (max_video_height == 0) {
234 		if (!fVideoView->IsHidden())
235 			fVideoView->Hide();
236 	} else {
237 //		fVideoView->MoveTo(0, y);
238 //		fVideoView->ResizeTo(max_video_width - 1, max_video_height - 1);
239 		_ResizeVideoView(0, y, max_video_width, max_video_height);
240 		if (fVideoView->IsHidden())
241 			fVideoView->Show();
242 		y += max_video_height;
243 	}
244 
245 	if (no_controls) {
246 		if (!fControls->IsHidden())
247 			fControls->Hide();
248 	} else {
249 		fControls->MoveTo(0, y);
250 		fControls->ResizeTo(new_width, fControlsHeight - 1);
251 		if (fControls->IsHidden())
252 			fControls->Show();
253 //		y += fControlsHeight;
254 	}
255 
256 	printf("FrameResized leave\n");
257 }
258 
259 
260 void
261 MainWin::Zoom(BPoint rec_position, float rec_width, float rec_height)
262 {
263 	PostMessage(M_TOGGLE_FULLSCREEN);
264 }
265 
266 
267 void
268 MainWin::DispatchMessage(BMessage *msg, BHandler *handler)
269 {
270 	if ((msg->what == B_MOUSE_DOWN)
271 		&& (handler == fBackground || handler == fVideoView
272 				|| handler == fControls))
273 		_MouseDown(msg, dynamic_cast<BView*>(handler));
274 
275 	if ((msg->what == B_MOUSE_MOVED)
276 		&& (handler == fBackground || handler == fVideoView
277 				|| handler == fControls))
278 		_MouseMoved(msg, dynamic_cast<BView*>(handler));
279 
280 	if ((msg->what == B_MOUSE_UP)
281 		&& (handler == fBackground || handler == fVideoView))
282 		_MouseUp(msg);
283 
284 	if ((msg->what == B_KEY_DOWN)
285 		&& (handler == fBackground || handler == fVideoView)) {
286 
287 		// special case for PrintScreen key
288 		if (msg->FindInt32("key") == B_PRINT_KEY) {
289 			fVideoView->OverlayScreenshotPrepare();
290 			BWindow::DispatchMessage(msg, handler);
291 			fVideoView->OverlayScreenshotCleanup();
292 			return;
293 		}
294 
295 		// every other key gets dispatched to our _KeyDown first
296 		if (_KeyDown(msg) == B_OK) {
297 			// it got handled, don't pass it on
298 			return;
299 		}
300 	}
301 
302 	BWindow::DispatchMessage(msg, handler);
303 }
304 
305 
306 void
307 MainWin::MessageReceived(BMessage *msg)
308 {
309 	switch (msg->what) {
310 		case B_REFS_RECEIVED:
311 			printf("MainWin::MessageReceived: B_REFS_RECEIVED\n");
312 			_RefsReceived(msg);
313 			break;
314 		case B_SIMPLE_DATA:
315 			printf("MainWin::MessageReceived: B_SIMPLE_DATA\n");
316 			if (msg->HasRef("refs"))
317 				_RefsReceived(msg);
318 			break;
319 
320 		// PlaylistObserver messages
321 		case MSG_PLAYLIST_REF_ADDED: {
322 			entry_ref ref;
323 			int32 index;
324 			if (msg->FindRef("refs", &ref) == B_OK
325 				&& msg->FindInt32("index", &index) == B_OK) {
326 				_AddPlaylistItem(ref, index);
327 			}
328 			break;
329 		}
330 		case MSG_PLAYLIST_REF_REMOVED: {
331 			int32 index;
332 			if (msg->FindInt32("index", &index) == B_OK) {
333 				_RemovePlaylistItem(index);
334 			}
335 			break;
336 		}
337 		case MSG_PLAYLIST_CURRENT_REF_CHANGED: {
338 			BAutolock _(fPlaylist);
339 
340 			int32 index;
341 			if (msg->FindInt32("index", &index) < B_OK
342 				|| index != fPlaylist->CurrentRefIndex())
343 				break;
344 			entry_ref ref;
345 			if (fPlaylist->GetRefAt(index, &ref) == B_OK) {
346 				printf("open ref: %s\n", ref.name);
347 				OpenFile(ref);
348 				_MarkPlaylistItem(index);
349 			}
350 			break;
351 		}
352 
353 		// ControllerObserver messages
354 		case MSG_CONTROLLER_FILE_FINISHED:
355 			fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() + 1);
356 			break;
357 		case MSG_CONTROLLER_FILE_CHANGED:
358 			// TODO: move all other GUI changes as a reaction to this notification
359 //			_UpdatePlaylistMenu();
360 			break;
361 		case MSG_CONTROLLER_VIDEO_TRACK_CHANGED: {
362 			int32 index;
363 			if (msg->FindInt32("index", &index) == B_OK) {
364 				BMenuItem* item = fVideoTrackMenu->ItemAt(index);
365 				if (item)
366 					item->SetMarked(true);
367 			}
368 			break;
369 		}
370 		case MSG_CONTROLLER_AUDIO_TRACK_CHANGED: {
371 			int32 index;
372 			if (msg->FindInt32("index", &index) == B_OK) {
373 				BMenuItem* item = fAudioTrackMenu->ItemAt(index);
374 				if (item)
375 					item->SetMarked(true);
376 			}
377 			break;
378 		}
379 		case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED: {
380 			uint32 state;
381 			if (msg->FindInt32("state", (int32*)&state) == B_OK)
382 				fControls->SetPlaybackState(state);
383 			break;
384 		}
385 		case MSG_CONTROLLER_POSITION_CHANGED: {
386 			float position;
387 			if (msg->FindFloat("position", &position) == B_OK)
388 				fControls->SetPosition(position);
389 			break;
390 		}
391 
392 		// menu item messages
393 		case M_FILE_NEWPLAYER:
394 			gMainApp->NewWindow();
395 			break;
396 		case M_FILE_OPEN:
397 			if (!fFilePanel) {
398 				fFilePanel = new BFilePanel();
399 				fFilePanel->SetTarget(BMessenger(0, this));
400 				fFilePanel->SetPanelDirectory("/boot/home/");
401 			}
402 			fFilePanel->Show();
403 			break;
404 		case M_FILE_INFO:
405 			ShowFileInfo();
406 			break;
407 		case M_FILE_PLAYLIST:
408 			ShowPlaylistWindow();
409 			break;
410 		case B_ABOUT_REQUESTED:
411 			BAlert *alert;
412 			alert = new BAlert("about", NAME"\n\n Written by Marcus Overhagen "
413 				"and Stephan Aßmus", "Thanks");
414 			if (fAlwaysOnTop) {
415 				_ToggleAlwaysOnTop();
416 				alert->Go();
417 				_ToggleAlwaysOnTop();
418 			} else {
419 				alert->Go();
420 			}
421 			break;
422 		case M_FILE_CLOSE:
423 			PostMessage(B_QUIT_REQUESTED);
424 			break;
425 		case M_FILE_QUIT:
426 			be_app->PostMessage(B_QUIT_REQUESTED);
427 			break;
428 
429 		case M_TOGGLE_FULLSCREEN:
430 			_ToggleFullscreen();
431 //			fSettingsMenu->ItemAt(1)->SetMarked(fIsFullscreen);
432 			break;
433 
434 		case M_TOGGLE_NO_MENU:
435 			_ToggleNoMenu();
436 //			fSettingsMenu->ItemAt(3)->SetMarked(fNoMenu);
437 			break;
438 
439 		case M_TOGGLE_NO_CONTROLS:
440 			_ToggleNoControls();
441 //			fSettingsMenu->ItemAt(3)->SetMarked(fNoControls);
442 			break;
443 
444 		case M_TOGGLE_NO_BORDER:
445 			_ToggleNoBorder();
446 //			fSettingsMenu->ItemAt(4)->SetMarked(fNoBorder);
447 			break;
448 
449 		case M_TOGGLE_ALWAYS_ON_TOP:
450 			_ToggleAlwaysOnTop();
451 //			fSettingsMenu->ItemAt(5)->SetMarked(fAlwaysOnTop);
452 			break;
453 
454 		case M_TOGGLE_KEEP_ASPECT_RATIO:
455 			_ToggleKeepAspectRatio();
456 //			fSettingsMenu->ItemAt(6)->SetMarked(fKeepAspectRatio);
457 			break;
458 
459 		case M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS:
460 			_ToggleNoBorderNoMenu();
461 			break;
462 
463 		case M_VIEW_50:
464 			if (!fHasVideo)
465 				break;
466 			if (fIsFullscreen)
467 				_ToggleFullscreen();
468 			_ResizeWindow(50);
469 			break;
470 
471 		case M_VIEW_100:
472 			if (!fHasVideo)
473 				break;
474 			if (fIsFullscreen)
475 				_ToggleFullscreen();
476 			_ResizeWindow(100);
477 			break;
478 
479 		case M_VIEW_200:
480 			if (!fHasVideo)
481 				break;
482 			if (fIsFullscreen)
483 				_ToggleFullscreen();
484 			_ResizeWindow(200);
485 			break;
486 
487 		case M_VIEW_300:
488 			if (!fHasVideo)
489 				break;
490 			if (fIsFullscreen)
491 				_ToggleFullscreen();
492 			_ResizeWindow(300);
493 			break;
494 
495 		case M_VIEW_400:
496 			if (!fHasVideo)
497 				break;
498 			if (fIsFullscreen)
499 				_ToggleFullscreen();
500 			_ResizeWindow(400);
501 			break;
502 
503 /*
504 
505 		case B_ACQUIRE_OVERLAY_LOCK:
506 			printf("B_ACQUIRE_OVERLAY_LOCK\n");
507 			fVideoView->OverlayLockAcquire();
508 			break;
509 
510 		case B_RELEASE_OVERLAY_LOCK:
511 			printf("B_RELEASE_OVERLAY_LOCK\n");
512 			fVideoView->OverlayLockRelease();
513 			break;
514 
515 		case B_MOUSE_WHEEL_CHANGED:
516 		{
517 			printf("B_MOUSE_WHEEL_CHANGED\n");
518 			float dx = msg->FindFloat("be:wheel_delta_x");
519 			float dy = msg->FindFloat("be:wheel_delta_y");
520 			bool inv = modifiers() & B_COMMAND_KEY;
521 			if (dx > 0.1)	PostMessage(inv ? M_VOLUME_DOWN : M_CHANNEL_PREV);
522 			if (dx < -0.1)	PostMessage(inv ? M_VOLUME_UP : M_CHANNEL_NEXT);
523 			if (dy > 0.1)	PostMessage(inv ? M_CHANNEL_PREV : M_VOLUME_DOWN);
524 			if (dy < -0.1)	PostMessage(inv ? M_CHANNEL_NEXT : M_VOLUME_UP);
525 			break;
526 		}
527 
528 		case M_CHANNEL_NEXT:
529 		{
530 			printf("M_CHANNEL_NEXT\n");
531 			int chan = fController->CurrentChannel();
532 			if (chan != -1) {
533 				chan++;
534 				if (chan < fController->ChannelCount())
535 					SelectChannel(chan);
536 			}
537 			break;
538 		}
539 
540 		case M_CHANNEL_PREV:
541 		{
542 			printf("M_CHANNEL_PREV\n");
543 			int chan = fController->CurrentChannel();
544 			if (chan != -1) {
545 				chan--;
546 				if (chan >= 0)
547 					SelectChannel(chan);
548 			}
549 			break;
550 		}
551 
552 		case M_VOLUME_UP:
553 			printf("M_VOLUME_UP\n");
554 			fController->VolumeUp();
555 			break;
556 
557 		case M_VOLUME_DOWN:
558 			printf("M_VOLUME_DOWN\n");
559 			fController->VolumeDown();
560 			break;
561 */
562 
563 		case M_ASPECT_100000_1:
564 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.0, 1.0);
565 			break;
566 
567 		case M_ASPECT_106666_1:
568 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.06666, 1.0);
569 			break;
570 
571 		case M_ASPECT_109091_1:
572 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.09091, 1.0);
573 			break;
574 
575 		case M_ASPECT_141176_1:
576 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.41176, 1.0);
577 			break;
578 
579 		case M_ASPECT_720_576:
580 			VideoFormatChange(720, 576, 1.06666, 1.0);
581 			break;
582 
583 		case M_ASPECT_704_576:
584 			VideoFormatChange(704, 576, 1.09091, 1.0);
585 			break;
586 
587 		case M_ASPECT_544_576:
588 			VideoFormatChange(544, 576, 1.41176, 1.0);
589 			break;
590 /*
591 		case M_PREFERENCES:
592 			break;
593 
594 		default:
595 			if (msg->what >= M_SELECT_CHANNEL && msg->what <= M_SELECT_CHANNEL_END) {
596 				SelectChannel(msg->what - M_SELECT_CHANNEL);
597 				break;
598 			}
599 			if (msg->what >= M_SELECT_INTERFACE && msg->what <= M_SELECT_INTERFACE_END) {
600 				SelectInterface(msg->what - M_SELECT_INTERFACE - 1);
601 				break;
602 			}
603 */
604 		case M_SET_PLAYLIST_POSITION: {
605 			int32 index;
606 			if (msg->FindInt32("index", &index) == B_OK)
607 				fPlaylist->SetCurrentRefIndex(index);
608 			break;
609 		}
610 
611 		default:
612 			// let BWindow handle the rest
613 			BWindow::MessageReceived(msg);
614 	}
615 }
616 
617 
618 bool
619 MainWin::QuitRequested()
620 {
621 	be_app->PostMessage(M_PLAYER_QUIT);
622 	return true;
623 }
624 
625 
626 // #pragma mark -
627 
628 
629 void
630 MainWin::OpenFile(const entry_ref &ref)
631 {
632 	printf("MainWin::OpenFile\n");
633 
634 	status_t err = fController->SetTo(ref);
635 	if (err != B_OK) {
636 		if (fPlaylist->CountItems() == 1) {
637 			// display error if this is the only file we're supposed to play
638 			char s[300];
639 			sprintf(s, "Can't open file\n\n%s\n\nError 0x%08lx\n(%s)\n",
640 				ref.name, err, strerror(err));
641 			(new BAlert("error", s, "OK"))->Go();
642 		} else {
643 			// just go to the next file and don't bother user
644 			// TODO: this makes it impossible to skip backwards
645 			// over a non recognized file!
646 			fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() + 1);
647 		}
648 		fHasFile = false;
649 		fHasVideo = false;
650 		fHasAudio = false;
651 		SetTitle(NAME);
652 	} else {
653 		fHasFile = true;
654 		fHasVideo = fController->VideoTrackCount() != 0;
655 		fHasAudio = fController->AudioTrackCount() != 0;
656 		SetTitle(ref.name);
657 	}
658 	_SetupWindow();
659 }
660 
661 void
662 MainWin::ShowFileInfo()
663 {
664 	if (!fInfoWin)
665 		fInfoWin = new InfoWin(Frame().LeftTop(), fController);
666 
667 	if (fInfoWin->Lock()) {
668 		if (fInfoWin->IsHidden())
669 			fInfoWin->Show();
670 		else
671 			fInfoWin->Activate();
672 		fInfoWin->Unlock();
673 	}
674 
675 	BMessenger msgr(fInfoWin);
676 	BMessage m(M_UPDATE_INFO);
677 	m.AddInt32("which", INFO_ALL);
678 	msgr.SendMessage(&m);
679 	msgr.SendMessage(B_WINDOW_ACTIVATED);
680 }
681 
682 
683 void
684 MainWin::ShowPlaylistWindow()
685 {
686 	if (!fPlaylistWindow) {
687 		fPlaylistWindow = new PlaylistWindow(BRect(150, 150, 400, 500),
688 			fPlaylist, fController);
689 		fPlaylistWindow->Show();
690 		return;
691 	}
692 
693 	if (fPlaylistWindow->Lock()) {
694 		if (fPlaylistWindow->IsHidden())
695 			fPlaylistWindow->Show();
696 		else
697 			fPlaylistWindow->Activate();
698 		fPlaylistWindow->Unlock();
699 	}
700 }
701 
702 
703 void
704 MainWin::VideoFormatChange(int width, int height, float width_scale, float height_scale)
705 {
706 	// called when video format or aspect ratio changes
707 
708 	printf("VideoFormatChange enter: width %d, height %d, width_scale %.6f, height_scale %.6f\n", width, height, width_scale, height_scale);
709 
710 	if (width_scale < 1.0 && height_scale >= 1.0) {
711 		width_scale  = 1.0 / width_scale;
712 		height_scale = 1.0 / height_scale;
713 		printf("inverting! new values: width_scale %.6f, height_scale %.6f\n", width_scale, height_scale);
714 	}
715 
716  	fSourceWidth  = width;
717  	fSourceHeight = height;
718  	fWidthScale   = width_scale;
719  	fHeightScale  = height_scale;
720 
721  	FrameResized(Bounds().Width(), Bounds().Height());
722 
723 	printf("VideoFormatChange leave\n");
724 }
725 
726 
727 // #pragma mark -
728 
729 
730 void
731 MainWin::_RefsReceived(BMessage *msg)
732 {
733 	// the playlist ist replaced by dropped files
734 	// or the dropped files are appended to the end
735 	// of the existing playlist if <shift> is pressed
736 	int32 appendIndex = modifiers() & B_SHIFT_KEY ?
737 		fPlaylist->CountItems() : -1;
738 
739 	fPlaylist->AppendRefs(msg, appendIndex);
740 }
741 
742 
743 void
744 MainWin::_SetupWindow()
745 {
746 	printf("MainWin::_SetupWindow\n");
747 
748 	// Populate the track menus
749 	_SetupTrackMenus();
750 	// Enable both if a file was loaded
751 	fAudioTrackMenu->SetEnabled(fHasFile);
752 	fVideoTrackMenu->SetEnabled(fHasFile);
753 	// Select first track (might be "none") in both
754 	fAudioTrackMenu->ItemAt(0)->SetMarked(true);
755 	fVideoTrackMenu->ItemAt(0)->SetMarked(true);
756 
757 	fVideoMenu->SetEnabled(fHasVideo);
758 	fAudioMenu->SetEnabled(fHasAudio);
759 	fDebugMenu->SetEnabled(fHasVideo);
760 
761 	if (fHasVideo) {
762 		fController->GetSize(&fSourceWidth, &fSourceHeight);
763 		fWidthScale = 1.0;
764 		fHeightScale = 1.0;
765 	} else {
766 		fSourceWidth = 0;
767 		fSourceHeight = 0;
768 		fWidthScale = 1.0;
769 		fHeightScale = 1.0;
770 	}
771 
772 	_UpdateControlsEnabledStatus();
773 
774 	_ResizeWindow(100);
775 
776 	fVideoView->MakeFocus();
777 }
778 
779 
780 void
781 MainWin::_CreateMenu()
782 {
783 	fFileMenu = new BMenu(NAME);
784 	fPlaylistMenu = new BMenu("Playlist"B_UTF8_ELLIPSIS);
785 	fAudioMenu = new BMenu("Audio");
786 	fVideoMenu = new BMenu("Video");
787 	fSettingsMenu = new BMenu("Settings");
788 	fAudioTrackMenu = new BMenu("Track");
789 	fVideoTrackMenu = new BMenu("Track");
790 	fDebugMenu = new BMenu("Debug");
791 
792 	fMenuBar->AddItem(fFileMenu);
793 	fMenuBar->AddItem(fAudioMenu);
794 	fMenuBar->AddItem(fVideoMenu);
795 	fMenuBar->AddItem(fSettingsMenu);
796 //	fMenuBar->AddItem(fDebugMenu);
797 
798 	fFileMenu->AddItem(new BMenuItem("New Player"B_UTF8_ELLIPSIS, new BMessage(M_FILE_NEWPLAYER), 'N', B_COMMAND_KEY));
799 	fFileMenu->AddSeparatorItem();
800 	fFileMenu->AddItem(new BMenuItem("Open File"B_UTF8_ELLIPSIS, new BMessage(M_FILE_OPEN), 'O', B_COMMAND_KEY));
801 	fFileMenu->AddItem(new BMenuItem("File Info"B_UTF8_ELLIPSIS, new BMessage(M_FILE_INFO), 'I', B_COMMAND_KEY));
802 	fFileMenu->AddItem(fPlaylistMenu);
803 	fPlaylistMenu->Superitem()->SetShortcut('P', B_COMMAND_KEY);
804 	fPlaylistMenu->Superitem()->SetMessage(new BMessage(M_FILE_PLAYLIST));
805 
806 	fFileMenu->AddSeparatorItem();
807 	fFileMenu->AddItem(new BMenuItem("About" NAME B_UTF8_ELLIPSIS,
808 		new BMessage(B_ABOUT_REQUESTED)));
809 	fFileMenu->AddSeparatorItem();
810 	fFileMenu->AddItem(new BMenuItem("Close", new BMessage(M_FILE_CLOSE), 'W', B_COMMAND_KEY));
811 	fFileMenu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q', B_COMMAND_KEY));
812 
813 	fPlaylistMenu->SetRadioMode(true);
814 
815 	fAudioMenu->AddItem(fAudioTrackMenu);
816 
817 	fVideoMenu->AddItem(fVideoTrackMenu);
818 	fVideoMenu->AddSeparatorItem();
819 	fVideoMenu->AddItem(new BMenuItem("50% scale", new BMessage(M_VIEW_50), '0', B_COMMAND_KEY));
820 	fVideoMenu->AddItem(new BMenuItem("100% scale", new BMessage(M_VIEW_100), '1', B_COMMAND_KEY));
821 	fVideoMenu->AddItem(new BMenuItem("200% scale", new BMessage(M_VIEW_200), '2', B_COMMAND_KEY));
822 	fVideoMenu->AddItem(new BMenuItem("300% scale", new BMessage(M_VIEW_300), '3', B_COMMAND_KEY));
823 	fVideoMenu->AddItem(new BMenuItem("400% scale", new BMessage(M_VIEW_400), '4', B_COMMAND_KEY));
824 	fVideoMenu->AddSeparatorItem();
825 	fVideoMenu->AddItem(new BMenuItem("Full Screen", new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
826 	fVideoMenu->AddItem(new BMenuItem("Keep Aspect Ratio", new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
827 
828 	fSettingsMenu->AddItem(new BMenuItem("No Menu", new BMessage(M_TOGGLE_NO_MENU), 'M', B_COMMAND_KEY));
829 	fSettingsMenu->AddItem(new BMenuItem("No Border", new BMessage(M_TOGGLE_NO_BORDER), 'B', B_COMMAND_KEY));
830 	fSettingsMenu->AddItem(new BMenuItem("No Controls", new BMessage(M_TOGGLE_NO_CONTROLS), 'C', B_COMMAND_KEY));
831 	fSettingsMenu->AddItem(new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
832 //	fSettingsMenu->AddSeparatorItem();
833 //	fSettingsMenu->AddItem(new BMenuItem("Preferences"B_UTF8_ELLIPSIS, new BMessage(M_PREFERENCES), 'P', B_COMMAND_KEY));
834 
835 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", new BMessage(M_ASPECT_100000_1)));
836 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", new BMessage(M_ASPECT_106666_1)));
837 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.09091:1", new BMessage(M_ASPECT_109091_1)));
838 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.41176:1", new BMessage(M_ASPECT_141176_1)));
839 	fDebugMenu->AddItem(new BMenuItem("force 720 x 576, display aspect 4:3", new BMessage(M_ASPECT_720_576)));
840 	fDebugMenu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", new BMessage(M_ASPECT_704_576)));
841 	fDebugMenu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", new BMessage(M_ASPECT_544_576)));
842 
843 	fAudioTrackMenu->SetRadioMode(true);
844 	fVideoTrackMenu->SetRadioMode(true);
845 /*
846 	fSettingsMenu->ItemAt(3)->SetMarked(fIsFullscreen);
847 	fSettingsMenu->ItemAt(5)->SetMarked(fNoMenu);
848 	fSettingsMenu->ItemAt(6)->SetMarked(fNoBorder);
849 	fSettingsMenu->ItemAt(7)->SetMarked(fAlwaysOnTop);
850 	fSettingsMenu->ItemAt(8)->SetMarked(fKeepAspectRatio);
851 	fSettingsMenu->ItemAt(10)->SetEnabled(false); // XXX disable unused preference menu
852 */
853 }
854 
855 
856 void
857 MainWin::_SetupTrackMenus()
858 {
859 	fAudioTrackMenu->RemoveItems(0, fAudioTrackMenu->CountItems(), true);
860 	fVideoTrackMenu->RemoveItems(0, fVideoTrackMenu->CountItems(), true);
861 
862 	int c, i;
863 	char s[100];
864 
865 	c = fController->AudioTrackCount();
866 	for (i = 0; i < c; i++) {
867 		sprintf(s, "Track %d", i + 1);
868 		fAudioTrackMenu->AddItem(new BMenuItem(s, new BMessage(M_SELECT_AUDIO_TRACK + i)));
869 	}
870 	if (!c)
871 		fAudioTrackMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY)));
872 
873 	c = fController->VideoTrackCount();
874 	for (i = 0; i < c; i++) {
875 		sprintf(s, "Track %d", i + 1);
876 		fVideoTrackMenu->AddItem(new BMenuItem(s, new BMessage(M_SELECT_VIDEO_TRACK + i)));
877 	}
878 	if (!c)
879 		fVideoTrackMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY)));
880 }
881 
882 
883 void
884 MainWin::_SetWindowSizeLimits()
885 {
886 	int minWidth = fNoControls  ? MIN_WIDTH : fControlsWidth;
887 	if (!fNoMenu)
888 		minWidth = max_c(minWidth, fMenuBarWidth);
889 	int minHeight = (fNoMenu ? 0 : fMenuBarHeight) + (fNoControls ? 0 : fControlsHeight);
890 
891 	SetSizeLimits(minWidth - 1, 32000, minHeight - 1, fHasVideo ? 32000 : minHeight - 1);
892 }
893 
894 
895 void
896 MainWin::_ResizeWindow(int percent)
897 {
898 	int video_width;
899 	int video_height;
900 
901 	// Get required window size
902 	video_width = lround(fSourceWidth * fWidthScale);
903 	video_height = lround(fSourceHeight * fHeightScale);
904 
905 	video_width = (video_width * percent) / 100;
906 	video_height = (video_height * percent) / 100;
907 
908 	// Calculate and set the initial window size
909 	int width = max_c(fControlsWidth, video_width);
910 	int height = (fNoControls ? 0 : fControlsHeight) + video_height;
911 	if (!fNoMenu) {
912 		width = max_c(width, fMenuBarWidth);
913 		height += fMenuBarHeight;
914 	}
915 	_SetWindowSizeLimits();
916 	ResizeTo(width - 1, height - 1);
917 }
918 
919 
920 void
921 MainWin::_ResizeVideoView(int x, int y, int width, int height)
922 {
923 	printf("_ResizeVideoView: %d,%d, width %d, height %d\n", x, y, width, height);
924 
925 	if (fKeepAspectRatio) {
926 		// Keep aspect ratio, place video view inside
927 		// the background area (may create black bars).
928 		float scaled_width  = fSourceWidth * fWidthScale;
929 		float scaled_height = fSourceHeight * fHeightScale;
930 		float factor = min_c(width / scaled_width, height / scaled_height);
931 		int render_width = lround(scaled_width * factor);
932 		int render_height = lround(scaled_height * factor);
933 		if (render_width > width)
934 			render_width = width;
935 		if (render_height > height)
936 			render_height = height;
937 
938 		int x_ofs = x + (width - render_width) / 2;
939 		int y_ofs = y + (height - render_height) / 2;
940 
941 		fVideoView->MoveTo(x_ofs, y_ofs);
942 		fVideoView->ResizeTo(render_width - 1, render_height - 1);
943 
944 	} else {
945 		fVideoView->MoveTo(x, y);
946 		fVideoView->ResizeTo(width - 1, height - 1);
947 	}
948 }
949 
950 
951 // #pragma mark -
952 
953 
954 void
955 MainWin::_MouseDown(BMessage *msg, BView* originalHandler)
956 {
957 	BPoint screen_where;
958 	uint32 buttons = msg->FindInt32("buttons");
959 
960 	// On Zeta, only "screen_where" is relyable, "where" and "be:view_where" seem to be broken
961 	if (B_OK != msg->FindPoint("screen_where", &screen_where)) {
962 		// Workaround for BeOS R5, it has no "screen_where"
963 		if (!originalHandler || msg->FindPoint("where", &screen_where) < B_OK)
964 			return;
965 		originalHandler->ConvertToScreen(&screen_where);
966 	}
967 
968 //	msg->PrintToStream();
969 
970 //	if (1 == msg->FindInt32("buttons") && msg->FindInt32("clicks") == 1) {
971 
972 	if (1 == buttons && msg->FindInt32("clicks") % 2 == 0) {
973 		BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1, screen_where.y + 1);
974 		if (r.Contains(fMouseDownMousePos)) {
975 			PostMessage(M_TOGGLE_FULLSCREEN);
976 			return;
977 		}
978 	}
979 
980 	if (2 == buttons && msg->FindInt32("clicks") % 2 == 0) {
981 		BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1, screen_where.y + 1);
982 		if (r.Contains(fMouseDownMousePos)) {
983 			PostMessage(M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS);
984 			return;
985 		}
986 	}
987 
988 /*
989 		// very broken in Zeta:
990 		fMouseDownMousePos = fVideoView->ConvertToScreen(msg->FindPoint("where"));
991 */
992 	fMouseDownMousePos = screen_where;
993 	fMouseDownWindowPos = Frame().LeftTop();
994 
995 	if (buttons == 1 && !fIsFullscreen) {
996 		// start mouse tracking
997 		fVideoView->SetMouseEventMask(B_POINTER_EVENTS | B_NO_POINTER_HISTORY /* | B_LOCK_WINDOW_FOCUS */);
998 		fMouseDownTracking = true;
999 	}
1000 
1001 	// pop up a context menu if right mouse button is down for 200 ms
1002 
1003 	if ((buttons & 2) == 0)
1004 		return;
1005 	bigtime_t start = system_time();
1006 	bigtime_t delay = 200000;
1007 	BPoint location;
1008 	do {
1009 		fVideoView->GetMouse(&location, &buttons);
1010 		if ((buttons & 2) == 0)
1011 			break;
1012 		snooze(1000);
1013 	} while (system_time() - start < delay);
1014 
1015 	if (buttons & 2)
1016 		_ShowContextMenu(screen_where);
1017 }
1018 
1019 
1020 void
1021 MainWin::_MouseMoved(BMessage *msg, BView* originalHandler)
1022 {
1023 //	msg->PrintToStream();
1024 
1025 	BPoint mousePos;
1026 	uint32 buttons = msg->FindInt32("buttons");
1027 
1028 	if (1 == buttons && fMouseDownTracking && !fIsFullscreen) {
1029 /*
1030 		// very broken in Zeta:
1031 		BPoint mousePos = msg->FindPoint("where");
1032 		printf("view where: %.0f, %.0f => ", mousePos.x, mousePos.y);
1033 		fVideoView->ConvertToScreen(&mousePos);
1034 */
1035 		// On Zeta, only "screen_where" is relyable, "where"
1036 		// and "be:view_where" seem to be broken
1037 		if (B_OK != msg->FindPoint("screen_where", &mousePos)) {
1038 			// Workaround for BeOS R5, it has no "screen_where"
1039 			if (!originalHandler || msg->FindPoint("where", &mousePos) < B_OK)
1040 				return;
1041 			originalHandler->ConvertToScreen(&mousePos);
1042 		}
1043 //		printf("screen where: %.0f, %.0f => ", mousePos.x, mousePos.y);
1044 		float delta_x = mousePos.x - fMouseDownMousePos.x;
1045 		float delta_y = mousePos.y - fMouseDownMousePos.y;
1046 		float x = fMouseDownWindowPos.x + delta_x;
1047 		float y = fMouseDownWindowPos.y + delta_y;
1048 //		printf("move window to %.0f, %.0f\n", x, y);
1049 		MoveTo(x, y);
1050 	}
1051 }
1052 
1053 
1054 void
1055 MainWin::_MouseUp(BMessage *msg)
1056 {
1057 //	msg->PrintToStream();
1058 	fMouseDownTracking = false;
1059 }
1060 
1061 
1062 void
1063 MainWin::_ShowContextMenu(const BPoint &screen_point)
1064 {
1065 	printf("Show context menu\n");
1066 	BPopUpMenu *menu = new BPopUpMenu("context menu", false, false);
1067 	BMenuItem *item;
1068 	menu->AddItem(item = new BMenuItem("Full Screen", new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
1069 	item->SetMarked(fIsFullscreen);
1070 	item->SetEnabled(fHasVideo);
1071 	menu->AddItem(item = new BMenuItem("Keep Aspect Ratio", new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
1072 	item->SetMarked(fKeepAspectRatio);
1073 	item->SetEnabled(fHasVideo);
1074 
1075 	menu->AddSeparatorItem();
1076 	menu->AddItem(item = new BMenuItem("No Menu", new BMessage(M_TOGGLE_NO_MENU), 'M', B_COMMAND_KEY));
1077 	item->SetMarked(fNoMenu);
1078 	menu->AddItem(item = new BMenuItem("No Border", new BMessage(M_TOGGLE_NO_BORDER), 'B', B_COMMAND_KEY));
1079 	item->SetMarked(fNoBorder);
1080 	menu->AddItem(item = new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
1081 	item->SetMarked(fAlwaysOnTop);
1082 
1083 	menu->AddSeparatorItem();
1084 	menu->AddItem(new BMenuItem("About" NAME B_UTF8_ELLIPSIS,
1085 		new BMessage(B_ABOUT_REQUESTED)));
1086 	menu->AddSeparatorItem();
1087 	menu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q', B_COMMAND_KEY));
1088 
1089 	menu->AddSeparatorItem();
1090 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", new BMessage(M_ASPECT_100000_1)));
1091 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", new BMessage(M_ASPECT_106666_1)));
1092 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.09091:1", new BMessage(M_ASPECT_109091_1)));
1093 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.41176:1", new BMessage(M_ASPECT_141176_1)));
1094 	menu->AddItem(new BMenuItem("force 720 x 576, display aspect 4:3", new BMessage(M_ASPECT_720_576)));
1095 	menu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", new BMessage(M_ASPECT_704_576)));
1096 	menu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", new BMessage(M_ASPECT_544_576)));
1097 
1098 	menu->SetTargetForItems(this);
1099 	BRect r(screen_point.x - 5, screen_point.y - 5, screen_point.x + 5, screen_point.y + 5);
1100 	menu->Go(screen_point, true, true, r, true);
1101 }
1102 
1103 
1104 /* Trap keys that are about to be send to background or renderer view.
1105  * Return B_OK if it shouldn't be passed to the view
1106  */
1107 status_t
1108 MainWin::_KeyDown(BMessage *msg)
1109 {
1110 //	msg->PrintToStream();
1111 
1112 	uint32 key		 = msg->FindInt32("key");
1113 	uint32 raw_char  = msg->FindInt32("raw_char");
1114 	uint32 modifiers = msg->FindInt32("modifiers");
1115 
1116 	printf("key 0x%lx, raw_char 0x%lx, modifiers 0x%lx\n", key, raw_char, modifiers);
1117 
1118 	switch (raw_char) {
1119 		case B_SPACE:
1120 			if (fController->IsPaused() || fController->IsStopped())
1121 				fController->Play();
1122 			else
1123 				fController->Pause();
1124 			return B_OK;
1125 
1126 		case B_ESCAPE:
1127 			if (fIsFullscreen) {
1128 				PostMessage(M_TOGGLE_FULLSCREEN);
1129 				return B_OK;
1130 			} else
1131 				break;
1132 
1133 		case B_ENTER:		// Enter / Return
1134 			if (modifiers & B_COMMAND_KEY) {
1135 				PostMessage(M_TOGGLE_FULLSCREEN);
1136 				return B_OK;
1137 			} else
1138 				break;
1139 
1140 		case B_TAB:
1141 			if ((modifiers & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY | B_MENU_KEY)) == 0) {
1142 				PostMessage(M_TOGGLE_FULLSCREEN);
1143 				return B_OK;
1144 			} else
1145 				break;
1146 
1147 		case B_UP_ARROW:
1148 			if (modifiers & B_COMMAND_KEY) {
1149 				PostMessage(M_CHANNEL_NEXT);
1150 			} else {
1151 				PostMessage(M_VOLUME_UP);
1152 			}
1153 			return B_OK;
1154 
1155 		case B_DOWN_ARROW:
1156 			if (modifiers & B_COMMAND_KEY) {
1157 				PostMessage(M_CHANNEL_PREV);
1158 			} else {
1159 				PostMessage(M_VOLUME_DOWN);
1160 			}
1161 			return B_OK;
1162 
1163 		case B_RIGHT_ARROW:
1164 			if (modifiers & B_COMMAND_KEY) {
1165 				PostMessage(M_VOLUME_UP);
1166 			} else {
1167 				PostMessage(M_CHANNEL_NEXT);
1168 			}
1169 			return B_OK;
1170 
1171 		case B_LEFT_ARROW:
1172 			if (modifiers & B_COMMAND_KEY) {
1173 				PostMessage(M_VOLUME_DOWN);
1174 			} else {
1175 				PostMessage(M_CHANNEL_PREV);
1176 			}
1177 			return B_OK;
1178 
1179 		case B_PAGE_UP:
1180 			PostMessage(M_CHANNEL_NEXT);
1181 			return B_OK;
1182 
1183 		case B_PAGE_DOWN:
1184 			PostMessage(M_CHANNEL_PREV);
1185 			return B_OK;
1186 	}
1187 
1188 	switch (key) {
1189 		case 0x3a:  		// numeric keypad +
1190 			if ((modifiers & B_COMMAND_KEY) == 0) {
1191 				printf("if\n");
1192 				PostMessage(M_VOLUME_UP);
1193 				return B_OK;
1194 			} else {
1195 				printf("else\n");
1196 				break;
1197 			}
1198 
1199 		case 0x25:  		// numeric keypad -
1200 			if ((modifiers & B_COMMAND_KEY) == 0) {
1201 				PostMessage(M_VOLUME_DOWN);
1202 				return B_OK;
1203 			} else {
1204 				break;
1205 			}
1206 
1207 		case 0x38:			// numeric keypad up arrow
1208 			PostMessage(M_VOLUME_UP);
1209 			return B_OK;
1210 
1211 		case 0x59:			// numeric keypad down arrow
1212 			PostMessage(M_VOLUME_DOWN);
1213 			return B_OK;
1214 
1215 		case 0x39:			// numeric keypad page up
1216 		case 0x4a:			// numeric keypad right arrow
1217 			PostMessage(M_CHANNEL_NEXT);
1218 			return B_OK;
1219 
1220 		case 0x5a:			// numeric keypad page down
1221 		case 0x48:			// numeric keypad left arrow
1222 			PostMessage(M_CHANNEL_PREV);
1223 			return B_OK;
1224 	}
1225 
1226 	return B_ERROR;
1227 }
1228 
1229 
1230 // #pragma mark -
1231 
1232 
1233 void
1234 MainWin::_ToggleNoBorderNoMenu()
1235 {
1236 	if (!fNoMenu && !fNoBorder && !fNoControls) {
1237 		PostMessage(M_TOGGLE_NO_MENU);
1238 		PostMessage(M_TOGGLE_NO_BORDER);
1239 		PostMessage(M_TOGGLE_NO_CONTROLS);
1240 	} else {
1241 		if (!fNoMenu)
1242 			PostMessage(M_TOGGLE_NO_MENU);
1243 		if (!fNoBorder)
1244 			PostMessage(M_TOGGLE_NO_BORDER);
1245 		if (!fNoControls)
1246 			PostMessage(M_TOGGLE_NO_CONTROLS);
1247 	}
1248 }
1249 
1250 
1251 void
1252 MainWin::_ToggleFullscreen()
1253 {
1254 	printf("_ToggleFullscreen enter\n");
1255 
1256 	if (!fHasVideo) {
1257 		printf("_ToggleFullscreen - ignoring, as we don't have a video\n");
1258 		return;
1259 	}
1260 
1261 	fIsFullscreen = !fIsFullscreen;
1262 
1263 	if (fIsFullscreen) {
1264 		// switch to fullscreen
1265 
1266 		fSavedFrame = Frame();
1267 		printf("saving current frame: %d %d %d %d\n", int(fSavedFrame.left), int(fSavedFrame.top), int(fSavedFrame.right), int(fSavedFrame.bottom));
1268 		BScreen screen(this);
1269 		BRect rect(screen.Frame());
1270 
1271 		Hide();
1272 		MoveTo(rect.left, rect.top);
1273 		ResizeTo(rect.Width(), rect.Height());
1274 		Show();
1275 
1276 	} else {
1277 		// switch back from full screen mode
1278 
1279 		Hide();
1280 		MoveTo(fSavedFrame.left, fSavedFrame.top);
1281 		ResizeTo(fSavedFrame.Width(), fSavedFrame.Height());
1282 		Show();
1283 	}
1284 
1285 	printf("_ToggleFullscreen leave\n");
1286 }
1287 
1288 void
1289 MainWin::_ToggleNoControls()
1290 {
1291 	printf("_ToggleNoControls enter\n");
1292 
1293 	if (fIsFullscreen) {
1294 		// fullscreen is always without menu
1295 		printf("_ToggleNoControls leave, doing nothing, we are fullscreen\n");
1296 		return;
1297 	}
1298 
1299 	fNoControls = !fNoControls;
1300 	_SetWindowSizeLimits();
1301 
1302 	if (fNoControls) {
1303 		ResizeBy(0, - fControlsHeight);
1304 	} else {
1305 		ResizeBy(0, fControlsHeight);
1306 	}
1307 
1308 	printf("_ToggleNoControls leave\n");
1309 }
1310 
1311 void
1312 MainWin::_ToggleNoMenu()
1313 {
1314 	printf("_ToggleNoMenu enter\n");
1315 
1316 	if (fIsFullscreen) {
1317 		// fullscreen is always without menu
1318 		printf("_ToggleNoMenu leave, doing nothing, we are fullscreen\n");
1319 		return;
1320 	}
1321 
1322 	fNoMenu = !fNoMenu;
1323 	_SetWindowSizeLimits();
1324 
1325 	if (fNoMenu) {
1326 		MoveBy(0, fMenuBarHeight);
1327 		ResizeBy(0, - fMenuBarHeight);
1328 	} else {
1329 		MoveBy(0, - fMenuBarHeight);
1330 		ResizeBy(0, fMenuBarHeight);
1331 	}
1332 
1333 	printf("_ToggleNoMenu leave\n");
1334 }
1335 
1336 
1337 void
1338 MainWin::_ToggleNoBorder()
1339 {
1340 	printf("_ToggleNoBorder enter\n");
1341 	fNoBorder = !fNoBorder;
1342 	SetLook(fNoBorder ? B_BORDERED_WINDOW_LOOK : B_TITLED_WINDOW_LOOK);
1343 	printf("_ToggleNoBorder leave\n");
1344 }
1345 
1346 
1347 void
1348 MainWin::_ToggleAlwaysOnTop()
1349 {
1350 	printf("_ToggleAlwaysOnTop enter\n");
1351 	fAlwaysOnTop = !fAlwaysOnTop;
1352 	SetFeel(fAlwaysOnTop ? B_FLOATING_ALL_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL);
1353 	printf("_ToggleAlwaysOnTop leave\n");
1354 }
1355 
1356 
1357 void
1358 MainWin::_ToggleKeepAspectRatio()
1359 {
1360 	printf("_ToggleKeepAspectRatio enter\n");
1361 	fKeepAspectRatio = !fKeepAspectRatio;
1362 	FrameResized(Bounds().Width(), Bounds().Height());
1363 	printf("_ToggleKeepAspectRatio leave\n");
1364 }
1365 
1366 
1367 // #pragma mark -
1368 
1369 
1370 void
1371 MainWin::_UpdateControlsEnabledStatus()
1372 {
1373 	uint32 enabledButtons = 0;
1374 	if (fHasVideo || fHasAudio) {
1375 		enabledButtons |= PLAYBACK_ENABLED | SEEK_ENABLED
1376 			| SEEK_BACK_ENABLED | SEEK_FORWARD_ENABLED;
1377 	}
1378 	if (fHasAudio)
1379 		enabledButtons |= VOLUME_ENABLED;
1380 
1381 	bool canSkipPrevious, canSkipNext;
1382 	fPlaylist->GetSkipInfo(&canSkipPrevious, &canSkipNext);
1383 	if (canSkipPrevious)
1384 		enabledButtons |= SKIP_BACK_ENABLED;
1385 	if (canSkipNext)
1386 		enabledButtons |= SKIP_FORWARD_ENABLED;
1387 
1388 	fControls->SetEnabled(enabledButtons);
1389 }
1390 
1391 
1392 void
1393 MainWin::_UpdatePlaylistMenu()
1394 {
1395 	if (!fPlaylist->Lock())
1396 		return;
1397 
1398 	fPlaylistMenu->RemoveItems(0, fPlaylistMenu->CountItems(), true);
1399 
1400 	int32 count = fPlaylist->CountItems();
1401 	for (int32 i = 0; i < count; i++) {
1402 		entry_ref ref;
1403 		if (fPlaylist->GetRefAt(i, &ref) < B_OK)
1404 			continue;
1405 		_AddPlaylistItem(ref, i);
1406 	}
1407 	fPlaylistMenu->SetTargetForItems(this);
1408 
1409 	_MarkPlaylistItem(fPlaylist->CurrentRefIndex());
1410 
1411 	fPlaylist->Unlock();
1412 }
1413 
1414 
1415 void
1416 MainWin::_AddPlaylistItem(const entry_ref& ref, int32 index)
1417 {
1418 	BMessage* message = new BMessage(M_SET_PLAYLIST_POSITION);
1419 	message->AddInt32("index", index);
1420 	BMenuItem* item = new BMenuItem(ref.name, message);
1421 	fPlaylistMenu->AddItem(item, index);
1422 }
1423 
1424 
1425 void
1426 MainWin::_RemovePlaylistItem(int32 index)
1427 {
1428 	delete fPlaylistMenu->RemoveItem(index);
1429 }
1430 
1431 
1432 void
1433 MainWin::_MarkPlaylistItem(int32 index)
1434 {
1435 	if (BMenuItem* item = fPlaylistMenu->ItemAt(index)) {
1436 		item->SetMarked(true);
1437 		// ... and in case the menu is currently on screen:
1438 		if (fPlaylistMenu->LockLooper()) {
1439 			fPlaylistMenu->Invalidate();
1440 			fPlaylistMenu->UnlockLooper();
1441 		}
1442 	}
1443 }
1444 
1445 
1446