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