xref: /haiku/src/apps/mediaplayer/MainWin.cpp (revision a637e3c53c976ebe3d2c7d1fe8792a1eaf1aae3e)
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 		// PlaylistObserver messages
332 		case MSG_PLAYLIST_REF_ADDED: {
333 			entry_ref ref;
334 			int32 index;
335 			if (msg->FindRef("refs", &ref) == B_OK
336 				&& msg->FindInt32("index", &index) == B_OK) {
337 				_AddPlaylistItem(ref, index);
338 			}
339 			break;
340 		}
341 		case MSG_PLAYLIST_REF_REMOVED: {
342 			int32 index;
343 			if (msg->FindInt32("index", &index) == B_OK) {
344 				_RemovePlaylistItem(index);
345 			}
346 			break;
347 		}
348 		case MSG_PLAYLIST_CURRENT_REF_CHANGED: {
349 			BAutolock _(fPlaylist);
350 
351 			int32 index;
352 			if (msg->FindInt32("index", &index) < B_OK
353 				|| index != fPlaylist->CurrentRefIndex())
354 				break;
355 			entry_ref ref;
356 			if (fPlaylist->GetRefAt(index, &ref) == B_OK) {
357 				printf("open ref: %s\n", ref.name);
358 				OpenFile(ref);
359 				_MarkPlaylistItem(index);
360 			}
361 			break;
362 		}
363 
364 		// ControllerObserver messages
365 		case MSG_CONTROLLER_FILE_FINISHED:
366 			fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() + 1);
367 			break;
368 		case MSG_CONTROLLER_FILE_CHANGED:
369 			// TODO: move all other GUI changes as a reaction to this notification
370 //			_UpdatePlaylistMenu();
371 			break;
372 		case MSG_CONTROLLER_VIDEO_TRACK_CHANGED: {
373 			int32 index;
374 			if (msg->FindInt32("index", &index) == B_OK) {
375 				BMenuItem* item = fVideoTrackMenu->ItemAt(index);
376 				if (item)
377 					item->SetMarked(true);
378 			}
379 			break;
380 		}
381 		case MSG_CONTROLLER_AUDIO_TRACK_CHANGED: {
382 			int32 index;
383 			if (msg->FindInt32("index", &index) == B_OK) {
384 				BMenuItem* item = fAudioTrackMenu->ItemAt(index);
385 				if (item)
386 					item->SetMarked(true);
387 			}
388 			break;
389 		}
390 		case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED: {
391 			uint32 state;
392 			if (msg->FindInt32("state", (int32*)&state) == B_OK)
393 				fControls->SetPlaybackState(state);
394 			break;
395 		}
396 		case MSG_CONTROLLER_POSITION_CHANGED: {
397 			float position;
398 			if (msg->FindFloat("position", &position) == B_OK)
399 				fControls->SetPosition(position);
400 			break;
401 		}
402 		case MSG_CONTROLLER_VOLUME_CHANGED: {
403 			float volume;
404 			if (msg->FindFloat("volume", &volume) == B_OK)
405 				fControls->SetVolume(volume);
406 			break;
407 		}
408 		case MSG_CONTROLLER_MUTED_CHANGED: {
409 			bool muted;
410 			if (msg->FindBool("muted", &muted) == B_OK)
411 				fControls->SetMuted(muted);
412 			break;
413 		}
414 
415 		// menu item messages
416 		case M_FILE_NEWPLAYER:
417 			gMainApp->NewWindow();
418 			break;
419 		case M_FILE_OPEN:
420 			if (!fFilePanel) {
421 				fFilePanel = new BFilePanel();
422 				fFilePanel->SetTarget(BMessenger(0, this));
423 				fFilePanel->SetPanelDirectory("/boot/home/");
424 			}
425 			fFilePanel->Show();
426 			break;
427 		case M_FILE_INFO:
428 			ShowFileInfo();
429 			break;
430 		case M_FILE_PLAYLIST:
431 			ShowPlaylistWindow();
432 			break;
433 		case B_ABOUT_REQUESTED:
434 			BAlert *alert;
435 			alert = new BAlert("about", NAME"\n\n Written by Marcus Overhagen "
436 				"and Stephan Aßmus", "Thanks");
437 			if (fAlwaysOnTop) {
438 				_ToggleAlwaysOnTop();
439 				alert->Go();
440 				_ToggleAlwaysOnTop();
441 			} else {
442 				alert->Go();
443 			}
444 			break;
445 		case M_FILE_CLOSE:
446 			PostMessage(B_QUIT_REQUESTED);
447 			break;
448 		case M_FILE_QUIT:
449 			be_app->PostMessage(B_QUIT_REQUESTED);
450 			break;
451 
452 		case M_TOGGLE_FULLSCREEN:
453 			_ToggleFullscreen();
454 			break;
455 
456 		case M_TOGGLE_NO_MENU:
457 			_ToggleNoMenu();
458 			break;
459 
460 		case M_TOGGLE_NO_CONTROLS:
461 			_ToggleNoControls();
462 			break;
463 
464 		case M_TOGGLE_NO_BORDER:
465 			_ToggleNoBorder();
466 			break;
467 
468 		case M_TOGGLE_ALWAYS_ON_TOP:
469 			_ToggleAlwaysOnTop();
470 			break;
471 
472 		case M_TOGGLE_KEEP_ASPECT_RATIO:
473 			_ToggleKeepAspectRatio();
474 			break;
475 
476 		case M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS:
477 			_ToggleNoBorderNoMenu();
478 			break;
479 
480 		case M_VIEW_50:
481 			if (!fHasVideo)
482 				break;
483 			if (fIsFullscreen)
484 				_ToggleFullscreen();
485 			_ResizeWindow(50);
486 			break;
487 
488 		case M_VIEW_100:
489 			if (!fHasVideo)
490 				break;
491 			if (fIsFullscreen)
492 				_ToggleFullscreen();
493 			_ResizeWindow(100);
494 			break;
495 
496 		case M_VIEW_200:
497 			if (!fHasVideo)
498 				break;
499 			if (fIsFullscreen)
500 				_ToggleFullscreen();
501 			_ResizeWindow(200);
502 			break;
503 
504 		case M_VIEW_300:
505 			if (!fHasVideo)
506 				break;
507 			if (fIsFullscreen)
508 				_ToggleFullscreen();
509 			_ResizeWindow(300);
510 			break;
511 
512 		case M_VIEW_400:
513 			if (!fHasVideo)
514 				break;
515 			if (fIsFullscreen)
516 				_ToggleFullscreen();
517 			_ResizeWindow(400);
518 			break;
519 
520 /*
521 
522 		case B_ACQUIRE_OVERLAY_LOCK:
523 			printf("B_ACQUIRE_OVERLAY_LOCK\n");
524 			fVideoView->OverlayLockAcquire();
525 			break;
526 
527 		case B_RELEASE_OVERLAY_LOCK:
528 			printf("B_RELEASE_OVERLAY_LOCK\n");
529 			fVideoView->OverlayLockRelease();
530 			break;
531 
532 		case B_MOUSE_WHEEL_CHANGED:
533 		{
534 			printf("B_MOUSE_WHEEL_CHANGED\n");
535 			float dx = msg->FindFloat("be:wheel_delta_x");
536 			float dy = msg->FindFloat("be:wheel_delta_y");
537 			bool inv = modifiers() & B_COMMAND_KEY;
538 			if (dx > 0.1)	PostMessage(inv ? M_VOLUME_DOWN : M_SKIP_PREV);
539 			if (dx < -0.1)	PostMessage(inv ? M_VOLUME_UP : M_SKIP_NEXT);
540 			if (dy > 0.1)	PostMessage(inv ? M_SKIP_PREV : M_VOLUME_DOWN);
541 			if (dy < -0.1)	PostMessage(inv ? M_SKIP_NEXT : M_VOLUME_UP);
542 			break;
543 		}
544 */
545 		case M_SKIP_NEXT:
546 			fControls->SkipForward();
547 			break;
548 
549 		case M_SKIP_PREV:
550 			fControls->SkipBackward();
551 			break;
552 
553 		case M_VOLUME_UP:
554 			fController->VolumeUp();
555 			break;
556 
557 		case M_VOLUME_DOWN:
558 			fController->VolumeDown();
559 			break;
560 
561 		case M_ASPECT_100000_1:
562 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.0, 1.0);
563 			break;
564 
565 		case M_ASPECT_106666_1:
566 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.06666, 1.0);
567 			break;
568 
569 		case M_ASPECT_109091_1:
570 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.09091, 1.0);
571 			break;
572 
573 		case M_ASPECT_141176_1:
574 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.41176, 1.0);
575 			break;
576 
577 		case M_ASPECT_720_576:
578 			VideoFormatChange(720, 576, 1.06666, 1.0);
579 			break;
580 
581 		case M_ASPECT_704_576:
582 			VideoFormatChange(704, 576, 1.09091, 1.0);
583 			break;
584 
585 		case M_ASPECT_544_576:
586 			VideoFormatChange(544, 576, 1.41176, 1.0);
587 			break;
588 /*
589 		case M_PREFERENCES:
590 			break;
591 
592 		default:
593 			if (msg->what >= M_SELECT_CHANNEL && msg->what <= M_SELECT_CHANNEL_END) {
594 				SelectChannel(msg->what - M_SELECT_CHANNEL);
595 				break;
596 			}
597 			if (msg->what >= M_SELECT_INTERFACE && msg->what <= M_SELECT_INTERFACE_END) {
598 				SelectInterface(msg->what - M_SELECT_INTERFACE - 1);
599 				break;
600 			}
601 */
602 		case M_SET_PLAYLIST_POSITION: {
603 			int32 index;
604 			if (msg->FindInt32("index", &index) == B_OK)
605 				fPlaylist->SetCurrentRefIndex(index);
606 			break;
607 		}
608 
609 		default:
610 			// let BWindow handle the rest
611 			BWindow::MessageReceived(msg);
612 	}
613 }
614 
615 
616 bool
617 MainWin::QuitRequested()
618 {
619 	be_app->PostMessage(M_PLAYER_QUIT);
620 	return true;
621 }
622 
623 
624 // #pragma mark -
625 
626 
627 void
628 MainWin::OpenFile(const entry_ref &ref)
629 {
630 	printf("MainWin::OpenFile\n");
631 
632 	status_t err = fController->SetTo(ref);
633 	if (err != B_OK) {
634 		if (fPlaylist->CountItems() == 1) {
635 			// display error if this is the only file we're supposed to play
636 			char s[300];
637 			sprintf(s, "Can't open file\n\n%s\n\nError 0x%08lx\n(%s)\n",
638 				ref.name, err, strerror(err));
639 			(new BAlert("error", s, "OK"))->Go();
640 		} else {
641 			// just go to the next file and don't bother user
642 			// TODO: this makes it impossible to skip backwards
643 			// over a non recognized file!
644 			fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() + 1);
645 		}
646 		fHasFile = false;
647 		fHasVideo = false;
648 		fHasAudio = false;
649 		SetTitle(NAME);
650 	} else {
651 		fHasFile = true;
652 		fHasVideo = fController->VideoTrackCount() != 0;
653 		fHasAudio = fController->AudioTrackCount() != 0;
654 		SetTitle(ref.name);
655 	}
656 	_SetupWindow();
657 }
658 
659 void
660 MainWin::ShowFileInfo()
661 {
662 	if (!fInfoWin)
663 		fInfoWin = new InfoWin(Frame().LeftTop(), fController);
664 
665 	if (fInfoWin->Lock()) {
666 		if (fInfoWin->IsHidden())
667 			fInfoWin->Show();
668 		else
669 			fInfoWin->Activate();
670 		fInfoWin->Unlock();
671 	}
672 }
673 
674 
675 void
676 MainWin::ShowPlaylistWindow()
677 {
678 	if (fPlaylistWindow->Lock()) {
679 		if (fPlaylistWindow->IsHidden())
680 			fPlaylistWindow->Show();
681 		else
682 			fPlaylistWindow->Activate();
683 		fPlaylistWindow->Unlock();
684 	}
685 }
686 
687 
688 void
689 MainWin::VideoFormatChange(int width, int height, float width_scale, float height_scale)
690 {
691 	// called when video format or aspect ratio changes
692 
693 	printf("VideoFormatChange enter: width %d, height %d, width_scale %.6f, height_scale %.6f\n", width, height, width_scale, height_scale);
694 
695 	if (width_scale < 1.0 && height_scale >= 1.0) {
696 		width_scale  = 1.0 / width_scale;
697 		height_scale = 1.0 / height_scale;
698 		printf("inverting! new values: width_scale %.6f, height_scale %.6f\n", width_scale, height_scale);
699 	}
700 
701  	fSourceWidth  = width;
702  	fSourceHeight = height;
703  	fWidthScale   = width_scale;
704  	fHeightScale  = height_scale;
705 
706  	FrameResized(Bounds().Width(), Bounds().Height());
707 
708 	printf("VideoFormatChange leave\n");
709 }
710 
711 
712 // #pragma mark -
713 
714 
715 void
716 MainWin::_RefsReceived(BMessage* msg)
717 {
718 	// the playlist ist replaced by dropped files
719 	// or the dropped files are appended to the end
720 	// of the existing playlist if <shift> is pressed
721 	int32 appendIndex = modifiers() & B_SHIFT_KEY ?
722 		fPlaylist->CountItems() : -1;
723 	msg->AddInt32("append_index", appendIndex);
724 
725 	// forward the message to the playlist window,
726 	// so that undo/redo is used for modifying the playlist
727 	fPlaylistWindow->PostMessage(msg);
728 }
729 
730 
731 void
732 MainWin::_SetupWindow()
733 {
734 	printf("MainWin::_SetupWindow\n");
735 
736 	// Populate the track menus
737 	_SetupTrackMenus();
738 	// Enable both if a file was loaded
739 	fAudioTrackMenu->SetEnabled(fHasFile);
740 	fVideoTrackMenu->SetEnabled(fHasFile);
741 	// Select first track (might be "none") in both
742 	fAudioTrackMenu->ItemAt(0)->SetMarked(true);
743 	fVideoTrackMenu->ItemAt(0)->SetMarked(true);
744 
745 	fVideoMenu->SetEnabled(fHasVideo);
746 	fAudioMenu->SetEnabled(fHasAudio);
747 	fDebugMenu->SetEnabled(fHasVideo);
748 
749 	if (fHasVideo) {
750 		fController->GetSize(&fSourceWidth, &fSourceHeight);
751 		fWidthScale = 1.0;
752 		fHeightScale = 1.0;
753 	} else {
754 		fSourceWidth = 0;
755 		fSourceHeight = 0;
756 		fWidthScale = 1.0;
757 		fHeightScale = 1.0;
758 	}
759 
760 	_UpdateControlsEnabledStatus();
761 
762 	_ResizeWindow(100);
763 
764 	fVideoView->MakeFocus();
765 }
766 
767 
768 void
769 MainWin::_CreateMenu()
770 {
771 	fFileMenu = new BMenu(NAME);
772 	fPlaylistMenu = new BMenu("Playlist"B_UTF8_ELLIPSIS);
773 	fAudioMenu = new BMenu("Audio");
774 	fVideoMenu = new BMenu("Video");
775 	fSettingsMenu = new BMenu("Settings");
776 	fAudioTrackMenu = new BMenu("Track");
777 	fVideoTrackMenu = new BMenu("Track");
778 	fDebugMenu = new BMenu("Debug");
779 
780 	fMenuBar->AddItem(fFileMenu);
781 	fMenuBar->AddItem(fAudioMenu);
782 	fMenuBar->AddItem(fVideoMenu);
783 	fMenuBar->AddItem(fSettingsMenu);
784 //	fMenuBar->AddItem(fDebugMenu);
785 
786 	fFileMenu->AddItem(new BMenuItem("New Player"B_UTF8_ELLIPSIS, new BMessage(M_FILE_NEWPLAYER), 'N', B_COMMAND_KEY));
787 	fFileMenu->AddSeparatorItem();
788 	fFileMenu->AddItem(new BMenuItem("Open File"B_UTF8_ELLIPSIS, new BMessage(M_FILE_OPEN), 'O', B_COMMAND_KEY));
789 	fFileMenu->AddItem(new BMenuItem("File Info"B_UTF8_ELLIPSIS, new BMessage(M_FILE_INFO), 'I', B_COMMAND_KEY));
790 	fFileMenu->AddItem(fPlaylistMenu);
791 	fPlaylistMenu->Superitem()->SetShortcut('P', B_COMMAND_KEY);
792 	fPlaylistMenu->Superitem()->SetMessage(new BMessage(M_FILE_PLAYLIST));
793 
794 	fFileMenu->AddSeparatorItem();
795 	fFileMenu->AddItem(new BMenuItem("About" NAME B_UTF8_ELLIPSIS,
796 		new BMessage(B_ABOUT_REQUESTED)));
797 	fFileMenu->AddSeparatorItem();
798 	fFileMenu->AddItem(new BMenuItem("Close", new BMessage(M_FILE_CLOSE), 'W', B_COMMAND_KEY));
799 	fFileMenu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q', B_COMMAND_KEY));
800 
801 	fPlaylistMenu->SetRadioMode(true);
802 
803 	fAudioMenu->AddItem(fAudioTrackMenu);
804 
805 	fVideoMenu->AddItem(fVideoTrackMenu);
806 	fVideoMenu->AddSeparatorItem();
807 	fVideoMenu->AddItem(new BMenuItem("50% scale", new BMessage(M_VIEW_50), '0', B_COMMAND_KEY));
808 	fVideoMenu->AddItem(new BMenuItem("100% scale", new BMessage(M_VIEW_100), '1', B_COMMAND_KEY));
809 	fVideoMenu->AddItem(new BMenuItem("200% scale", new BMessage(M_VIEW_200), '2', B_COMMAND_KEY));
810 	fVideoMenu->AddItem(new BMenuItem("300% scale", new BMessage(M_VIEW_300), '3', B_COMMAND_KEY));
811 	fVideoMenu->AddItem(new BMenuItem("400% scale", new BMessage(M_VIEW_400), '4', B_COMMAND_KEY));
812 	fVideoMenu->AddSeparatorItem();
813 	fVideoMenu->AddItem(new BMenuItem("Full Screen", new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
814 	fVideoMenu->AddItem(new BMenuItem("Keep Aspect Ratio", new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
815 
816 	fSettingsMenu->AddItem(new BMenuItem("No Menu", new BMessage(M_TOGGLE_NO_MENU), 'M', B_COMMAND_KEY));
817 	fSettingsMenu->AddItem(new BMenuItem("No Border", new BMessage(M_TOGGLE_NO_BORDER), 'B', B_COMMAND_KEY));
818 	fSettingsMenu->AddItem(new BMenuItem("No Controls", new BMessage(M_TOGGLE_NO_CONTROLS), 'C', B_COMMAND_KEY));
819 	fSettingsMenu->AddItem(new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
820 //	fSettingsMenu->AddSeparatorItem();
821 //	fSettingsMenu->AddItem(new BMenuItem("Preferences"B_UTF8_ELLIPSIS, new BMessage(M_PREFERENCES), 'P', B_COMMAND_KEY));
822 
823 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", new BMessage(M_ASPECT_100000_1)));
824 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", new BMessage(M_ASPECT_106666_1)));
825 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.09091:1", new BMessage(M_ASPECT_109091_1)));
826 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.41176:1", new BMessage(M_ASPECT_141176_1)));
827 	fDebugMenu->AddItem(new BMenuItem("force 720 x 576, display aspect 4:3", new BMessage(M_ASPECT_720_576)));
828 	fDebugMenu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", new BMessage(M_ASPECT_704_576)));
829 	fDebugMenu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", new BMessage(M_ASPECT_544_576)));
830 
831 	fAudioTrackMenu->SetRadioMode(true);
832 	fVideoTrackMenu->SetRadioMode(true);
833 /*
834 	fSettingsMenu->ItemAt(3)->SetMarked(fIsFullscreen);
835 	fSettingsMenu->ItemAt(5)->SetMarked(fNoMenu);
836 	fSettingsMenu->ItemAt(6)->SetMarked(fNoBorder);
837 	fSettingsMenu->ItemAt(7)->SetMarked(fAlwaysOnTop);
838 	fSettingsMenu->ItemAt(8)->SetMarked(fKeepAspectRatio);
839 	fSettingsMenu->ItemAt(10)->SetEnabled(false); // XXX disable unused preference menu
840 */
841 }
842 
843 
844 void
845 MainWin::_SetupTrackMenus()
846 {
847 	fAudioTrackMenu->RemoveItems(0, fAudioTrackMenu->CountItems(), true);
848 	fVideoTrackMenu->RemoveItems(0, fVideoTrackMenu->CountItems(), true);
849 
850 	int c, i;
851 	char s[100];
852 
853 	c = fController->AudioTrackCount();
854 	for (i = 0; i < c; i++) {
855 		sprintf(s, "Track %d", i + 1);
856 		fAudioTrackMenu->AddItem(new BMenuItem(s, new BMessage(M_SELECT_AUDIO_TRACK + i)));
857 	}
858 	if (!c)
859 		fAudioTrackMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY)));
860 
861 	c = fController->VideoTrackCount();
862 	for (i = 0; i < c; i++) {
863 		sprintf(s, "Track %d", i + 1);
864 		fVideoTrackMenu->AddItem(new BMenuItem(s, new BMessage(M_SELECT_VIDEO_TRACK + i)));
865 	}
866 	if (!c)
867 		fVideoTrackMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY)));
868 }
869 
870 
871 void
872 MainWin::_SetWindowSizeLimits()
873 {
874 	int minWidth = fNoControls  ? MIN_WIDTH : fControlsWidth;
875 	if (!fNoMenu)
876 		minWidth = max_c(minWidth, fMenuBarWidth);
877 	int minHeight = (fNoMenu ? 0 : fMenuBarHeight) + (fNoControls ? 0 : fControlsHeight);
878 
879 	SetSizeLimits(minWidth - 1, 32000, minHeight - 1, fHasVideo ? 32000 : minHeight - 1);
880 }
881 
882 
883 void
884 MainWin::_ResizeWindow(int percent)
885 {
886 	int video_width;
887 	int video_height;
888 
889 	// Get required window size
890 	video_width = lround(fSourceWidth * fWidthScale);
891 	video_height = lround(fSourceHeight * fHeightScale);
892 
893 	video_width = (video_width * percent) / 100;
894 	video_height = (video_height * percent) / 100;
895 
896 	// Calculate and set the initial window size
897 	int width = max_c(fControlsWidth, video_width);
898 	int height = (fNoControls ? 0 : fControlsHeight) + video_height;
899 	if (!fNoMenu) {
900 		width = max_c(width, fMenuBarWidth);
901 		height += fMenuBarHeight;
902 	}
903 	_SetWindowSizeLimits();
904 	ResizeTo(width - 1, height - 1);
905 }
906 
907 
908 void
909 MainWin::_ResizeVideoView(int x, int y, int width, int height)
910 {
911 	printf("_ResizeVideoView: %d,%d, width %d, height %d\n", x, y, width, height);
912 
913 	if (fKeepAspectRatio) {
914 		// Keep aspect ratio, place video view inside
915 		// the background area (may create black bars).
916 		float scaled_width  = fSourceWidth * fWidthScale;
917 		float scaled_height = fSourceHeight * fHeightScale;
918 		float factor = min_c(width / scaled_width, height / scaled_height);
919 		int render_width = lround(scaled_width * factor);
920 		int render_height = lround(scaled_height * factor);
921 		if (render_width > width)
922 			render_width = width;
923 		if (render_height > height)
924 			render_height = height;
925 
926 		int x_ofs = x + (width - render_width) / 2;
927 		int y_ofs = y + (height - render_height) / 2;
928 
929 		fVideoView->MoveTo(x_ofs, y_ofs);
930 		fVideoView->ResizeTo(render_width - 1, render_height - 1);
931 
932 	} else {
933 		fVideoView->MoveTo(x, y);
934 		fVideoView->ResizeTo(width - 1, height - 1);
935 	}
936 }
937 
938 
939 // #pragma mark -
940 
941 
942 void
943 MainWin::_MouseDown(BMessage *msg, BView* originalHandler)
944 {
945 	BPoint screen_where;
946 	uint32 buttons = msg->FindInt32("buttons");
947 
948 	// On Zeta, only "screen_where" is relyable, "where" and "be:view_where" seem to be broken
949 	if (B_OK != msg->FindPoint("screen_where", &screen_where)) {
950 		// Workaround for BeOS R5, it has no "screen_where"
951 		if (!originalHandler || msg->FindPoint("where", &screen_where) < B_OK)
952 			return;
953 		originalHandler->ConvertToScreen(&screen_where);
954 	}
955 
956 //	msg->PrintToStream();
957 
958 //	if (1 == msg->FindInt32("buttons") && msg->FindInt32("clicks") == 1) {
959 
960 	if (1 == buttons && msg->FindInt32("clicks") % 2 == 0) {
961 		BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1, screen_where.y + 1);
962 		if (r.Contains(fMouseDownMousePos)) {
963 			PostMessage(M_TOGGLE_FULLSCREEN);
964 			return;
965 		}
966 	}
967 
968 	if (2 == 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_NO_BORDER_NO_MENU_NO_CONTROLS);
972 			return;
973 		}
974 	}
975 
976 /*
977 		// very broken in Zeta:
978 		fMouseDownMousePos = fVideoView->ConvertToScreen(msg->FindPoint("where"));
979 */
980 	fMouseDownMousePos = screen_where;
981 	fMouseDownWindowPos = Frame().LeftTop();
982 
983 	if (buttons == 1 && !fIsFullscreen) {
984 		// start mouse tracking
985 		fVideoView->SetMouseEventMask(B_POINTER_EVENTS | B_NO_POINTER_HISTORY /* | B_LOCK_WINDOW_FOCUS */);
986 		fMouseDownTracking = true;
987 	}
988 
989 	// pop up a context menu if right mouse button is down for 200 ms
990 
991 	if ((buttons & 2) == 0)
992 		return;
993 	bigtime_t start = system_time();
994 	bigtime_t delay = 200000;
995 	BPoint location;
996 	do {
997 		fVideoView->GetMouse(&location, &buttons);
998 		if ((buttons & 2) == 0)
999 			break;
1000 		snooze(1000);
1001 	} while (system_time() - start < delay);
1002 
1003 	if (buttons & 2)
1004 		_ShowContextMenu(screen_where);
1005 }
1006 
1007 
1008 void
1009 MainWin::_MouseMoved(BMessage *msg, BView* originalHandler)
1010 {
1011 //	msg->PrintToStream();
1012 
1013 	BPoint mousePos;
1014 	uint32 buttons = msg->FindInt32("buttons");
1015 
1016 	if (1 == buttons && fMouseDownTracking && !fIsFullscreen) {
1017 /*
1018 		// very broken in Zeta:
1019 		BPoint mousePos = msg->FindPoint("where");
1020 		printf("view where: %.0f, %.0f => ", mousePos.x, mousePos.y);
1021 		fVideoView->ConvertToScreen(&mousePos);
1022 */
1023 		// On Zeta, only "screen_where" is relyable, "where"
1024 		// and "be:view_where" seem to be broken
1025 		if (B_OK != msg->FindPoint("screen_where", &mousePos)) {
1026 			// Workaround for BeOS R5, it has no "screen_where"
1027 			if (!originalHandler || msg->FindPoint("where", &mousePos) < B_OK)
1028 				return;
1029 			originalHandler->ConvertToScreen(&mousePos);
1030 		}
1031 //		printf("screen where: %.0f, %.0f => ", mousePos.x, mousePos.y);
1032 		float delta_x = mousePos.x - fMouseDownMousePos.x;
1033 		float delta_y = mousePos.y - fMouseDownMousePos.y;
1034 		float x = fMouseDownWindowPos.x + delta_x;
1035 		float y = fMouseDownWindowPos.y + delta_y;
1036 //		printf("move window to %.0f, %.0f\n", x, y);
1037 		MoveTo(x, y);
1038 	}
1039 }
1040 
1041 
1042 void
1043 MainWin::_MouseUp(BMessage *msg)
1044 {
1045 //	msg->PrintToStream();
1046 	fMouseDownTracking = false;
1047 }
1048 
1049 
1050 void
1051 MainWin::_ShowContextMenu(const BPoint &screen_point)
1052 {
1053 	printf("Show context menu\n");
1054 	BPopUpMenu *menu = new BPopUpMenu("context menu", false, false);
1055 	BMenuItem *item;
1056 	menu->AddItem(item = new BMenuItem("Full Screen", new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
1057 	item->SetMarked(fIsFullscreen);
1058 	item->SetEnabled(fHasVideo);
1059 	menu->AddItem(item = new BMenuItem("Keep Aspect Ratio", new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
1060 	item->SetMarked(fKeepAspectRatio);
1061 	item->SetEnabled(fHasVideo);
1062 
1063 	menu->AddSeparatorItem();
1064 	menu->AddItem(item = new BMenuItem("No Menu", new BMessage(M_TOGGLE_NO_MENU), 'M', B_COMMAND_KEY));
1065 	item->SetMarked(fNoMenu);
1066 	menu->AddItem(item = new BMenuItem("No Border", new BMessage(M_TOGGLE_NO_BORDER), 'B', B_COMMAND_KEY));
1067 	item->SetMarked(fNoBorder);
1068 	menu->AddItem(item = new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
1069 	item->SetMarked(fAlwaysOnTop);
1070 
1071 	menu->AddSeparatorItem();
1072 	menu->AddItem(new BMenuItem("About" NAME B_UTF8_ELLIPSIS,
1073 		new BMessage(B_ABOUT_REQUESTED)));
1074 	menu->AddSeparatorItem();
1075 	menu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q', B_COMMAND_KEY));
1076 
1077 	menu->AddSeparatorItem();
1078 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", new BMessage(M_ASPECT_100000_1)));
1079 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", new BMessage(M_ASPECT_106666_1)));
1080 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.09091:1", new BMessage(M_ASPECT_109091_1)));
1081 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.41176:1", new BMessage(M_ASPECT_141176_1)));
1082 	menu->AddItem(new BMenuItem("force 720 x 576, display aspect 4:3", new BMessage(M_ASPECT_720_576)));
1083 	menu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", new BMessage(M_ASPECT_704_576)));
1084 	menu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", new BMessage(M_ASPECT_544_576)));
1085 
1086 	menu->SetTargetForItems(this);
1087 	BRect r(screen_point.x - 5, screen_point.y - 5, screen_point.x + 5, screen_point.y + 5);
1088 	menu->Go(screen_point, true, true, r, true);
1089 }
1090 
1091 
1092 /* Trap keys that are about to be send to background or renderer view.
1093  * Return B_OK if it shouldn't be passed to the view
1094  */
1095 status_t
1096 MainWin::_KeyDown(BMessage *msg)
1097 {
1098 //	msg->PrintToStream();
1099 
1100 	uint32 key		 = msg->FindInt32("key");
1101 	uint32 raw_char  = msg->FindInt32("raw_char");
1102 	uint32 modifiers = msg->FindInt32("modifiers");
1103 
1104 	printf("key 0x%lx, raw_char 0x%lx, modifiers 0x%lx\n", key, raw_char, modifiers);
1105 
1106 	switch (raw_char) {
1107 		case B_SPACE:
1108 			if (fController->IsPaused() || fController->IsStopped())
1109 				fController->Play();
1110 			else
1111 				fController->Pause();
1112 			return B_OK;
1113 
1114 		case B_ESCAPE:
1115 			if (fIsFullscreen) {
1116 				PostMessage(M_TOGGLE_FULLSCREEN);
1117 				return B_OK;
1118 			} else
1119 				break;
1120 
1121 		case B_ENTER:		// Enter / Return
1122 			if (modifiers & B_COMMAND_KEY) {
1123 				PostMessage(M_TOGGLE_FULLSCREEN);
1124 				return B_OK;
1125 			} else
1126 				break;
1127 
1128 		case B_TAB:
1129 			if ((modifiers & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY | B_MENU_KEY)) == 0) {
1130 				PostMessage(M_TOGGLE_FULLSCREEN);
1131 				return B_OK;
1132 			} else
1133 				break;
1134 
1135 		case B_UP_ARROW:
1136 			if (modifiers & B_COMMAND_KEY) {
1137 				PostMessage(M_SKIP_NEXT);
1138 			} else {
1139 				PostMessage(M_VOLUME_UP);
1140 			}
1141 			return B_OK;
1142 
1143 		case B_DOWN_ARROW:
1144 			if (modifiers & B_COMMAND_KEY) {
1145 				PostMessage(M_SKIP_PREV);
1146 			} else {
1147 				PostMessage(M_VOLUME_DOWN);
1148 			}
1149 			return B_OK;
1150 
1151 		case B_RIGHT_ARROW:
1152 			if (modifiers & B_COMMAND_KEY) {
1153 				PostMessage(M_VOLUME_UP);
1154 			} else {
1155 				PostMessage(M_SKIP_NEXT);
1156 			}
1157 			return B_OK;
1158 
1159 		case B_LEFT_ARROW:
1160 			if (modifiers & B_COMMAND_KEY) {
1161 				PostMessage(M_VOLUME_DOWN);
1162 			} else {
1163 				PostMessage(M_SKIP_PREV);
1164 			}
1165 			return B_OK;
1166 
1167 		case B_PAGE_UP:
1168 			PostMessage(M_SKIP_NEXT);
1169 			return B_OK;
1170 
1171 		case B_PAGE_DOWN:
1172 			PostMessage(M_SKIP_PREV);
1173 			return B_OK;
1174 	}
1175 
1176 	switch (key) {
1177 		case 0x3a:  		// numeric keypad +
1178 			if ((modifiers & B_COMMAND_KEY) == 0) {
1179 				printf("if\n");
1180 				PostMessage(M_VOLUME_UP);
1181 				return B_OK;
1182 			} else {
1183 				printf("else\n");
1184 				break;
1185 			}
1186 
1187 		case 0x25:  		// numeric keypad -
1188 			if ((modifiers & B_COMMAND_KEY) == 0) {
1189 				PostMessage(M_VOLUME_DOWN);
1190 				return B_OK;
1191 			} else {
1192 				break;
1193 			}
1194 
1195 		case 0x38:			// numeric keypad up arrow
1196 			PostMessage(M_VOLUME_UP);
1197 			return B_OK;
1198 
1199 		case 0x59:			// numeric keypad down arrow
1200 			PostMessage(M_VOLUME_DOWN);
1201 			return B_OK;
1202 
1203 		case 0x39:			// numeric keypad page up
1204 		case 0x4a:			// numeric keypad right arrow
1205 			PostMessage(M_SKIP_NEXT);
1206 			return B_OK;
1207 
1208 		case 0x5a:			// numeric keypad page down
1209 		case 0x48:			// numeric keypad left arrow
1210 			PostMessage(M_SKIP_PREV);
1211 			return B_OK;
1212 	}
1213 
1214 	return B_ERROR;
1215 }
1216 
1217 
1218 // #pragma mark -
1219 
1220 
1221 void
1222 MainWin::_ToggleNoBorderNoMenu()
1223 {
1224 	if (!fNoMenu && !fNoBorder && !fNoControls) {
1225 		PostMessage(M_TOGGLE_NO_MENU);
1226 		PostMessage(M_TOGGLE_NO_BORDER);
1227 		PostMessage(M_TOGGLE_NO_CONTROLS);
1228 	} else {
1229 		if (!fNoMenu)
1230 			PostMessage(M_TOGGLE_NO_MENU);
1231 		if (!fNoBorder)
1232 			PostMessage(M_TOGGLE_NO_BORDER);
1233 		if (!fNoControls)
1234 			PostMessage(M_TOGGLE_NO_CONTROLS);
1235 	}
1236 }
1237 
1238 
1239 void
1240 MainWin::_ToggleFullscreen()
1241 {
1242 	printf("_ToggleFullscreen enter\n");
1243 
1244 	if (!fHasVideo) {
1245 		printf("_ToggleFullscreen - ignoring, as we don't have a video\n");
1246 		return;
1247 	}
1248 
1249 	fIsFullscreen = !fIsFullscreen;
1250 
1251 	if (fIsFullscreen) {
1252 		// switch to fullscreen
1253 
1254 		fSavedFrame = Frame();
1255 		printf("saving current frame: %d %d %d %d\n", int(fSavedFrame.left), int(fSavedFrame.top), int(fSavedFrame.right), int(fSavedFrame.bottom));
1256 		BScreen screen(this);
1257 		BRect rect(screen.Frame());
1258 
1259 		Hide();
1260 		MoveTo(rect.left, rect.top);
1261 		ResizeTo(rect.Width(), rect.Height());
1262 		Show();
1263 
1264 	} else {
1265 		// switch back from full screen mode
1266 
1267 		Hide();
1268 		MoveTo(fSavedFrame.left, fSavedFrame.top);
1269 		ResizeTo(fSavedFrame.Width(), fSavedFrame.Height());
1270 		Show();
1271 	}
1272 
1273 	_MarkSettingsItem(M_TOGGLE_FULLSCREEN, fIsFullscreen);
1274 
1275 	printf("_ToggleFullscreen leave\n");
1276 }
1277 
1278 void
1279 MainWin::_ToggleNoControls()
1280 {
1281 	printf("_ToggleNoControls enter\n");
1282 
1283 	if (fIsFullscreen) {
1284 		// fullscreen is always without menu
1285 		printf("_ToggleNoControls leave, doing nothing, we are fullscreen\n");
1286 		return;
1287 	}
1288 
1289 	fNoControls = !fNoControls;
1290 	_SetWindowSizeLimits();
1291 
1292 	if (fNoControls) {
1293 		ResizeBy(0, - fControlsHeight);
1294 	} else {
1295 		ResizeBy(0, fControlsHeight);
1296 	}
1297 
1298 	_MarkSettingsItem(M_TOGGLE_NO_CONTROLS, fNoControls);
1299 
1300 	printf("_ToggleNoControls leave\n");
1301 }
1302 
1303 void
1304 MainWin::_ToggleNoMenu()
1305 {
1306 	printf("_ToggleNoMenu enter\n");
1307 
1308 	if (fIsFullscreen) {
1309 		// fullscreen is always without menu
1310 		printf("_ToggleNoMenu leave, doing nothing, we are fullscreen\n");
1311 		return;
1312 	}
1313 
1314 	fNoMenu = !fNoMenu;
1315 	_SetWindowSizeLimits();
1316 
1317 	if (fNoMenu) {
1318 		MoveBy(0, fMenuBarHeight);
1319 		ResizeBy(0, - fMenuBarHeight);
1320 	} else {
1321 		MoveBy(0, - fMenuBarHeight);
1322 		ResizeBy(0, fMenuBarHeight);
1323 	}
1324 
1325 	_MarkSettingsItem(M_TOGGLE_NO_MENU, fNoMenu);
1326 
1327 	printf("_ToggleNoMenu leave\n");
1328 }
1329 
1330 
1331 void
1332 MainWin::_ToggleNoBorder()
1333 {
1334 	fNoBorder = !fNoBorder;
1335 	SetLook(fNoBorder ? B_BORDERED_WINDOW_LOOK : B_TITLED_WINDOW_LOOK);
1336 
1337 	_MarkSettingsItem(M_TOGGLE_NO_BORDER, fNoBorder);
1338 }
1339 
1340 
1341 void
1342 MainWin::_ToggleAlwaysOnTop()
1343 {
1344 	fAlwaysOnTop = !fAlwaysOnTop;
1345 	SetFeel(fAlwaysOnTop ? B_FLOATING_ALL_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL);
1346 
1347 	_MarkSettingsItem(M_TOGGLE_ALWAYS_ON_TOP, fAlwaysOnTop);
1348 }
1349 
1350 
1351 void
1352 MainWin::_ToggleKeepAspectRatio()
1353 {
1354 	fKeepAspectRatio = !fKeepAspectRatio;
1355 	FrameResized(Bounds().Width(), Bounds().Height());
1356 
1357 	_MarkSettingsItem(M_TOGGLE_KEEP_ASPECT_RATIO, fKeepAspectRatio);
1358 }
1359 
1360 
1361 // #pragma mark -
1362 
1363 
1364 void
1365 MainWin::_UpdateControlsEnabledStatus()
1366 {
1367 	uint32 enabledButtons = 0;
1368 	if (fHasVideo || fHasAudio) {
1369 		enabledButtons |= PLAYBACK_ENABLED | SEEK_ENABLED
1370 			| SEEK_BACK_ENABLED | SEEK_FORWARD_ENABLED;
1371 	}
1372 	if (fHasAudio)
1373 		enabledButtons |= VOLUME_ENABLED;
1374 
1375 	bool canSkipPrevious, canSkipNext;
1376 	fPlaylist->GetSkipInfo(&canSkipPrevious, &canSkipNext);
1377 	if (canSkipPrevious)
1378 		enabledButtons |= SKIP_BACK_ENABLED;
1379 	if (canSkipNext)
1380 		enabledButtons |= SKIP_FORWARD_ENABLED;
1381 
1382 	fControls->SetEnabled(enabledButtons);
1383 }
1384 
1385 
1386 void
1387 MainWin::_UpdatePlaylistMenu()
1388 {
1389 	if (!fPlaylist->Lock())
1390 		return;
1391 
1392 	fPlaylistMenu->RemoveItems(0, fPlaylistMenu->CountItems(), true);
1393 
1394 	int32 count = fPlaylist->CountItems();
1395 	for (int32 i = 0; i < count; i++) {
1396 		entry_ref ref;
1397 		if (fPlaylist->GetRefAt(i, &ref) < B_OK)
1398 			continue;
1399 		_AddPlaylistItem(ref, i);
1400 	}
1401 	fPlaylistMenu->SetTargetForItems(this);
1402 
1403 	_MarkPlaylistItem(fPlaylist->CurrentRefIndex());
1404 
1405 	fPlaylist->Unlock();
1406 }
1407 
1408 
1409 void
1410 MainWin::_AddPlaylistItem(const entry_ref& ref, int32 index)
1411 {
1412 	BMessage* message = new BMessage(M_SET_PLAYLIST_POSITION);
1413 	message->AddInt32("index", index);
1414 	BMenuItem* item = new BMenuItem(ref.name, message);
1415 	fPlaylistMenu->AddItem(item, index);
1416 }
1417 
1418 
1419 void
1420 MainWin::_RemovePlaylistItem(int32 index)
1421 {
1422 	delete fPlaylistMenu->RemoveItem(index);
1423 }
1424 
1425 
1426 void
1427 MainWin::_MarkPlaylistItem(int32 index)
1428 {
1429 	if (BMenuItem* item = fPlaylistMenu->ItemAt(index)) {
1430 		item->SetMarked(true);
1431 		// ... and in case the menu is currently on screen:
1432 		if (fPlaylistMenu->LockLooper()) {
1433 			fPlaylistMenu->Invalidate();
1434 			fPlaylistMenu->UnlockLooper();
1435 		}
1436 	}
1437 }
1438 
1439 
1440 void
1441 MainWin::_MarkSettingsItem(uint32 command, bool mark)
1442 {
1443 	if (BMenuItem* item = fSettingsMenu->FindItem(command))
1444 		item->SetMarked(mark);
1445 }
1446 
1447 
1448