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