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