xref: /haiku/src/apps/mediaplayer/MainWin.cpp (revision 04a91b97bde1b41f4100b923a1699ddeac36635b)
1 /*
2  * MainWin.cpp - Media Player for the Haiku Operating System
3  *
4  * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  *
19  */
20 #include "MainWin.h"
21 #include "MainApp.h"
22 #include "Controller.h"
23 #include "config.h"
24 #include "DeviceRoster.h"
25 
26 #include <View.h>
27 #include <Screen.h>
28 #include <Menu.h>
29 #include <MenuBar.h>
30 #include <MenuItem.h>
31 #include <Application.h>
32 #include <Alert.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <Messenger.h>
36 #include <PopUpMenu.h>
37 #include <String.h>
38 
39 enum
40 {
41 	M_DUMMY = 0x100,
42 	M_CHECK_TB,
43 	M_FILE_ABOUT,
44 	M_FILE_QUIT,
45 	M_SCALE_TO_NATIVE_SIZE,
46 	M_TOGGLE_FULLSCREEN,
47 	M_TOGGLE_NO_BORDER,
48 	M_TOGGLE_NO_MENU,
49 	M_TOGGLE_NO_BORDER_NO_MENU,
50 	M_TOGGLE_ALWAYS_ON_TOP,
51 	M_TOGGLE_KEEP_ASPECT_RATIO,
52 	M_PREFERENCES,
53 	M_CHANNEL_NEXT,
54 	M_CHANNEL_PREV,
55 	M_VOLUME_UP,
56 	M_VOLUME_DOWN,
57 	M_ASPECT_100000_1,
58 	M_ASPECT_106666_1,
59 	M_ASPECT_109091_1,
60 	M_ASPECT_141176_1,
61 	M_ASPECT_720_576,
62 	M_ASPECT_704_576,
63 	M_ASPECT_544_576,
64 	M_SELECT_INTERFACE		= 0x00000800,
65 	M_SELECT_INTERFACE_END	= 0x00000fff,
66 	M_SELECT_CHANNEL		= 0x00010000,
67 	M_SELECT_CHANNEL_END	= 0x000fffff, // this limits possible channel count to 0xeffff = 983039
68 };
69 
70 //#define printf(a...)
71 
72 
73 MainWin::MainWin(BRect frame_rect)
74  :	BWindow(frame_rect, NAME, B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS /* | B_WILL_ACCEPT_FIRST_CLICK */)
75  ,	fController(new Controller)
76  ,	fIsFullscreen(false)
77  ,	fKeepAspectRatio(true)
78  ,	fAlwaysOnTop(false)
79  ,	fNoMenu(false)
80  ,	fNoBorder(false)
81  ,	fSourceWidth(720)
82  ,	fSourceHeight(576)
83  ,	fWidthScale(1.0)
84  ,	fHeightScale(1.0)
85  ,	fMouseDownTracking(false)
86  ,	fFrameResizedTriggeredAutomatically(false)
87  ,	fIgnoreFrameResized(false)
88  ,	fFrameResizedCalled(true)
89 {
90 	BRect rect = Bounds();
91 
92 	// background
93 	fBackground = new BView(rect, "background", B_FOLLOW_ALL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
94 	fBackground->SetViewColor(0,0,0);
95 	AddChild(fBackground);
96 
97 	// menu
98 	fMenuBar = new BMenuBar(fBackground->Bounds(), "menu");
99 	CreateMenu();
100 	fBackground->AddChild(fMenuBar);
101 	fMenuBar->ResizeToPreferred();
102 	fMenuBarHeight = (int)fMenuBar->Frame().Height() + 1;
103 	fMenuBar->SetResizingMode(B_FOLLOW_TOP | B_FOLLOW_LEFT_RIGHT);
104 
105 	// video view
106 	BRect video_rect = BRect(0, fMenuBarHeight, rect.right, rect.bottom);
107 	fVideoView = new VideoView(video_rect, "video display", B_FOLLOW_ALL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
108 	fBackground->AddChild(fVideoView);
109 
110 	fVideoView->MakeFocus();
111 
112 //	SetSizeLimits(fControlViewMinWidth - 1, 32767,
113 //		fMenuBarHeight + fControlViewHeight - 1, fMenuBarHeight + fControlViewHeight - 1);
114 
115 //	SetSizeLimits(320 - 1, 32767, 240 + fMenuBarHeight - 1, 32767);
116 
117 	SetSizeLimits(0, 32767, fMenuBarHeight - 1, 32767);
118 
119 	fController->SetVideoView(fVideoView);
120 	fController->SetVideoNode(fVideoView->Node());
121 
122 	fVideoView->IsOverlaySupported();
123 
124 	SetupInterfaceMenu();
125 	SelectInitialInterface();
126 	SetInterfaceMenuMarker();
127 	SetupChannelMenu();
128 	SetChannelMenuMarker();
129 
130 	VideoFormatChange(fSourceWidth, fSourceHeight, fWidthScale, fHeightScale);
131 }
132 
133 
134 MainWin::~MainWin()
135 {
136 	printf("MainWin::~MainWin\n");
137 	fController->DisconnectInterface();
138 	delete fController;
139 }
140 
141 
142 void
143 MainWin::CreateMenu()
144 {
145 	fFileMenu = new BMenu(NAME);
146 	fChannelMenu = new BMenu("Channel");
147 	fInterfaceMenu = new BMenu("Interface");
148 	fSettingsMenu = new BMenu("Settings");
149 	fDebugMenu = new BMenu("Debug");
150 
151 	fMenuBar->AddItem(fFileMenu);
152 	fMenuBar->AddItem(fChannelMenu);
153 	fMenuBar->AddItem(fInterfaceMenu);
154 	fMenuBar->AddItem(fSettingsMenu);
155 	fMenuBar->AddItem(fDebugMenu);
156 
157 	fFileMenu->AddItem(new BMenuItem("About", new BMessage(M_FILE_ABOUT), 'A', B_COMMAND_KEY));
158 	fFileMenu->AddSeparatorItem();
159 	fFileMenu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q', B_COMMAND_KEY));
160 
161 
162 	fSettingsMenu->AddItem(new BMenuItem("Scale to native size", new BMessage(M_SCALE_TO_NATIVE_SIZE), 'N', B_COMMAND_KEY));
163 	fSettingsMenu->AddItem(new BMenuItem("Full Screen", new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
164 	fSettingsMenu->AddSeparatorItem();
165 	fSettingsMenu->AddItem(new BMenuItem("No Menu", new BMessage(M_TOGGLE_NO_MENU), 'M', B_COMMAND_KEY));
166 	fSettingsMenu->AddItem(new BMenuItem("No Border", new BMessage(M_TOGGLE_NO_BORDER), 'B', B_COMMAND_KEY));
167 	fSettingsMenu->AddItem(new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
168 	fSettingsMenu->AddItem(new BMenuItem("Keep Aspect Ratio", new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
169 	fSettingsMenu->AddSeparatorItem();
170 	fSettingsMenu->AddItem(new BMenuItem("Preferences"B_UTF8_ELLIPSIS, new BMessage(M_PREFERENCES), 'P', B_COMMAND_KEY));
171 
172 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", new BMessage(M_ASPECT_100000_1)));
173 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", new BMessage(M_ASPECT_106666_1)));
174 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.09091:1", new BMessage(M_ASPECT_109091_1)));
175 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.41176:1", new BMessage(M_ASPECT_141176_1)));
176 	fDebugMenu->AddItem(new BMenuItem("force 720 x 576, display aspect 4:3", new BMessage(M_ASPECT_720_576)));
177 	fDebugMenu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", new BMessage(M_ASPECT_704_576)));
178 	fDebugMenu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", new BMessage(M_ASPECT_544_576)));
179 
180 	fSettingsMenu->ItemAt(1)->SetMarked(fIsFullscreen);
181 	fSettingsMenu->ItemAt(3)->SetMarked(fNoMenu);
182 	fSettingsMenu->ItemAt(4)->SetMarked(fNoBorder);
183 	fSettingsMenu->ItemAt(5)->SetMarked(fAlwaysOnTop);
184 	fSettingsMenu->ItemAt(6)->SetMarked(fKeepAspectRatio);
185 	fSettingsMenu->ItemAt(8)->SetEnabled(false); // XXX disable unused preference menu
186 }
187 
188 
189 
190 bool
191 MainWin::QuitRequested()
192 {
193 	be_app->PostMessage(B_QUIT_REQUESTED);
194 	return true;
195 }
196 
197 
198 void
199 MainWin::MouseDown(BMessage *msg)
200 {
201 	BPoint screen_where;
202 	uint32 buttons = msg->FindInt32("buttons");
203 
204 	// On Zeta, only "screen_where" is relyable, "where" and "be:view_where" seem to be broken
205 	if (B_OK != msg->FindPoint("screen_where", &screen_where)) {
206 		// Workaround for BeOS R5, it has no "screen_where"
207 		fVideoView->GetMouse(&screen_where, &buttons, false);
208 		fVideoView->ConvertToScreen(&screen_where);
209 	}
210 
211 //	msg->PrintToStream();
212 
213 //	if (1 == msg->FindInt32("buttons") && msg->FindInt32("clicks") == 1) {
214 
215 	if (1 == buttons && msg->FindInt32("clicks") % 2 == 0) {
216 		BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1, screen_where.y + 1);
217 		if (r.Contains(fMouseDownMousePos)) {
218 			PostMessage(M_TOGGLE_FULLSCREEN);
219 			return;
220 		}
221 	}
222 
223 	if (2 == buttons && msg->FindInt32("clicks") % 2 == 0) {
224 		BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1, screen_where.y + 1);
225 		if (r.Contains(fMouseDownMousePos)) {
226 			PostMessage(M_TOGGLE_NO_BORDER_NO_MENU);
227 			return;
228 		}
229 	}
230 
231 /*
232 		// very broken in Zeta:
233 		fMouseDownMousePos = fVideoView->ConvertToScreen(msg->FindPoint("where"));
234 */
235 	fMouseDownMousePos = screen_where;
236 	fMouseDownWindowPos = Frame().LeftTop();
237 
238 	if (buttons == 1 && !fIsFullscreen) {
239 		// start mouse tracking
240 		fVideoView->SetMouseEventMask(B_POINTER_EVENTS | B_NO_POINTER_HISTORY /* | B_LOCK_WINDOW_FOCUS */);
241 		fMouseDownTracking = true;
242 	}
243 
244 	// pop up a context menu if right mouse button is down for 200 ms
245 
246 	if ((buttons & 2) == 0)
247 		return;
248 	bigtime_t start = system_time();
249 	bigtime_t delay = 200000;
250 	BPoint location;
251 	do {
252 		fVideoView->GetMouse(&location, &buttons);
253 		if ((buttons & 2) == 0)
254 			break;
255 		snooze(1000);
256 	} while (system_time() - start < delay);
257 
258 	if (buttons & 2)
259 		ShowContextMenu(screen_where);
260 }
261 
262 
263 void
264 MainWin::MouseMoved(BMessage *msg)
265 {
266 //	msg->PrintToStream();
267 
268 	BPoint mousePos;
269 	uint32 buttons = msg->FindInt32("buttons");
270 
271 	if (1 == buttons && fMouseDownTracking && !fIsFullscreen) {
272 /*
273 		// very broken in Zeta:
274 		BPoint mousePos = msg->FindPoint("where");
275 		printf("view where: %.0f, %.0f => ", mousePos.x, mousePos.y);
276 		fVideoView->ConvertToScreen(&mousePos);
277 */
278 		// On Zeta, only "screen_where" is relyable, "where" and "be:view_where" seem to be broken
279 		if (B_OK != msg->FindPoint("screen_where", &mousePos)) {
280 			// Workaround for BeOS R5, it has no "screen_where"
281 			fVideoView->GetMouse(&mousePos, &buttons, false);
282 			fVideoView->ConvertToScreen(&mousePos);
283 		}
284 //		printf("screen where: %.0f, %.0f => ", mousePos.x, mousePos.y);
285 		float delta_x = mousePos.x - fMouseDownMousePos.x;
286 		float delta_y = mousePos.y - fMouseDownMousePos.y;
287 		float x = fMouseDownWindowPos.x + delta_x;
288 		float y = fMouseDownWindowPos.y + delta_y;
289 //		printf("move window to %.0f, %.0f\n", x, y);
290 		MoveTo(x, y);
291 	}
292 }
293 
294 
295 void
296 MainWin::MouseUp(BMessage *msg)
297 {
298 //	msg->PrintToStream();
299 	fMouseDownTracking = false;
300 }
301 
302 
303 void
304 MainWin::ShowContextMenu(const BPoint &screen_point)
305 {
306 	printf("Show context menu\n");
307 	BPopUpMenu *menu = new BPopUpMenu("context menu", false, false);
308 	BMenuItem *item;
309 	menu->AddItem(new BMenuItem("Scale to native size", new BMessage(M_SCALE_TO_NATIVE_SIZE), 'N', B_COMMAND_KEY));
310 	menu->AddItem(item = new BMenuItem("Full Screen", new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
311 	item->SetMarked(fIsFullscreen);
312 	menu->AddSeparatorItem();
313 	menu->AddItem(item = new BMenuItem("No Menu", new BMessage(M_TOGGLE_NO_MENU), 'M', B_COMMAND_KEY));
314 	item->SetMarked(fNoMenu);
315 	menu->AddItem(item = new BMenuItem("No Border", new BMessage(M_TOGGLE_NO_BORDER), 'B', B_COMMAND_KEY));
316 	item->SetMarked(fNoBorder);
317 	menu->AddItem(item = new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
318 	item->SetMarked(fAlwaysOnTop);
319 	menu->AddItem(item = new BMenuItem("Keep Aspect Ratio", new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
320 	item->SetMarked(fKeepAspectRatio);
321 	menu->AddSeparatorItem();
322 	menu->AddItem(new BMenuItem("About", new BMessage(M_FILE_ABOUT), 'A', B_COMMAND_KEY));
323 	menu->AddSeparatorItem();
324 	menu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q', B_COMMAND_KEY));
325 
326 	menu->AddSeparatorItem();
327 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", new BMessage(M_ASPECT_100000_1)));
328 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", new BMessage(M_ASPECT_106666_1)));
329 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.09091:1", new BMessage(M_ASPECT_109091_1)));
330 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.41176:1", new BMessage(M_ASPECT_141176_1)));
331 	menu->AddItem(new BMenuItem("force 720 x 576, display aspect 4:3", new BMessage(M_ASPECT_720_576)));
332 	menu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", new BMessage(M_ASPECT_704_576)));
333 	menu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", new BMessage(M_ASPECT_544_576)));
334 
335 	menu->SetTargetForItems(this);
336 	BRect r(screen_point.x - 5, screen_point.y - 5, screen_point.x + 5, screen_point.y + 5);
337 	menu->Go(screen_point, true, true, r, true);
338 }
339 
340 
341 void
342 MainWin::VideoFormatChange(int width, int height, float width_scale, float height_scale)
343 {
344 	// called when video format or aspect ratio changes
345 
346 	printf("VideoFormatChange enter: width %d, height %d, width_scale %.6f, height_scale %.6f\n", width, height, width_scale, height_scale);
347 
348 	if (width_scale < 1.0 && height_scale >= 1.0) {
349 		width_scale  = 1.0 / width_scale;
350 		height_scale = 1.0 / height_scale;
351 		printf("inverting! new values: width_scale %.6f, height_scale %.6f\n", width_scale, height_scale);
352 	}
353 
354  	fSourceWidth  = width;
355  	fSourceHeight = height;
356  	fWidthScale   = width_scale;
357  	fHeightScale  = height_scale;
358 
359 //	ResizeWindow(Bounds().Width() + 1, Bounds().Height() + 1, true);
360 
361 	if (fIsFullscreen) {
362 		AdjustFullscreenRenderer();
363 	} else {
364 		AdjustWindowedRenderer(false);
365 	}
366 
367 	printf("VideoFormatChange leave\n");
368 
369 }
370 
371 
372 void
373 MainWin::Zoom(BPoint rec_position, float rec_width, float rec_height)
374 {
375 	PostMessage(M_TOGGLE_FULLSCREEN);
376 }
377 
378 
379 void
380 MainWin::FrameResized(float new_width, float new_height)
381 {
382 	// called when the window got resized
383 	fFrameResizedCalled = true;
384 
385 	if (new_width != Bounds().Width() || new_height != Bounds().Height()) {
386 		debugger("size wrong\n");
387 	}
388 
389 
390 	printf("FrameResized enter: new_width %.0f, new_height %.0f, bounds width %.0f, bounds height %.0f\n", new_width, new_height, Bounds().Width(), Bounds().Height());
391 
392 	if (fIsFullscreen) {
393 
394 		printf("FrameResized in fullscreen mode\n");
395 
396 		fIgnoreFrameResized = false;
397 		AdjustFullscreenRenderer();
398 
399 	} else {
400 
401 		if (fFrameResizedTriggeredAutomatically) {
402 			fFrameResizedTriggeredAutomatically = false;
403 			printf("FrameResized triggered automatically\n");
404 
405 			fIgnoreFrameResized = false;
406 
407 			AdjustWindowedRenderer(false);
408 		} else {
409 			printf("FrameResized by user in window mode\n");
410 
411 			if (fIgnoreFrameResized) {
412 				fIgnoreFrameResized = false;
413 				printf("FrameResized ignored\n");
414 				return;
415 			}
416 
417 			AdjustWindowedRenderer(true);
418 		}
419 
420 	}
421 
422 	printf("FrameResized leave\n");
423 }
424 
425 
426 
427 void
428 MainWin::UpdateWindowTitle()
429 {
430 	char buf[100];
431 	sprintf(buf, "%s - %d x %d, %.3f:%.3f => %.0f x %.0f", NAME, fSourceWidth, fSourceHeight, fWidthScale, fHeightScale, fVideoView->Bounds().Width() + 1, fVideoView->Bounds().Height() + 1);
432 	SetTitle(buf);
433 }
434 
435 
436 void
437 MainWin::AdjustFullscreenRenderer()
438 {
439 	// n.b. we don't have a menu in fullscreen mode!
440 
441 	if (fKeepAspectRatio) {
442 
443 		// Keep aspect ratio, place render inside
444 		// the background area (may create black bars).
445 		float max_width  = fBackground->Bounds().Width() + 1.0f;
446 		float max_height = fBackground->Bounds().Height() + 1.0f;
447 		float scaled_width  = fSourceWidth * fWidthScale;
448 		float scaled_height = fSourceHeight * fHeightScale;
449 		float factor = min_c(max_width / scaled_width, max_height / scaled_height);
450 		int render_width = int(scaled_width * factor);
451 		int render_height = int(scaled_height * factor);
452 		int x_ofs = (int(max_width) - render_width) / 2;
453 		int y_ofs = (int(max_height) - render_height) / 2;
454 
455 		printf("AdjustFullscreenRenderer: background %.1f x %.1f, src video %d x %d, "
456 			  "scaled video %.3f x %.3f, factor %.3f, render %d x %d, x-ofs %d, y-ofs %d\n",
457 			  max_width, max_height, fSourceWidth, fSourceHeight, scaled_width, scaled_height,
458 			  factor, render_width, render_height, x_ofs, y_ofs);
459 
460 		fVideoView->MoveTo(x_ofs, y_ofs);
461 		fVideoView->ResizeTo(render_width - 1, render_height - 1);
462 
463 	} else {
464 
465 		printf("AdjustFullscreenRenderer: using whole background area\n");
466 
467 		// no need to keep aspect ratio, make
468 		// render cover the whole background
469 		fVideoView->MoveTo(0, 0);
470 		fVideoView->ResizeTo(fBackground->Bounds().Width(), fBackground->Bounds().Height());
471 
472 	}
473 }
474 
475 
476 void
477 MainWin::AdjustWindowedRenderer(bool user_resized)
478 {
479 	printf("AdjustWindowedRenderer enter - user_resized %d\n", user_resized);
480 
481 	// In windowed mode, the renderer always covers the
482 	// whole background, accounting for the menu
483 	fVideoView->MoveTo(0, fNoMenu ? 0 : fMenuBarHeight);
484 	fVideoView->ResizeTo(fBackground->Bounds().Width(), fBackground->Bounds().Height() - (fNoMenu ? 0 : fMenuBarHeight));
485 
486 	if (fKeepAspectRatio) {
487 		// To keep the aspect ratio correct, we
488 		// do resize the window as required
489 
490 		float max_width  = Bounds().Width() + 1.0f;
491 		float max_height = Bounds().Height() + 1.0f - (fNoMenu ? 0 : fMenuBarHeight);
492 		float scaled_width  = fSourceWidth * fWidthScale;
493 		float scaled_height = fSourceHeight * fHeightScale;
494 
495 		if (!user_resized && (scaled_width > max_width || scaled_height > max_height)) {
496 			// A format switch occured, and the window was
497 			// smaller then the video source. As it was not
498 			// initiated by the user resizing the window, we
499 			// enlarge the window to fit the video.
500 			fIgnoreFrameResized = true;
501 			ResizeTo(scaled_width - 1, scaled_height - 1 + (fNoMenu ? 0 : fMenuBarHeight));
502 //			Sync();
503 			return;
504 		}
505 
506 		float display_aspect_ratio = scaled_width / scaled_height;
507 		int new_width  = int(max_width);
508 		int new_height = int(max_width / display_aspect_ratio + 0.5);
509 
510 		printf("AdjustWindowedRenderer: old display %d x %d, src video %d x %d, "
511 			  "scaled video %.3f x %.3f, aspect ratio %.3f, new display %d x %d\n",
512 			  int(max_width), int(max_height), fSourceWidth, fSourceHeight, scaled_width, scaled_height,
513 			  display_aspect_ratio, new_width, new_height);
514 
515 		fIgnoreFrameResized = true;
516 		ResizeTo(new_width - 1, new_height - 1 + (fNoMenu ? 0 : fMenuBarHeight));
517 //		Sync();
518 	}
519 
520 	printf("AdjustWindowedRenderer leave\n");
521 }
522 
523 
524 void
525 MainWin::ToggleNoBorderNoMenu()
526 {
527 	if (!fNoMenu && fNoBorder) {
528 		// if no border, switch of menu, too
529 		PostMessage(M_TOGGLE_NO_MENU);
530 	} else
531 	if (fNoMenu && !fNoBorder) {
532 		// if no menu, switch of border, too
533 		PostMessage(M_TOGGLE_NO_BORDER);
534 	} else {
535 		// both are either on or off, toggle both
536 		PostMessage(M_TOGGLE_NO_MENU);
537 		PostMessage(M_TOGGLE_NO_BORDER);
538 	}
539 }
540 
541 
542 void
543 MainWin::ToggleFullscreen()
544 {
545 	printf("ToggleFullscreen enter\n");
546 
547 	if (!fFrameResizedCalled) {
548 		printf("ToggleFullscreen - ignoring, as FrameResized wasn't called since last switch\n");
549 		return;
550 	}
551 	fFrameResizedCalled = false;
552 
553 
554 	fIsFullscreen = !fIsFullscreen;
555 
556 	if (fIsFullscreen) {
557 		// switch to fullscreen
558 
559 		fSavedFrame = Frame();
560 		printf("saving current frame: %d %d %d %d\n", int(fSavedFrame.left), int(fSavedFrame.top), int(fSavedFrame.right), int(fSavedFrame.bottom));
561 		BScreen screen(this);
562 		BRect rect(screen.Frame());
563 
564 		Hide();
565 		if (!fNoMenu) {
566 			// if we have a menu, remove it now
567 			fMenuBar->Hide();
568 		}
569 		fFrameResizedTriggeredAutomatically = true;
570 		MoveTo(rect.left, rect.top);
571 		ResizeTo(rect.Width(), rect.Height());
572 		Show();
573 
574 	} else {
575 		// switch back from full screen mode
576 
577 		Hide();
578 		// if we need a menu, show it now
579 		if (!fNoMenu) {
580 			fMenuBar->Show();
581 		}
582 		fFrameResizedTriggeredAutomatically = true;
583 		MoveTo(fSavedFrame.left, fSavedFrame.top);
584 		ResizeTo(fSavedFrame.Width(), fSavedFrame.Height());
585 		Show();
586 
587 	}
588 
589 	// FrameResized() will do the required adjustments
590 
591 	printf("ToggleFullscreen leave\n");
592 }
593 
594 
595 void
596 MainWin::ToggleNoMenu()
597 {
598 	printf("ToggleNoMenu enter\n");
599 
600 	fNoMenu = !fNoMenu;
601 
602 	if (fIsFullscreen) {
603 		// fullscreen is always without menu
604 		printf("ToggleNoMenu leave, doing nothing, we are fullscreen\n");
605 		return;
606 	}
607 
608 //	fFrameResizedTriggeredAutomatically = true;
609 	fIgnoreFrameResized = true;
610 
611 	if (fNoMenu) {
612 		fMenuBar->Hide();
613 		fVideoView->MoveTo(0, 0);
614 		fVideoView->ResizeBy(0, fMenuBarHeight);
615 		MoveBy(0, fMenuBarHeight);
616 		ResizeBy(0, - fMenuBarHeight);
617 //		Sync();
618 	} else {
619 		fMenuBar->Show();
620 		fVideoView->MoveTo(0, fMenuBarHeight);
621 		fVideoView->ResizeBy(0, -fMenuBarHeight);
622 		MoveBy(0, - fMenuBarHeight);
623 		ResizeBy(0, fMenuBarHeight);
624 //		Sync();
625 	}
626 
627 	printf("ToggleNoMenu leave\n");
628 }
629 
630 
631 void
632 MainWin::ToggleNoBorder()
633 {
634 	printf("ToggleNoBorder enter\n");
635 	fNoBorder = !fNoBorder;
636 //	SetLook(fNoBorder ? B_NO_BORDER_WINDOW_LOOK : B_TITLED_WINDOW_LOOK);
637 	SetLook(fNoBorder ? B_BORDERED_WINDOW_LOOK : B_TITLED_WINDOW_LOOK);
638 	printf("ToggleNoBorder leave\n");
639 }
640 
641 
642 void
643 MainWin::ToggleAlwaysOnTop()
644 {
645 	printf("ToggleAlwaysOnTop enter\n");
646 	fAlwaysOnTop = !fAlwaysOnTop;
647 	SetFeel(fAlwaysOnTop ? B_FLOATING_ALL_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL);
648 	printf("ToggleAlwaysOnTop leave\n");
649 }
650 
651 
652 void
653 MainWin::ToggleKeepAspectRatio()
654 {
655 	printf("ToggleKeepAspectRatio enter\n");
656 	fKeepAspectRatio = !fKeepAspectRatio;
657 
658 	fFrameResizedTriggeredAutomatically = true;
659 	FrameResized(Bounds().Width(), Bounds().Height());
660 //	if (fIsFullscreen) {
661 //		AdjustFullscreenRenderer();
662 //	} else {
663 //		AdjustWindowedRenderer(false);
664 //	}
665 	printf("ToggleKeepAspectRatio leave\n");
666 }
667 
668 
669 /* Trap keys that are about to be send to background or renderer view.
670  * Return B_OK if it shouldn't be passed to the view
671  */
672 status_t
673 MainWin::KeyDown(BMessage *msg)
674 {
675 //	msg->PrintToStream();
676 
677 	uint32 key		 = msg->FindInt32("key");
678 	uint32 raw_char  = msg->FindInt32("raw_char");
679 	uint32 modifiers = msg->FindInt32("modifiers");
680 
681 	printf("key 0x%lx, raw_char 0x%lx, modifiers 0x%lx\n", key, raw_char, modifiers);
682 
683 	switch (raw_char) {
684 		case B_SPACE:
685 			PostMessage(M_TOGGLE_NO_BORDER_NO_MENU);
686 			return B_OK;
687 
688 		case B_ESCAPE:
689 			if (fIsFullscreen) {
690 				PostMessage(M_TOGGLE_FULLSCREEN);
691 				return B_OK;
692 			} else
693 				break;
694 
695 		case B_ENTER:		// Enter / Return
696 			if (modifiers & B_COMMAND_KEY) {
697 				PostMessage(M_TOGGLE_FULLSCREEN);
698 				return B_OK;
699 			} else
700 				break;
701 
702 		case B_TAB:
703 			if ((modifiers & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY | B_MENU_KEY)) == 0) {
704 				PostMessage(M_TOGGLE_FULLSCREEN);
705 				return B_OK;
706 			} else
707 				break;
708 
709 		case B_UP_ARROW:
710 			if (modifiers & B_COMMAND_KEY) {
711 				PostMessage(M_CHANNEL_NEXT);
712 			} else {
713 				PostMessage(M_VOLUME_UP);
714 			}
715 			return B_OK;
716 
717 		case B_DOWN_ARROW:
718 			if (modifiers & B_COMMAND_KEY) {
719 				PostMessage(M_CHANNEL_PREV);
720 			} else {
721 				PostMessage(M_VOLUME_DOWN);
722 			}
723 			return B_OK;
724 
725 		case B_RIGHT_ARROW:
726 			if (modifiers & B_COMMAND_KEY) {
727 				PostMessage(M_VOLUME_UP);
728 			} else {
729 				PostMessage(M_CHANNEL_NEXT);
730 			}
731 			return B_OK;
732 
733 		case B_LEFT_ARROW:
734 			if (modifiers & B_COMMAND_KEY) {
735 				PostMessage(M_VOLUME_DOWN);
736 			} else {
737 				PostMessage(M_CHANNEL_PREV);
738 			}
739 			return B_OK;
740 
741 		case B_PAGE_UP:
742 			PostMessage(M_CHANNEL_NEXT);
743 			return B_OK;
744 
745 		case B_PAGE_DOWN:
746 			PostMessage(M_CHANNEL_PREV);
747 			return B_OK;
748 	}
749 
750 	switch (key) {
751 		case 0x3a:  		// numeric keypad +
752 			if ((modifiers & B_COMMAND_KEY) == 0) {
753 				printf("if\n");
754 				PostMessage(M_VOLUME_UP);
755 				return B_OK;
756 			} else {
757 				printf("else\n");
758 				break;
759 			}
760 
761 		case 0x25:  		// numeric keypad -
762 			if ((modifiers & B_COMMAND_KEY) == 0) {
763 				PostMessage(M_VOLUME_DOWN);
764 				return B_OK;
765 			} else {
766 				break;
767 			}
768 
769 		case 0x38:			// numeric keypad up arrow
770 			PostMessage(M_VOLUME_UP);
771 			return B_OK;
772 
773 		case 0x59:			// numeric keypad down arrow
774 			PostMessage(M_VOLUME_DOWN);
775 			return B_OK;
776 
777 		case 0x39:			// numeric keypad page up
778 		case 0x4a:			// numeric keypad right arrow
779 			PostMessage(M_CHANNEL_NEXT);
780 			return B_OK;
781 
782 		case 0x5a:			// numeric keypad page down
783 		case 0x48:			// numeric keypad left arrow
784 			PostMessage(M_CHANNEL_PREV);
785 			return B_OK;
786 	}
787 
788 	return B_ERROR;
789 }
790 
791 
792 void
793 MainWin::DispatchMessage(BMessage *msg, BHandler *handler)
794 {
795 	if ((msg->what == B_MOUSE_DOWN) && (handler == fBackground || handler == fVideoView))
796 		MouseDown(msg);
797 	if ((msg->what == B_MOUSE_MOVED) && (handler == fBackground || handler == fVideoView))
798 		MouseMoved(msg);
799 	if ((msg->what == B_MOUSE_UP) && (handler == fBackground || handler == fVideoView))
800 		MouseUp(msg);
801 
802 	if ((msg->what == B_KEY_DOWN) && (handler == fBackground || handler == fVideoView)) {
803 
804 		// special case for PrintScreen key
805 		if (msg->FindInt32("key") == B_PRINT_KEY) {
806 			fVideoView->OverlayScreenshotPrepare();
807 			BWindow::DispatchMessage(msg, handler);
808 			fVideoView->OverlayScreenshotCleanup();
809 			return;
810 		}
811 
812 		// every other key gets dispatched to our KeyDown first
813 		if (KeyDown(msg) == B_OK) {
814 			// it got handled, don't pass it on
815 			return;
816 		}
817 	}
818 
819 	BWindow::DispatchMessage(msg, handler);
820 }
821 
822 
823 void
824 MainWin::MessageReceived(BMessage *msg)
825 {
826 	switch (msg->what) {
827 		case B_ACQUIRE_OVERLAY_LOCK:
828 			printf("B_ACQUIRE_OVERLAY_LOCK\n");
829 			fVideoView->OverlayLockAcquire();
830 			break;
831 
832 		case B_RELEASE_OVERLAY_LOCK:
833 			printf("B_RELEASE_OVERLAY_LOCK\n");
834 			fVideoView->OverlayLockRelease();
835 			break;
836 
837 		case B_MOUSE_WHEEL_CHANGED:
838 		{
839 			printf("B_MOUSE_WHEEL_CHANGED\n");
840 			float dx = msg->FindFloat("be:wheel_delta_x");
841 			float dy = msg->FindFloat("be:wheel_delta_y");
842 			bool inv = modifiers() & B_COMMAND_KEY;
843 			if (dx > 0.1)	PostMessage(inv ? M_VOLUME_DOWN : M_CHANNEL_PREV);
844 			if (dx < -0.1)	PostMessage(inv ? M_VOLUME_UP : M_CHANNEL_NEXT);
845 			if (dy > 0.1)	PostMessage(inv ? M_CHANNEL_PREV : M_VOLUME_DOWN);
846 			if (dy < -0.1)	PostMessage(inv ? M_CHANNEL_NEXT : M_VOLUME_UP);
847 			break;
848 		}
849 
850 		case M_CHANNEL_NEXT:
851 		{
852 			printf("M_CHANNEL_NEXT\n");
853 			int chan = fController->CurrentChannel();
854 			if (chan != -1) {
855 				chan++;
856 				if (chan < fController->ChannelCount())
857 					SelectChannel(chan);
858 			}
859 			break;
860 		}
861 
862 		case M_CHANNEL_PREV:
863 		{
864 			printf("M_CHANNEL_PREV\n");
865 			int chan = fController->CurrentChannel();
866 			if (chan != -1) {
867 				chan--;
868 				if (chan >= 0)
869 					SelectChannel(chan);
870 			}
871 			break;
872 		}
873 
874 		case M_VOLUME_UP:
875 			printf("M_VOLUME_UP\n");
876 			fController->VolumeUp();
877 			break;
878 
879 		case M_VOLUME_DOWN:
880 			printf("M_VOLUME_DOWN\n");
881 			fController->VolumeDown();
882 			break;
883 
884 		case M_ASPECT_100000_1:
885 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.0, 1.0);
886 			break;
887 
888 		case M_ASPECT_106666_1:
889 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.06666, 1.0);
890 			break;
891 
892 		case M_ASPECT_109091_1:
893 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.09091, 1.0);
894 			break;
895 
896 		case M_ASPECT_141176_1:
897 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.41176, 1.0);
898 			break;
899 
900 		case M_ASPECT_720_576:
901 			VideoFormatChange(720, 576, 1.06666, 1.0);
902 			break;
903 
904 		case M_ASPECT_704_576:
905 			VideoFormatChange(704, 576, 1.09091, 1.0);
906 			break;
907 
908 		case M_ASPECT_544_576:
909 			VideoFormatChange(544, 576, 1.41176, 1.0);
910 			break;
911 
912 		case B_REFS_RECEIVED:
913 			printf("MainWin::MessageReceived: B_REFS_RECEIVED\n");
914 //			RefsReceived(msg);
915 			break;
916 
917 		case B_SIMPLE_DATA:
918 			printf("MainWin::MessageReceived: B_SIMPLE_DATA\n");
919 //			if (msg->HasRef("refs"))
920 //				RefsReceived(msg);
921 			break;
922 
923 		case M_FILE_ABOUT:
924 			BAlert *alert;
925 			alert = new BAlert("about", NAME"\n\n"
926 			INFO1
927 			"\n\nCopyright "COPYRIGHT"\n\nVersion "VERSION"\n\nRevision "REVISION"\n\nBuild "BUILD, "Thanks");
928 			if (fAlwaysOnTop) {
929 				ToggleAlwaysOnTop();
930 				alert->Go();
931 				ToggleAlwaysOnTop();
932 			} else {
933 				alert->Go();
934 			}
935 			break;
936 
937 		case M_FILE_QUIT:
938 //			be_app->PostMessage(B_QUIT_REQUESTED);
939 			PostMessage(B_QUIT_REQUESTED);
940 			break;
941 
942 		case M_SCALE_TO_NATIVE_SIZE:
943 			printf("M_SCALE_TO_NATIVE_SIZE\n");
944 			if (fIsFullscreen) {
945 				ToggleFullscreen();
946 			}
947 			ResizeTo(int(fSourceWidth * fWidthScale),
948 					 int(fSourceHeight * fHeightScale) + (fNoMenu ? 0 : fMenuBarHeight));
949 //			Sync();
950 			break;
951 
952 		case M_TOGGLE_FULLSCREEN:
953 			ToggleFullscreen();
954 			fSettingsMenu->ItemAt(1)->SetMarked(fIsFullscreen);
955 			break;
956 
957 		case M_TOGGLE_NO_MENU:
958 			ToggleNoMenu();
959 			fSettingsMenu->ItemAt(3)->SetMarked(fNoMenu);
960 			break;
961 
962 		case M_TOGGLE_NO_BORDER:
963 			ToggleNoBorder();
964 			fSettingsMenu->ItemAt(4)->SetMarked(fNoBorder);
965 			break;
966 
967 		case M_TOGGLE_ALWAYS_ON_TOP:
968 			ToggleAlwaysOnTop();
969 			fSettingsMenu->ItemAt(5)->SetMarked(fAlwaysOnTop);
970 			break;
971 
972 		case M_TOGGLE_KEEP_ASPECT_RATIO:
973 			ToggleKeepAspectRatio();
974 			fSettingsMenu->ItemAt(6)->SetMarked(fKeepAspectRatio);
975 			break;
976 
977 		case M_TOGGLE_NO_BORDER_NO_MENU:
978 			ToggleNoBorderNoMenu();
979 			break;
980 
981 		case M_PREFERENCES:
982 			break;
983 
984 		default:
985 			if (msg->what >= M_SELECT_CHANNEL && msg->what <= M_SELECT_CHANNEL_END) {
986 				SelectChannel(msg->what - M_SELECT_CHANNEL);
987 				break;
988 			}
989 			if (msg->what >= M_SELECT_INTERFACE && msg->what <= M_SELECT_INTERFACE_END) {
990 				SelectInterface(msg->what - M_SELECT_INTERFACE - 1);
991 				break;
992 			}
993 	}
994 }
995