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