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