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