HaikuDepot: notify work status from main window
[haiku.git] / src / apps / tv / MainWin.cpp
blobe9a54b4fd521d55a14587ce7b72fa3a24b6a5b80
1 /*
2 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
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:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
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.
25 #include "MainWin.h"
26 #include "MainApp.h"
27 #include "Controller.h"
28 #include "config.h"
29 #include "DeviceRoster.h"
31 #include <stdio.h>
32 #include <string.h>
34 #include <Application.h>
35 #include <Alert.h>
36 #include <Menu.h>
37 #include <MenuBar.h>
38 #include <MenuItem.h>
39 #include <Messenger.h>
40 #include <PopUpMenu.h>
41 #include <Screen.h>
42 #include <String.h>
43 #include <View.h>
46 #undef B_TRANSLATION_CONTEXT
47 #define B_TRANSLATION_CONTEXT "MainWin"
49 B_TRANSLATE_MARK_VOID("TV");
50 B_TRANSLATE_MARK_VOID("unknown");
51 B_TRANSLATE_MARK_VOID("DVB - Digital Video Broadcasting TV");
53 enum
55 M_DUMMY = 0x100,
56 M_FILE_QUIT,
57 M_SCALE_TO_NATIVE_SIZE,
58 M_TOGGLE_FULLSCREEN,
59 M_TOGGLE_NO_BORDER,
60 M_TOGGLE_NO_MENU,
61 M_TOGGLE_NO_BORDER_NO_MENU,
62 M_TOGGLE_ALWAYS_ON_TOP,
63 M_TOGGLE_KEEP_ASPECT_RATIO,
64 M_PREFERENCES,
65 M_CHANNEL_NEXT,
66 M_CHANNEL_PREV,
67 M_VOLUME_UP,
68 M_VOLUME_DOWN,
69 M_ASPECT_100000_1,
70 M_ASPECT_106666_1,
71 M_ASPECT_109091_1,
72 M_ASPECT_141176_1,
73 M_ASPECT_720_576,
74 M_ASPECT_704_576,
75 M_ASPECT_544_576,
76 M_SELECT_INTERFACE = 0x00000800,
77 M_SELECT_INTERFACE_END = 0x00000fff,
78 M_SELECT_CHANNEL = 0x00010000,
79 M_SELECT_CHANNEL_END = 0x000fffff,
80 // this limits possible channel count to 0xeffff = 983039
83 //#define printf(a...)
86 MainWin::MainWin(BRect frame_rect)
88 BWindow(frame_rect, B_TRANSLATE_SYSTEM_NAME(NAME), B_TITLED_WINDOW,
89 B_ASYNCHRONOUS_CONTROLS /* | B_WILL_ACCEPT_FIRST_CLICK */)
90 , fController(new Controller)
91 , fIsFullscreen(false)
92 , fKeepAspectRatio(true)
93 , fAlwaysOnTop(false)
94 , fNoMenu(false)
95 , fNoBorder(false)
96 , fSourceWidth(720)
97 , fSourceHeight(576)
98 , fWidthScale(1.0)
99 , fHeightScale(1.0)
100 , fMouseDownTracking(false)
101 , fFrameResizedTriggeredAutomatically(false)
102 , fIgnoreFrameResized(false)
103 , fFrameResizedCalled(true)
105 BRect rect = Bounds();
107 // background
108 fBackground = new BView(rect, "background", B_FOLLOW_ALL,
109 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
110 fBackground->SetViewColor(0,0,0);
111 AddChild(fBackground);
113 // menu
114 fMenuBar = new BMenuBar(fBackground->Bounds(), "menu");
115 CreateMenu();
116 fBackground->AddChild(fMenuBar);
117 fMenuBar->ResizeToPreferred();
118 fMenuBarHeight = (int)fMenuBar->Frame().Height() + 1;
119 fMenuBar->SetResizingMode(B_FOLLOW_TOP | B_FOLLOW_LEFT_RIGHT);
121 // video view
122 BRect video_rect = BRect(0, fMenuBarHeight, rect.right, rect.bottom);
123 fVideoView = new VideoView(video_rect, "video display", B_FOLLOW_ALL,
124 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
125 fBackground->AddChild(fVideoView);
127 fVideoView->MakeFocus();
129 // SetSizeLimits(fControlViewMinWidth - 1, 32767,
130 // fMenuBarHeight + fControlViewHeight - 1, fMenuBarHeight
131 // + fControlViewHeight - 1);
133 // SetSizeLimits(320 - 1, 32767, 240 + fMenuBarHeight - 1, 32767);
135 SetSizeLimits(0, 32767, fMenuBarHeight - 1, 32767);
137 fController->SetVideoView(fVideoView);
138 fController->SetVideoNode(fVideoView->Node());
140 fVideoView->IsOverlaySupported();
142 SetupInterfaceMenu();
143 SelectInitialInterface();
144 SetInterfaceMenuMarker();
145 SetupChannelMenu();
146 SetChannelMenuMarker();
148 VideoFormatChange(fSourceWidth, fSourceHeight, fWidthScale, fHeightScale);
150 CenterOnScreen();
154 MainWin::~MainWin()
156 printf("MainWin::~MainWin\n");
157 fController->DisconnectInterface();
158 delete fController;
162 void
163 MainWin::CreateMenu()
165 fFileMenu = new BMenu(B_TRANSLATE(NAME));
166 fChannelMenu = new BMenu(B_TRANSLATE("Channel"));
167 fInterfaceMenu = new BMenu(B_TRANSLATE("Interface"));
168 fSettingsMenu = new BMenu(B_TRANSLATE("Settings"));
169 fDebugMenu = new BMenu(B_TRANSLATE("Debug"));
171 fMenuBar->AddItem(fFileMenu);
172 fMenuBar->AddItem(fChannelMenu);
173 fMenuBar->AddItem(fInterfaceMenu);
174 fMenuBar->AddItem(fSettingsMenu);
175 fMenuBar->AddItem(fDebugMenu);
177 fFileMenu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
178 new BMessage(M_FILE_QUIT), 'Q', B_COMMAND_KEY));
181 fChannelMenu->AddItem(new BMenuItem(B_TRANSLATE("Next channel"),
182 new BMessage(M_CHANNEL_NEXT), '+', B_COMMAND_KEY));
183 fChannelMenu->AddItem(new BMenuItem(B_TRANSLATE("Previous channel"),
184 new BMessage(M_CHANNEL_PREV), '-', B_COMMAND_KEY));
185 fChannelMenu->AddSeparatorItem();
186 fChannelMenu->AddItem(new BMenuItem("RTL", new BMessage(M_DUMMY), '0',
187 B_COMMAND_KEY));
188 fChannelMenu->AddItem(new BMenuItem("Pro7", new BMessage(M_DUMMY), '1',
189 B_COMMAND_KEY));
191 fInterfaceMenu->AddItem(new BMenuItem(B_TRANSLATE("none"),
192 new BMessage(M_DUMMY)));
193 fInterfaceMenu->AddItem(new BMenuItem(B_TRANSLATE("none 1"),
194 new BMessage(M_DUMMY)));
195 fInterfaceMenu->AddItem(new BMenuItem(B_TRANSLATE("none 2"),
196 new BMessage(M_DUMMY)));
199 fSettingsMenu->AddItem(new BMenuItem(B_TRANSLATE("Scale to native size"),
200 new BMessage(M_SCALE_TO_NATIVE_SIZE), 'N', B_COMMAND_KEY));
201 fSettingsMenu->AddItem(new BMenuItem(B_TRANSLATE("Full screen"),
202 new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
203 fSettingsMenu->AddSeparatorItem();
204 fSettingsMenu->AddItem(new BMenuItem(B_TRANSLATE("No menu"),
205 new BMessage(M_TOGGLE_NO_MENU), 'M', B_COMMAND_KEY));
206 fSettingsMenu->AddItem(new BMenuItem(B_TRANSLATE("No border"),
207 new BMessage(M_TOGGLE_NO_BORDER), 'B', B_COMMAND_KEY));
208 fSettingsMenu->AddItem(new BMenuItem(B_TRANSLATE("Always on top"),
209 new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
210 fSettingsMenu->AddItem(new BMenuItem(B_TRANSLATE("Keep aspect ratio"),
211 new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
212 fSettingsMenu->AddSeparatorItem();
213 fSettingsMenu->AddItem(new BMenuItem(B_TRANSLATE("Settings" B_UTF8_ELLIPSIS)
214 , new BMessage(M_PREFERENCES), 'P', B_COMMAND_KEY));
216 const char* pixel_ratio = B_TRANSLATE("pixel aspect ratio");
217 BString str1 = pixel_ratio;
218 str1 << " 1.00000:1";
219 fDebugMenu->AddItem(new BMenuItem(str1.String(),
220 new BMessage(M_ASPECT_100000_1)));
221 BString str2 = pixel_ratio;
222 str2 << " 1.06666:1";
223 fDebugMenu->AddItem(new BMenuItem(str2.String(),
224 new BMessage(M_ASPECT_106666_1)));
225 BString str3 = pixel_ratio;
226 str3 << " 1.09091:1";
227 fDebugMenu->AddItem(new BMenuItem(str3.String(),
228 new BMessage(M_ASPECT_109091_1)));
229 BString str4 = pixel_ratio;
230 str4 << " 1.41176:1";
231 fDebugMenu->AddItem(new BMenuItem(str4.String(),
232 new BMessage(M_ASPECT_141176_1)));
233 fDebugMenu->AddItem(new BMenuItem(B_TRANSLATE(
234 "force 720 x 576, display aspect 4:3"),
235 new BMessage(M_ASPECT_720_576)));
236 fDebugMenu->AddItem(new BMenuItem(B_TRANSLATE(
237 "force 704 x 576, display aspect 4:3"),
238 new BMessage(M_ASPECT_704_576)));
239 fDebugMenu->AddItem(new BMenuItem(B_TRANSLATE(
240 "force 544 x 576, display aspect 4:3"),
241 new BMessage(M_ASPECT_544_576)));
243 fSettingsMenu->ItemAt(1)->SetMarked(fIsFullscreen);
244 fSettingsMenu->ItemAt(3)->SetMarked(fNoMenu);
245 fSettingsMenu->ItemAt(4)->SetMarked(fNoBorder);
246 fSettingsMenu->ItemAt(5)->SetMarked(fAlwaysOnTop);
247 fSettingsMenu->ItemAt(6)->SetMarked(fKeepAspectRatio);
248 fSettingsMenu->ItemAt(8)->SetEnabled(false);
249 // XXX disable unused preference menu
253 void
254 MainWin::SetupInterfaceMenu()
256 fInterfaceMenu->RemoveItems(0, fInterfaceMenu->CountItems(), true);
258 fInterfaceMenu->AddItem(new BMenuItem(B_TRANSLATE("None"),
259 new BMessage(M_SELECT_INTERFACE)));
261 int count = gDeviceRoster->DeviceCount();
263 if (count > 0)
264 fInterfaceMenu->AddSeparatorItem();
266 for (int i = 0; i < count; i++) {
267 // 1 gets subtracted in MessageReceived, so -1 is Interface None,
268 // and 0 == Interface 0 in SelectInterface()
269 fInterfaceMenu->AddItem(new BMenuItem(gDeviceRoster->DeviceName(i),
270 new BMessage(M_SELECT_INTERFACE + i + 1)));
275 void
276 MainWin::SetupChannelMenu()
278 fChannelMenu->RemoveItems(0, fChannelMenu->CountItems(), true);
280 int interface = fController->CurrentInterface();
281 printf("MainWin::SetupChannelMenu: interface %d\n", interface);
283 int channels = fController->ChannelCount();
285 if (channels == 0) {
286 fChannelMenu->AddItem(new BMenuItem(B_TRANSLATE("None"),
287 new BMessage(M_DUMMY)));
288 } else {
289 fChannelMenu->AddItem(new BMenuItem(B_TRANSLATE("Next channel"),
290 new BMessage(M_CHANNEL_NEXT), '+', B_COMMAND_KEY));
291 fChannelMenu->AddItem(new BMenuItem(B_TRANSLATE("Previous channel"),
292 new BMessage(M_CHANNEL_PREV), '-', B_COMMAND_KEY));
293 fChannelMenu->AddSeparatorItem();
296 for (int i = 0; i < channels; i++) {
297 BString string;
298 string.SetToFormat("%s%d %s", (i < 9) ? " " : "", i + 1,
299 fController->ChannelName(i));
300 fChannelMenu->AddItem(new BMenuItem(string,
301 new BMessage(M_SELECT_CHANNEL + i)));
306 void
307 MainWin::SetInterfaceMenuMarker()
309 BMenuItem *item;
311 int interface = fController->CurrentInterface();
312 printf("MainWin::SetInterfaceMenuMarker: interface %d\n", interface);
314 // remove old marker
315 item = fInterfaceMenu->FindMarked();
316 if (item)
317 item->SetMarked(false);
319 // set new marker
320 int index = (interface < 0) ? 0 : interface + 2;
321 item = fInterfaceMenu->ItemAt(index);
322 if (item)
323 item->SetMarked(true);
327 void
328 MainWin::SetChannelMenuMarker()
330 BMenuItem *item;
332 int channel = fController->CurrentChannel();
333 printf("MainWin::SetChannelMenuMarker: channel %d\n", channel);
335 // remove old marker
336 item = fChannelMenu->FindMarked();
337 if (item)
338 item->SetMarked(false);
340 // set new marker
341 int index = (channel < 0) ? 0 : channel + 3;
342 item = fChannelMenu->ItemAt(index);
343 if (item)
344 item->SetMarked(true);
348 void
349 MainWin::SelectChannel(int i)
351 printf("MainWin::SelectChannel %d\n", i);
353 if (B_OK != fController->SelectChannel(i))
354 return;
356 SetChannelMenuMarker();
360 void
361 MainWin::SelectInterface(int i)
363 printf("MainWin::SelectInterface %d\n", i);
364 printf(" CurrentInterface %d\n", fController->CurrentInterface());
365 printf(" CurrentChannel %d\n", fController->CurrentChannel());
367 // i = -1 means "None"
369 if (i < 0) {
370 fController->DisconnectInterface();
371 goto done;
374 if (!fController->IsInterfaceAvailable(i)) {
375 BString s;
376 s << B_TRANSLATE("Error, interface is busy:\n\n");
377 s << gDeviceRoster->DeviceName(i);
378 BAlert* alert = new BAlert("error", s.String(), B_TRANSLATE("OK"));
379 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
380 alert->Go();
381 return;
384 fController->DisconnectInterface();
385 if (fController->ConnectInterface(i) != B_OK) {
386 BString s;
387 s << B_TRANSLATE("Error, connecting to interface failed:\n\n");
388 s << gDeviceRoster->DeviceName(i);
389 BAlert* alert = new BAlert("error", s.String(), B_TRANSLATE("OK"));
390 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
391 alert->Go();
394 done:
395 printf("MainWin::SelectInterface done:\n");
396 printf(" CurrentInterface %d\n", fController->CurrentInterface());
397 printf(" CurrentChannel %d\n", fController->CurrentChannel());
399 SetInterfaceMenuMarker();
400 SetupChannelMenu();
401 SetChannelMenuMarker();
405 void
406 MainWin::SelectInitialInterface()
408 printf("MainWin::SelectInitialInterface enter\n");
410 int count = gDeviceRoster->DeviceCount();
411 for (int i = 0; i < count; i++) {
412 if (fController->IsInterfaceAvailable(i)
413 && B_OK == fController->ConnectInterface(i)) {
414 printf("MainWin::SelectInitialInterface connected to interface "
415 "%d\n", i);
416 break;
420 printf("MainWin::SelectInitialInterface leave\n");
424 bool
425 MainWin::QuitRequested()
427 be_app->PostMessage(B_QUIT_REQUESTED);
428 return true;
432 void
433 MainWin::MouseDown(BMessage *msg)
435 BPoint screen_where;
436 uint32 buttons = msg->FindInt32("buttons");
438 // On Zeta, only "screen_where" is relyable, "where" and "be:view_where"
439 // seem to be broken
440 if (B_OK != msg->FindPoint("screen_where", &screen_where)) {
441 // Workaround for BeOS R5, it has no "screen_where"
442 fVideoView->GetMouse(&screen_where, &buttons, false);
443 fVideoView->ConvertToScreen(&screen_where);
446 // msg->PrintToStream();
448 // if (1 == msg->FindInt32("buttons") && msg->FindInt32("clicks") == 1) {
450 if (1 == buttons && msg->FindInt32("clicks") % 2 == 0) {
451 BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1,
452 screen_where.y + 1);
453 if (r.Contains(fMouseDownMousePos)) {
454 PostMessage(M_TOGGLE_FULLSCREEN);
455 return;
459 if (2 == buttons && msg->FindInt32("clicks") % 2 == 0) {
460 BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1,
461 screen_where.y + 1);
462 if (r.Contains(fMouseDownMousePos)) {
463 PostMessage(M_TOGGLE_NO_BORDER_NO_MENU);
464 return;
469 // very broken in Zeta:
470 fMouseDownMousePos = fVideoView->ConvertToScreen(
471 msg->FindPoint("where"));
473 fMouseDownMousePos = screen_where;
474 fMouseDownWindowPos = Frame().LeftTop();
476 if (buttons == 1 && !fIsFullscreen) {
477 // start mouse tracking
478 fVideoView->SetMouseEventMask(B_POINTER_EVENTS | B_NO_POINTER_HISTORY
479 /* | B_LOCK_WINDOW_FOCUS */);
480 fMouseDownTracking = true;
483 // pop up a context menu if right mouse button is down for 200 ms
485 if ((buttons & 2) == 0)
486 return;
487 bigtime_t start = system_time();
488 bigtime_t delay = 200000;
489 BPoint location;
490 do {
491 fVideoView->GetMouse(&location, &buttons);
492 if ((buttons & 2) == 0)
493 break;
494 snooze(1000);
495 } while (system_time() - start < delay);
497 if (buttons & 2)
498 ShowContextMenu(screen_where);
502 void
503 MainWin::MouseMoved(BMessage *msg)
505 // msg->PrintToStream();
507 BPoint mousePos;
508 uint32 buttons = msg->FindInt32("buttons");
510 if (1 == buttons && fMouseDownTracking && !fIsFullscreen) {
512 // very broken in Zeta:
513 BPoint mousePos = msg->FindPoint("where");
514 printf("view where: %.0f, %.0f => ", mousePos.x, mousePos.y);
515 fVideoView->ConvertToScreen(&mousePos);
517 // On Zeta, only "screen_where" is relyable, "where" and
518 // "be:view_where" seem to be broken
519 if (B_OK != msg->FindPoint("screen_where", &mousePos)) {
520 // Workaround for BeOS R5, it has no "screen_where"
521 fVideoView->GetMouse(&mousePos, &buttons, false);
522 fVideoView->ConvertToScreen(&mousePos);
524 // printf("screen where: %.0f, %.0f => ", mousePos.x, mousePos.y);
525 float delta_x = mousePos.x - fMouseDownMousePos.x;
526 float delta_y = mousePos.y - fMouseDownMousePos.y;
527 float x = fMouseDownWindowPos.x + delta_x;
528 float y = fMouseDownWindowPos.y + delta_y;
529 // printf("move window to %.0f, %.0f\n", x, y);
530 MoveTo(x, y);
535 void
536 MainWin::MouseUp(BMessage *msg)
538 // msg->PrintToStream();
539 fMouseDownTracking = false;
543 void
544 MainWin::ShowContextMenu(const BPoint &screen_point)
546 printf("Show context menu\n");
547 BPopUpMenu *menu = new BPopUpMenu("context menu", false, false);
548 BMenuItem *item;
549 menu->AddItem(new BMenuItem(B_TRANSLATE("Scale to native size"),
550 new BMessage(M_SCALE_TO_NATIVE_SIZE), 'N', B_COMMAND_KEY));
551 menu->AddItem(item = new BMenuItem(B_TRANSLATE("Full screen"),
552 new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
553 item->SetMarked(fIsFullscreen);
554 menu->AddSeparatorItem();
555 menu->AddItem(item = new BMenuItem(B_TRANSLATE("No menu"),
556 new BMessage(M_TOGGLE_NO_MENU), 'M', B_COMMAND_KEY));
557 item->SetMarked(fNoMenu);
558 menu->AddItem(item = new BMenuItem(B_TRANSLATE("No border"),
559 new BMessage(M_TOGGLE_NO_BORDER), 'B', B_COMMAND_KEY));
560 item->SetMarked(fNoBorder);
561 menu->AddItem(item = new BMenuItem(B_TRANSLATE("Always on top"),
562 new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
563 item->SetMarked(fAlwaysOnTop);
564 menu->AddItem(item = new BMenuItem(B_TRANSLATE("Keep aspect ratio"),
565 new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
566 item->SetMarked(fKeepAspectRatio);
567 menu->AddSeparatorItem();
568 menu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
569 new BMessage(M_FILE_QUIT), 'Q', B_COMMAND_KEY));
571 menu->AddSeparatorItem();
572 const char* pixel_aspect = "pixel aspect ratio";
573 BString str1 = pixel_aspect;
574 str1 << " 1.00000:1";
575 menu->AddItem(new BMenuItem(str1.String(),
576 new BMessage(M_ASPECT_100000_1)));
577 BString str2 = pixel_aspect;
578 str2 << " 1.06666:1";
579 menu->AddItem(new BMenuItem(str2.String(),
580 new BMessage(M_ASPECT_106666_1)));
581 BString str3 = pixel_aspect;
582 str3 << " 1.09091:1";
583 menu->AddItem(new BMenuItem(str3.String(),
584 new BMessage(M_ASPECT_109091_1)));
585 BString str4 = pixel_aspect;
586 str4 << " 1.41176:1";
587 menu->AddItem(new BMenuItem(str4.String(),
588 new BMessage(M_ASPECT_141176_1)));
589 menu->AddItem(new BMenuItem(B_TRANSLATE(
590 "force 720 x 576, display aspect 4:3"),
591 new BMessage(M_ASPECT_720_576)));
592 menu->AddItem(new BMenuItem(B_TRANSLATE(
593 "force 704 x 576, display aspect 4:3"),
594 new BMessage(M_ASPECT_704_576)));
595 menu->AddItem(new BMenuItem(B_TRANSLATE(
596 "force 544 x 576, display aspect 4:3"),
597 new BMessage(M_ASPECT_544_576)));
599 menu->SetTargetForItems(this);
600 BRect r(screen_point.x - 5, screen_point.y - 5, screen_point.x + 5,
601 screen_point.y + 5);
602 menu->Go(screen_point, true, true, r, true);
606 void
607 MainWin::VideoFormatChange(int width, int height, float width_scale,
608 float height_scale)
610 // called when video format or aspect ratio changes
612 printf("VideoFormatChange enter: width %d, height %d, width_scale %.6f, "
613 "height_scale %.6f\n", width, height, width_scale, height_scale);
615 if (width_scale < 1.0 && height_scale >= 1.0) {
616 width_scale = 1.0 / width_scale;
617 height_scale = 1.0 / height_scale;
618 printf("inverting! new values: width_scale %.6f, height_scale %.6f\n",
619 width_scale, height_scale);
622 fSourceWidth = width;
623 fSourceHeight = height;
624 fWidthScale = width_scale;
625 fHeightScale = height_scale;
627 // ResizeWindow(Bounds().Width() + 1, Bounds().Height() + 1, true);
629 if (fIsFullscreen) {
630 AdjustFullscreenRenderer();
631 } else {
632 AdjustWindowedRenderer(false);
635 printf("VideoFormatChange leave\n");
640 void
641 MainWin::Zoom(BPoint rec_position, float rec_width, float rec_height)
643 PostMessage(M_TOGGLE_FULLSCREEN);
647 void
648 MainWin::FrameResized(float new_width, float new_height)
650 // called when the window got resized
651 fFrameResizedCalled = true;
653 if (new_width != Bounds().Width() || new_height != Bounds().Height()) {
654 debugger("size wrong\n");
658 printf("FrameResized enter: new_width %.0f, new_height %.0f, bounds width "
659 "%.0f, bounds height %.0f\n", new_width, new_height, Bounds().Width(),
660 Bounds().Height());
662 if (fIsFullscreen) {
664 printf("FrameResized in fullscreen mode\n");
666 fIgnoreFrameResized = false;
667 AdjustFullscreenRenderer();
669 } else {
671 if (fFrameResizedTriggeredAutomatically) {
672 fFrameResizedTriggeredAutomatically = false;
673 printf("FrameResized triggered automatically\n");
675 fIgnoreFrameResized = false;
677 AdjustWindowedRenderer(false);
678 } else {
679 printf("FrameResized by user in window mode\n");
681 if (fIgnoreFrameResized) {
682 fIgnoreFrameResized = false;
683 printf("FrameResized ignored\n");
684 return;
687 AdjustWindowedRenderer(true);
692 printf("FrameResized leave\n");
697 void
698 MainWin::UpdateWindowTitle()
700 BString title;
701 title.SetToFormat("%s - %d x %d, %.3f:%.3f => %.0f x %.0f",
702 B_TRANSLATE_SYSTEM_NAME(NAME),
703 fSourceWidth, fSourceHeight, fWidthScale, fHeightScale,
704 fVideoView->Bounds().Width() + 1, fVideoView->Bounds().Height() + 1);
705 SetTitle(title);
709 void
710 MainWin::AdjustFullscreenRenderer()
712 // n.b. we don't have a menu in fullscreen mode!
714 if (fKeepAspectRatio) {
716 // Keep aspect ratio, place render inside
717 // the background area (may create black bars).
718 float max_width = fBackground->Bounds().Width() + 1.0f;
719 float max_height = fBackground->Bounds().Height() + 1.0f;
720 float scaled_width = fSourceWidth * fWidthScale;
721 float scaled_height = fSourceHeight * fHeightScale;
722 float factor = min_c(max_width / scaled_width, max_height
723 / scaled_height);
724 int render_width = int(scaled_width * factor);
725 int render_height = int(scaled_height * factor);
726 int x_ofs = (int(max_width) - render_width) / 2;
727 int y_ofs = (int(max_height) - render_height) / 2;
729 printf("AdjustFullscreenRenderer: background %.1f x %.1f, src video "
730 "%d x %d, scaled video %.3f x %.3f, factor %.3f, render %d x %d, "
731 "x-ofs %d, y-ofs %d\n", max_width, max_height, fSourceWidth,
732 fSourceHeight, scaled_width, scaled_height, factor, render_width,
733 render_height, x_ofs, y_ofs);
735 fVideoView->MoveTo(x_ofs, y_ofs);
736 fVideoView->ResizeTo(render_width - 1, render_height - 1);
738 } else {
740 printf("AdjustFullscreenRenderer: using whole background area\n");
742 // no need to keep aspect ratio, make
743 // render cover the whole background
744 fVideoView->MoveTo(0, 0);
745 fVideoView->ResizeTo(fBackground->Bounds().Width(),
746 fBackground->Bounds().Height());
752 void
753 MainWin::AdjustWindowedRenderer(bool user_resized)
755 printf("AdjustWindowedRenderer enter - user_resized %d\n", user_resized);
757 // In windowed mode, the renderer always covers the
758 // whole background, accounting for the menu
759 fVideoView->MoveTo(0, fNoMenu ? 0 : fMenuBarHeight);
760 fVideoView->ResizeTo(fBackground->Bounds().Width(),
761 fBackground->Bounds().Height() - (fNoMenu ? 0 : fMenuBarHeight));
763 if (fKeepAspectRatio) {
764 // To keep the aspect ratio correct, we
765 // do resize the window as required
767 float max_width = Bounds().Width() + 1.0f;
768 float max_height = Bounds().Height() + 1.0f - (fNoMenu ? 0
769 : fMenuBarHeight);
770 float scaled_width = fSourceWidth * fWidthScale;
771 float scaled_height = fSourceHeight * fHeightScale;
773 if (!user_resized && (scaled_width > max_width
774 || scaled_height > max_height)) {
775 // A format switch occured, and the window was
776 // smaller then the video source. As it was not
777 // initiated by the user resizing the window, we
778 // enlarge the window to fit the video.
779 fIgnoreFrameResized = true;
780 ResizeTo(scaled_width - 1, scaled_height - 1
781 + (fNoMenu ? 0 : fMenuBarHeight));
782 // Sync();
783 return;
786 float display_aspect_ratio = scaled_width / scaled_height;
787 int new_width = int(max_width);
788 int new_height = int(max_width / display_aspect_ratio + 0.5);
790 printf("AdjustWindowedRenderer: old display %d x %d, src video "
791 "%d x %d, scaled video %.3f x %.3f, aspect ratio %.3f, new "
792 "display %d x %d\n", int(max_width), int(max_height),
793 fSourceWidth, fSourceHeight, scaled_width, scaled_height,
794 display_aspect_ratio, new_width, new_height);
796 fIgnoreFrameResized = true;
797 ResizeTo(new_width - 1, new_height - 1 + (fNoMenu ? 0
798 : fMenuBarHeight));
799 // Sync();
802 printf("AdjustWindowedRenderer leave\n");
806 void
807 MainWin::ToggleNoBorderNoMenu()
809 if (!fNoMenu && fNoBorder) {
810 // if no border, switch of menu, too
811 PostMessage(M_TOGGLE_NO_MENU);
812 } else
813 if (fNoMenu && !fNoBorder) {
814 // if no menu, switch of border, too
815 PostMessage(M_TOGGLE_NO_BORDER);
816 } else {
817 // both are either on or off, toggle both
818 PostMessage(M_TOGGLE_NO_MENU);
819 PostMessage(M_TOGGLE_NO_BORDER);
824 void
825 MainWin::ToggleFullscreen()
827 printf("ToggleFullscreen enter\n");
829 if (!fFrameResizedCalled) {
830 printf("ToggleFullscreen - ignoring, as FrameResized wasn't called "
831 "since last switch\n");
832 return;
834 fFrameResizedCalled = false;
837 fIsFullscreen = !fIsFullscreen;
839 if (fIsFullscreen) {
840 // switch to fullscreen
842 // Sync here is probably not required
843 // Sync();
845 fSavedFrame = Frame();
846 printf("saving current frame: %d %d %d %d\n", int(fSavedFrame.left),
847 int(fSavedFrame.top), int(fSavedFrame.right),
848 int(fSavedFrame.bottom));
849 BScreen screen(this);
850 BRect rect(screen.Frame());
852 Hide();
853 if (!fNoMenu) {
854 // if we have a menu, remove it now
855 fMenuBar->Hide();
857 fFrameResizedTriggeredAutomatically = true;
858 MoveTo(rect.left, rect.top);
859 ResizeTo(rect.Width(), rect.Height());
860 Show();
862 // Sync();
864 } else {
865 // switch back from full screen mode
867 Hide();
868 // if we need a menu, show it now
869 if (!fNoMenu) {
870 fMenuBar->Show();
872 fFrameResizedTriggeredAutomatically = true;
873 MoveTo(fSavedFrame.left, fSavedFrame.top);
874 ResizeTo(fSavedFrame.Width(), fSavedFrame.Height());
875 Show();
877 // We *must* make sure that the window is at
878 // the correct position before continuing, or
879 // rapid fullscreen switching by holding down
880 // the TAB key will expose strange bugs.
881 // Never remove this Sync!
882 // Sync();
885 // FrameResized() will do the required adjustments
887 printf("ToggleFullscreen leave\n");
891 void
892 MainWin::ToggleNoMenu()
894 printf("ToggleNoMenu enter\n");
896 fNoMenu = !fNoMenu;
898 if (fIsFullscreen) {
899 // fullscreen is always without menu
900 printf("ToggleNoMenu leave, doing nothing, we are fullscreen\n");
901 return;
904 // fFrameResizedTriggeredAutomatically = true;
905 fIgnoreFrameResized = true;
907 if (fNoMenu) {
908 fMenuBar->Hide();
909 fVideoView->MoveTo(0, 0);
910 fVideoView->ResizeBy(0, fMenuBarHeight);
911 MoveBy(0, fMenuBarHeight);
912 ResizeBy(0, - fMenuBarHeight);
913 // Sync();
914 } else {
915 fMenuBar->Show();
916 fVideoView->MoveTo(0, fMenuBarHeight);
917 fVideoView->ResizeBy(0, -fMenuBarHeight);
918 MoveBy(0, - fMenuBarHeight);
919 ResizeBy(0, fMenuBarHeight);
920 // Sync();
923 printf("ToggleNoMenu leave\n");
927 void
928 MainWin::ToggleNoBorder()
930 printf("ToggleNoBorder enter\n");
931 fNoBorder = !fNoBorder;
932 // SetLook(fNoBorder ? B_NO_BORDER_WINDOW_LOOK : B_TITLED_WINDOW_LOOK);
933 SetLook(fNoBorder ? B_BORDERED_WINDOW_LOOK : B_TITLED_WINDOW_LOOK);
934 printf("ToggleNoBorder leave\n");
938 void
939 MainWin::ToggleAlwaysOnTop()
941 printf("ToggleAlwaysOnTop enter\n");
942 fAlwaysOnTop = !fAlwaysOnTop;
943 SetFeel(fAlwaysOnTop ? B_FLOATING_ALL_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL);
944 printf("ToggleAlwaysOnTop leave\n");
948 void
949 MainWin::ToggleKeepAspectRatio()
951 printf("ToggleKeepAspectRatio enter\n");
952 fKeepAspectRatio = !fKeepAspectRatio;
954 fFrameResizedTriggeredAutomatically = true;
955 FrameResized(Bounds().Width(), Bounds().Height());
956 // if (fIsFullscreen) {
957 // AdjustFullscreenRenderer();
958 // } else {
959 // AdjustWindowedRenderer(false);
960 // }
961 printf("ToggleKeepAspectRatio leave\n");
965 /* Trap keys that are about to be send to background or renderer view.
966 * Return B_OK if it shouldn't be passed to the view
968 status_t
969 MainWin::KeyDown(BMessage *msg)
971 // msg->PrintToStream();
973 uint32 key = msg->FindInt32("key");
974 uint32 raw_char = msg->FindInt32("raw_char");
975 uint32 modifiers = msg->FindInt32("modifiers");
977 printf("key 0x%" B_PRIx32 ", raw_char 0x%" B_PRIx32 ", modifiers 0x%" B_PRIx32 "\n", key, raw_char,
978 modifiers);
980 switch (raw_char) {
981 case B_SPACE:
982 PostMessage(M_TOGGLE_NO_BORDER_NO_MENU);
983 return B_OK;
985 case B_ESCAPE:
986 if (fIsFullscreen) {
987 PostMessage(M_TOGGLE_FULLSCREEN);
988 return B_OK;
989 } else
990 break;
992 case B_ENTER: // Enter / Return
993 if (modifiers & B_COMMAND_KEY) {
994 PostMessage(M_TOGGLE_FULLSCREEN);
995 return B_OK;
996 } else
997 break;
999 case B_TAB:
1000 if ((modifiers & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY
1001 | B_MENU_KEY)) == 0) {
1002 PostMessage(M_TOGGLE_FULLSCREEN);
1003 return B_OK;
1004 } else
1005 break;
1007 case B_UP_ARROW:
1008 if (modifiers & B_COMMAND_KEY) {
1009 PostMessage(M_CHANNEL_NEXT);
1010 } else {
1011 PostMessage(M_VOLUME_UP);
1013 return B_OK;
1015 case B_DOWN_ARROW:
1016 if (modifiers & B_COMMAND_KEY) {
1017 PostMessage(M_CHANNEL_PREV);
1018 } else {
1019 PostMessage(M_VOLUME_DOWN);
1021 return B_OK;
1023 case B_RIGHT_ARROW:
1024 if (modifiers & B_COMMAND_KEY) {
1025 PostMessage(M_VOLUME_UP);
1026 } else {
1027 PostMessage(M_CHANNEL_NEXT);
1029 return B_OK;
1031 case B_LEFT_ARROW:
1032 if (modifiers & B_COMMAND_KEY) {
1033 PostMessage(M_VOLUME_DOWN);
1034 } else {
1035 PostMessage(M_CHANNEL_PREV);
1037 return B_OK;
1039 case B_PAGE_UP:
1040 PostMessage(M_CHANNEL_NEXT);
1041 return B_OK;
1043 case B_PAGE_DOWN:
1044 PostMessage(M_CHANNEL_PREV);
1045 return B_OK;
1048 switch (key) {
1049 case 0x3a: // numeric keypad +
1050 if ((modifiers & B_COMMAND_KEY) == 0) {
1051 printf("if\n");
1052 PostMessage(M_VOLUME_UP);
1053 return B_OK;
1054 } else {
1055 printf("else\n");
1056 break;
1059 case 0x25: // numeric keypad -
1060 if ((modifiers & B_COMMAND_KEY) == 0) {
1061 PostMessage(M_VOLUME_DOWN);
1062 return B_OK;
1063 } else {
1064 break;
1067 case 0x38: // numeric keypad up arrow
1068 PostMessage(M_VOLUME_UP);
1069 return B_OK;
1071 case 0x59: // numeric keypad down arrow
1072 PostMessage(M_VOLUME_DOWN);
1073 return B_OK;
1075 case 0x39: // numeric keypad page up
1076 case 0x4a: // numeric keypad right arrow
1077 PostMessage(M_CHANNEL_NEXT);
1078 return B_OK;
1080 case 0x5a: // numeric keypad page down
1081 case 0x48: // numeric keypad left arrow
1082 PostMessage(M_CHANNEL_PREV);
1083 return B_OK;
1086 return B_ERROR;
1090 void
1091 MainWin::DispatchMessage(BMessage *msg, BHandler *handler)
1093 if ((msg->what == B_MOUSE_DOWN) && (handler == fBackground
1094 || handler == fVideoView))
1095 MouseDown(msg);
1096 if ((msg->what == B_MOUSE_MOVED) && (handler == fBackground
1097 || handler == fVideoView))
1098 MouseMoved(msg);
1099 if ((msg->what == B_MOUSE_UP) && (handler == fBackground
1100 || handler == fVideoView))
1101 MouseUp(msg);
1103 if ((msg->what == B_KEY_DOWN) && (handler == fBackground
1104 || handler == fVideoView)) {
1106 // special case for PrintScreen key
1107 if (msg->FindInt32("key") == B_PRINT_KEY) {
1108 fVideoView->OverlayScreenshotPrepare();
1109 BWindow::DispatchMessage(msg, handler);
1110 fVideoView->OverlayScreenshotCleanup();
1111 return;
1114 // every other key gets dispatched to our KeyDown first
1115 if (KeyDown(msg) == B_OK) {
1116 // it got handled, don't pass it on
1117 return;
1121 BWindow::DispatchMessage(msg, handler);
1125 void
1126 MainWin::MessageReceived(BMessage *msg)
1128 switch (msg->what) {
1129 case B_ACQUIRE_OVERLAY_LOCK:
1130 printf("B_ACQUIRE_OVERLAY_LOCK\n");
1131 fVideoView->OverlayLockAcquire();
1132 break;
1134 case B_RELEASE_OVERLAY_LOCK:
1135 printf("B_RELEASE_OVERLAY_LOCK\n");
1136 fVideoView->OverlayLockRelease();
1137 break;
1139 case B_MOUSE_WHEEL_CHANGED:
1141 printf("B_MOUSE_WHEEL_CHANGED\n");
1142 float dx = msg->FindFloat("be:wheel_delta_x");
1143 float dy = msg->FindFloat("be:wheel_delta_y");
1144 bool inv = modifiers() & B_COMMAND_KEY;
1145 if (dx > 0.1) PostMessage(inv ? M_VOLUME_DOWN : M_CHANNEL_PREV);
1146 if (dx < -0.1) PostMessage(inv ? M_VOLUME_UP : M_CHANNEL_NEXT);
1147 if (dy > 0.1) PostMessage(inv ? M_CHANNEL_PREV : M_VOLUME_DOWN);
1148 if (dy < -0.1) PostMessage(inv ? M_CHANNEL_NEXT : M_VOLUME_UP);
1149 break;
1152 case M_CHANNEL_NEXT:
1154 printf("M_CHANNEL_NEXT\n");
1155 int chan = fController->CurrentChannel();
1156 if (chan != -1) {
1157 chan++;
1158 if (chan < fController->ChannelCount())
1159 SelectChannel(chan);
1161 break;
1164 case M_CHANNEL_PREV:
1166 printf("M_CHANNEL_PREV\n");
1167 int chan = fController->CurrentChannel();
1168 if (chan != -1) {
1169 chan--;
1170 if (chan >= 0)
1171 SelectChannel(chan);
1173 break;
1176 case M_VOLUME_UP:
1177 printf("M_VOLUME_UP\n");
1178 fController->VolumeUp();
1179 break;
1181 case M_VOLUME_DOWN:
1182 printf("M_VOLUME_DOWN\n");
1183 fController->VolumeDown();
1184 break;
1186 case M_ASPECT_100000_1:
1187 VideoFormatChange(fSourceWidth, fSourceHeight, 1.0, 1.0);
1188 break;
1190 case M_ASPECT_106666_1:
1191 VideoFormatChange(fSourceWidth, fSourceHeight, 1.06666, 1.0);
1192 break;
1194 case M_ASPECT_109091_1:
1195 VideoFormatChange(fSourceWidth, fSourceHeight, 1.09091, 1.0);
1196 break;
1198 case M_ASPECT_141176_1:
1199 VideoFormatChange(fSourceWidth, fSourceHeight, 1.41176, 1.0);
1200 break;
1202 case M_ASPECT_720_576:
1203 VideoFormatChange(720, 576, 1.06666, 1.0);
1204 break;
1206 case M_ASPECT_704_576:
1207 VideoFormatChange(704, 576, 1.09091, 1.0);
1208 break;
1210 case M_ASPECT_544_576:
1211 VideoFormatChange(544, 576, 1.41176, 1.0);
1212 break;
1214 case B_REFS_RECEIVED:
1215 printf("MainWin::MessageReceived: B_REFS_RECEIVED\n");
1216 // RefsReceived(msg);
1217 break;
1219 case B_SIMPLE_DATA:
1220 printf("MainWin::MessageReceived: B_SIMPLE_DATA\n");
1221 // if (msg->HasRef("refs"))
1222 // RefsReceived(msg);
1223 break;
1225 case M_FILE_QUIT:
1226 // be_app->PostMessage(B_QUIT_REQUESTED);
1227 PostMessage(B_QUIT_REQUESTED);
1228 break;
1230 case M_SCALE_TO_NATIVE_SIZE:
1231 printf("M_SCALE_TO_NATIVE_SIZE\n");
1232 if (fIsFullscreen) {
1233 ToggleFullscreen();
1235 ResizeTo(int(fSourceWidth * fWidthScale),
1236 int(fSourceHeight * fHeightScale) + (fNoMenu ? 0
1237 : fMenuBarHeight));
1238 // Sync();
1239 break;
1241 case M_TOGGLE_FULLSCREEN:
1242 ToggleFullscreen();
1243 fSettingsMenu->ItemAt(1)->SetMarked(fIsFullscreen);
1244 break;
1246 case M_TOGGLE_NO_MENU:
1247 ToggleNoMenu();
1248 fSettingsMenu->ItemAt(3)->SetMarked(fNoMenu);
1249 break;
1251 case M_TOGGLE_NO_BORDER:
1252 ToggleNoBorder();
1253 fSettingsMenu->ItemAt(4)->SetMarked(fNoBorder);
1254 break;
1256 case M_TOGGLE_ALWAYS_ON_TOP:
1257 ToggleAlwaysOnTop();
1258 fSettingsMenu->ItemAt(5)->SetMarked(fAlwaysOnTop);
1259 break;
1261 case M_TOGGLE_KEEP_ASPECT_RATIO:
1262 ToggleKeepAspectRatio();
1263 fSettingsMenu->ItemAt(6)->SetMarked(fKeepAspectRatio);
1264 break;
1266 case M_TOGGLE_NO_BORDER_NO_MENU:
1267 ToggleNoBorderNoMenu();
1268 break;
1270 case M_PREFERENCES:
1271 break;
1273 default:
1274 if (msg->what >= M_SELECT_CHANNEL
1275 && msg->what <= M_SELECT_CHANNEL_END) {
1276 SelectChannel(msg->what - M_SELECT_CHANNEL);
1277 break;
1279 if (msg->what >= M_SELECT_INTERFACE
1280 && msg->what <= M_SELECT_INTERFACE_END) {
1281 SelectInterface(msg->what - M_SELECT_INTERFACE - 1);
1282 break;