btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / mediaplayer / InfoWin.cpp
blob12f9e64b7da938b70edb8495137093871e59bf1f
1 /*
2 * InfoWin.cpp - Media Player for the Haiku Operating System
4 * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
5 * Copyright 2015 Axel Dörfler <axeld@pinc-software.de>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * version 2 as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include "InfoWin.h"
25 #include <math.h>
26 #include <stdio.h>
27 #include <string.h>
29 #include <Bitmap.h>
30 #include <Catalog.h>
31 #include <ControlLook.h>
32 #include <Debug.h>
33 #include <LayoutBuilder.h>
34 #include <MediaDefs.h>
35 #include <MessageFormat.h>
36 #include <Mime.h>
37 #include <NodeInfo.h>
38 #include <Screen.h>
39 #include <String.h>
40 #include <StringForRate.h>
41 #include <StringView.h>
42 #include <TextView.h>
44 #include "Controller.h"
45 #include "ControllerObserver.h"
46 #include "PlaylistItem.h"
49 #define MIN_WIDTH 500
52 #undef B_TRANSLATION_CONTEXT
53 #define B_TRANSLATION_CONTEXT "MediaPlayer-InfoWin"
56 class IconView : public BView {
57 public:
58 IconView(const char* name, int32 iconSize);
59 virtual ~IconView();
61 status_t SetIcon(const PlaylistItem* item);
62 status_t SetIcon(const char* mimeType);
63 void SetGenericIcon();
65 virtual void GetPreferredSize(float* _width, float* _height);
66 virtual void AttachedToWindow();
67 virtual void Draw(BRect updateRect);
69 private:
70 BBitmap* fIconBitmap;
74 IconView::IconView(const char* name, int32 iconSize)
76 BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
77 fIconBitmap(NULL)
79 fIconBitmap = new BBitmap(BRect(0, 0, iconSize - 1, iconSize - 1),
80 B_RGBA32);
81 SetExplicitMaxSize(PreferredSize());
85 IconView::~IconView()
87 delete fIconBitmap;
91 status_t
92 IconView::SetIcon(const PlaylistItem* item)
94 return item->GetIcon(fIconBitmap, B_LARGE_ICON);
98 status_t
99 IconView::SetIcon(const char* mimeTypeString)
101 if (!mimeTypeString)
102 return B_BAD_VALUE;
104 // get type icon
105 BMimeType mimeType(mimeTypeString);
106 status_t status = mimeType.GetIcon(fIconBitmap, B_LARGE_ICON);
108 // get supertype icon
109 if (status != B_OK) {
110 BMimeType superType;
111 status = mimeType.GetSupertype(&superType);
112 if (status == B_OK)
113 status = superType.GetIcon(fIconBitmap, B_LARGE_ICON);
116 return status;
120 void
121 IconView::SetGenericIcon()
123 // get default icon
124 BMimeType genericType(B_FILE_MIME_TYPE);
125 if (genericType.GetIcon(fIconBitmap, B_LARGE_ICON) != B_OK) {
126 // clear bitmap
127 uint8 transparent = 0;
128 if (fIconBitmap->ColorSpace() == B_CMAP8)
129 transparent = B_TRANSPARENT_MAGIC_CMAP8;
131 memset(fIconBitmap->Bits(), transparent, fIconBitmap->BitsLength());
136 void
137 IconView::GetPreferredSize(float* _width, float* _height)
139 if (_width != NULL) {
140 *_width = fIconBitmap->Bounds().Width()
141 + 2 * be_control_look->DefaultItemSpacing();
143 if (_height != NULL) {
144 *_height = fIconBitmap->Bounds().Height()
145 + 2 * be_control_look->DefaultItemSpacing();
150 void
151 IconView::AttachedToWindow()
153 if (Parent() != NULL)
154 SetViewColor(Parent()->ViewColor());
155 else
156 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
160 void
161 IconView::Draw(BRect updateRect)
163 BRect rect(Bounds());
165 if (fIconBitmap != NULL) {
166 // Draw bitmap centered within the view
167 SetDrawingMode(B_OP_ALPHA);
168 DrawBitmap(fIconBitmap, BPoint(rect.left
169 + (rect.Width() - fIconBitmap->Bounds().Width()) / 2,
170 rect.top + (rect.Height() - fIconBitmap->Bounds().Height()) / 2));
175 // #pragma mark -
178 InfoWin::InfoWin(BPoint leftTop, Controller* controller)
180 BWindow(BRect(leftTop.x, leftTop.y, leftTop.x + MIN_WIDTH - 1,
181 leftTop.y + 300), B_TRANSLATE("File info"), B_TITLED_WINDOW,
182 B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_ZOOMABLE),
183 fController(controller),
184 fControllerObserver(new ControllerObserver(this,
185 OBSERVE_FILE_CHANGES | OBSERVE_TRACK_CHANGES | OBSERVE_STAT_CHANGES))
187 fIconView = new IconView("background", B_LARGE_ICON);
189 fFilenameView = _CreateInfo("filename");
190 BFont bigFont(be_plain_font);
191 bigFont.SetSize(bigFont.Size() * 1.5f);
192 fFilenameView->SetFont(&bigFont);
194 // Create info views
196 BStringView* containerLabel = _CreateLabel("containerLabel",
197 B_TRANSLATE("Container"));
198 fContainerInfo = _CreateInfo("container");
200 fVideoSeparator = _CreateSeparator();
201 fVideoLabel = _CreateLabel("videoLabel", B_TRANSLATE("Video"));
202 fVideoFormatInfo = _CreateInfo("videoFormat");
203 fVideoConfigInfo = _CreateInfo("videoConfig");
204 fDisplayModeLabel = _CreateLabel("displayModeLabel",
205 B_TRANSLATE("Display mode"));
206 fDisplayModeInfo = _CreateInfo("displayMode");
208 fAudioSeparator = _CreateSeparator();
209 fAudioLabel = _CreateLabel("audioLabel", B_TRANSLATE("Audio"));
210 fAudioFormatInfo = _CreateInfo("audioFormat");
211 fAudioConfigInfo = _CreateInfo("audioConfig");
213 BStringView* durationLabel = _CreateLabel("durationLabel",
214 B_TRANSLATE("Duration"));
215 fDurationInfo = _CreateInfo("duration");
217 BStringView* locationLabel = _CreateLabel("locationLabel",
218 B_TRANSLATE("Location"));
219 fLocationInfo = _CreateInfo("location");
221 fCopyrightSeparator = _CreateSeparator();
222 fCopyrightLabel = _CreateLabel("copyrightLabel", B_TRANSLATE("Copyright"));
223 fCopyrightInfo = _CreateInfo("copyright");
225 BLayoutBuilder::Group<>(this, B_VERTICAL)
226 .SetInsets(B_USE_DEFAULT_SPACING)
227 .AddGroup(B_HORIZONTAL)
228 .Add(fIconView, 0)
229 .Add(fFilenameView, 1)
230 .End()
231 .AddGrid(2, 13)
232 .Add(containerLabel, 0, 0)
233 .Add(fContainerInfo, 1, 0)
234 .Add(fVideoSeparator, 0, 1)
235 .Add(fVideoLabel, 0, 2)
236 .Add(fVideoFormatInfo, 1, 2)
237 .Add(fVideoConfigInfo, 1, 3)
238 .Add(fDisplayModeLabel, 0, 4)
239 .Add(fDisplayModeInfo, 1, 4)
240 .Add(fAudioSeparator, 0, 5)
241 .Add(fAudioLabel, 0, 6)
242 .Add(fAudioFormatInfo, 1, 6)
243 .Add(fAudioConfigInfo, 1, 7)
244 .Add(_CreateSeparator(), 0, 8)
245 .Add(durationLabel, 0, 9)
246 .Add(fDurationInfo, 1, 9)
247 .Add(_CreateSeparator(), 0, 10)
248 .Add(locationLabel, 0, 11)
249 .Add(fLocationInfo, 1, 11)
250 .Add(fCopyrightSeparator, 0, 12)
251 .Add(fCopyrightLabel, 0, 12)
252 .Add(fCopyrightInfo, 1, 12)
253 .SetColumnWeight(0, 0)
254 .SetColumnWeight(1, 1)
255 .SetSpacing(B_USE_DEFAULT_SPACING, 0)
256 .SetExplicitMinSize(BSize(MIN_WIDTH, B_SIZE_UNSET));
258 fController->AddListener(fControllerObserver);
259 Update();
261 UpdateSizeLimits();
263 // Move window on screen if needed
264 BScreen screen(this);
265 if (screen.Frame().bottom < Frame().bottom)
266 MoveBy(0, screen.Frame().bottom - Frame().bottom);
267 if (screen.Frame().right < Frame().right)
268 MoveBy(0, screen.Frame().right - Frame().right);
270 Show();
274 InfoWin::~InfoWin()
276 fController->RemoveListener(fControllerObserver);
277 delete fControllerObserver;
281 void
282 InfoWin::MessageReceived(BMessage* msg)
284 switch (msg->what) {
285 case MSG_CONTROLLER_FILE_FINISHED:
286 break;
287 case MSG_CONTROLLER_FILE_CHANGED:
288 Update(INFO_ALL);
289 break;
290 case MSG_CONTROLLER_VIDEO_TRACK_CHANGED:
291 Update(INFO_VIDEO | INFO_STATS);
292 break;
293 case MSG_CONTROLLER_AUDIO_TRACK_CHANGED:
294 Update(INFO_AUDIO | INFO_STATS);
295 break;
296 case MSG_CONTROLLER_VIDEO_STATS_CHANGED:
297 case MSG_CONTROLLER_AUDIO_STATS_CHANGED:
298 Update(INFO_STATS);
299 break;
300 default:
301 BWindow::MessageReceived(msg);
302 break;
307 bool
308 InfoWin::QuitRequested()
310 Hide();
311 return false;
315 void
316 InfoWin::Pulse()
318 if (IsHidden())
319 return;
320 Update(INFO_STATS);
324 // #pragma mark -
327 void
328 InfoWin::Update(uint32 which)
330 if (!fController->Lock())
331 return;
333 if ((which & INFO_FILE) != 0)
334 _UpdateFile();
336 // video track format information
337 if ((which & INFO_VIDEO) != 0)
338 _UpdateVideo();
340 // audio track format information
341 if ((which & INFO_AUDIO) != 0)
342 _UpdateAudio();
344 // statistics
345 if ((which & INFO_STATS) != 0) {
346 _UpdateDuration();
347 // TODO: demux/video/audio/... perfs (Kb/info)
350 if ((which & INFO_TRANSPORT) != 0) {
351 // Transport protocol info (file, http, rtsp, ...)
354 if ((which & INFO_COPYRIGHT)!=0)
355 _UpdateCopyright();
357 fController->Unlock();
361 void
362 InfoWin::_UpdateFile()
364 bool iconSet = false;
365 if (fController->HasFile()) {
366 const PlaylistItem* item = fController->Item();
367 iconSet = fIconView->SetIcon(item) == B_OK;
368 media_file_format fileFormat;
369 status_t status = fController->GetFileFormatInfo(&fileFormat);
370 if (status == B_OK) {
371 fContainerInfo->SetText(fileFormat.pretty_name);
372 if (!iconSet)
373 iconSet = fIconView->SetIcon(fileFormat.mime_type) == B_OK;
374 } else
375 fContainerInfo->SetText(strerror(status));
377 BString info;
378 if (fController->GetLocation(&info) != B_OK)
379 info = B_TRANSLATE("<unknown>");
380 fLocationInfo->SetText(info.String());
381 fLocationInfo->SetToolTip(info.String());
383 if (fController->GetName(&info) != B_OK || info.IsEmpty())
384 info = B_TRANSLATE("<unnamed media>");
385 fFilenameView->SetText(info.String());
386 fFilenameView->SetToolTip(info.String());
387 } else {
388 fFilenameView->SetText(B_TRANSLATE("<no media>"));
389 fContainerInfo->SetText("-");
390 fLocationInfo->SetText("-");
393 if (!iconSet)
394 fIconView->SetGenericIcon();
398 void
399 InfoWin::_UpdateVideo()
401 bool visible = fController->VideoTrackCount() > 0;
402 if (visible) {
403 BString info;
404 media_format format;
405 media_raw_video_format videoFormat = {};
406 status_t status = fController->GetEncodedVideoFormat(&format);
407 if (status != B_OK) {
408 info << "(" << strerror(status) << ")\n";
409 } else if (format.type == B_MEDIA_ENCODED_VIDEO) {
410 videoFormat = format.u.encoded_video.output;
411 media_codec_info mci;
412 status = fController->GetVideoCodecInfo(&mci);
413 if (status != B_OK) {
414 if (format.user_data_type == B_CODEC_TYPE_INFO) {
415 info << (char *)format.user_data << " "
416 << B_TRANSLATE("(not supported)");
417 } else
418 info = strerror(status);
419 } else
420 info << mci.pretty_name; //<< "(" << mci.short_name << ")";
421 } else if (format.type == B_MEDIA_RAW_VIDEO) {
422 videoFormat = format.u.raw_video;
423 info << B_TRANSLATE("raw video");
424 } else
425 info << B_TRANSLATE("unknown format");
427 fVideoFormatInfo->SetText(info.String());
429 info.SetToFormat("%" B_PRIu32 " x %" B_PRIu32, format.Width(),
430 format.Height());
432 // encoded has output as 1st field...
433 char fpsString[20];
434 snprintf(fpsString, sizeof(fpsString), B_TRANSLATE("%.3f fps"),
435 videoFormat.field_rate);
436 info << ", " << fpsString;
438 fVideoConfigInfo->SetText(info.String());
440 if (fController->IsOverlayActive())
441 fDisplayModeInfo->SetText(B_TRANSLATE("Overlay"));
442 else
443 fDisplayModeInfo->SetText(B_TRANSLATE("DrawBitmap"));
446 fVideoSeparator->SetVisible(visible);
447 _SetVisible(fVideoLabel, visible);
448 _SetVisible(fVideoFormatInfo, visible);
449 _SetVisible(fVideoConfigInfo, visible);
450 _SetVisible(fDisplayModeLabel, visible);
451 _SetVisible(fDisplayModeInfo, visible);
455 void
456 InfoWin::_UpdateAudio()
458 bool visible = fController->AudioTrackCount() > 0;
459 if (visible) {
460 BString info;
461 media_format format;
462 media_raw_audio_format audioFormat = {};
464 status_t status = fController->GetEncodedAudioFormat(&format);
465 if (status != B_OK) {
466 info << "(" << strerror(status) << ")\n";
467 } else if (format.type == B_MEDIA_ENCODED_AUDIO) {
468 audioFormat = format.u.encoded_audio.output;
469 media_codec_info mci;
470 status = fController->GetAudioCodecInfo(&mci);
471 if (status != B_OK) {
472 if (format.user_data_type == B_CODEC_TYPE_INFO) {
473 info << (char *)format.user_data << " "
474 << B_TRANSLATE("(not supported)");
475 } else
476 info = strerror(status);
477 } else
478 info = mci.pretty_name;
479 } else if (format.type == B_MEDIA_RAW_AUDIO) {
480 audioFormat = format.u.raw_audio;
481 info = B_TRANSLATE("raw audio");
482 } else
483 info = B_TRANSLATE("unknown format");
485 fAudioFormatInfo->SetText(info.String());
487 uint32 bitsPerSample = 8 * (audioFormat.format
488 & media_raw_audio_format::B_AUDIO_SIZE_MASK);
489 uint32 channelCount = audioFormat.channel_count;
490 float sr = audioFormat.frame_rate;
492 info.Truncate(0);
494 if (bitsPerSample > 0) {
495 char bitString[20];
496 snprintf(bitString, sizeof(bitString), B_TRANSLATE("%d Bit"),
497 bitsPerSample);
498 info << bitString << " ";
501 static BMessageFormat channelFormat(B_TRANSLATE(
502 "{0, plural, =1{Mono} =2{Stereo} other{# Channels}}"));
503 channelFormat.Format(info, channelCount);
505 info << ", ";
506 if (sr > 0.0) {
507 char rateString[20];
508 snprintf(rateString, sizeof(rateString),
509 B_TRANSLATE("%.3f kHz"), sr / 1000);
510 info << rateString;
511 } else {
512 BString rateString = B_TRANSLATE("%d kHz");
513 rateString.ReplaceFirst("%d", "??");
514 info << rateString;
516 if (format.type == B_MEDIA_ENCODED_AUDIO) {
517 float br = format.u.encoded_audio.bit_rate;
518 char string[20] = "";
519 if (br > 0.0)
520 info << ", " << string_for_rate(br, string, sizeof(string));
523 fAudioConfigInfo->SetText(info.String());
526 fAudioSeparator->SetVisible(visible);
527 _SetVisible(fAudioLabel, visible);
528 _SetVisible(fAudioFormatInfo, visible);
529 _SetVisible(fAudioConfigInfo, visible);
533 void
534 InfoWin::_UpdateDuration()
536 if (!fController->HasFile()) {
537 fDurationInfo->SetText("-");
538 return;
541 BString info;
543 bigtime_t d = fController->TimeDuration() / 1000;
544 bigtime_t v = d / (3600 * 1000);
545 d = d % (3600 * 1000);
546 bool hours = v > 0;
547 if (hours)
548 info << v << ":";
549 v = d / (60 * 1000);
550 d = d % (60 * 1000);
551 info << v << ":";
552 v = d / 1000;
553 if (v < 10)
554 info << '0';
555 info << v;
556 if (hours)
557 info << " " << B_TRANSLATE_COMMENT("h", "Hours");
558 else
559 info << " " << B_TRANSLATE_COMMENT("min", "Minutes");
561 fDurationInfo->SetText(info.String());
565 void
566 InfoWin::_UpdateCopyright()
568 BString info;
570 bool visible = fController->HasFile()
571 && fController->GetCopyright(&info) == B_OK && !info.IsEmpty();
572 if (visible)
573 fCopyrightInfo->SetText(info.String());
575 fCopyrightSeparator->SetVisible(visible);
576 _SetVisible(fCopyrightLabel, visible);
577 _SetVisible(fCopyrightInfo, visible);
581 // #pragma mark -
584 BStringView*
585 InfoWin::_CreateLabel(const char* name, const char* label)
587 static const rgb_color kLabelColor = tint_color(
588 ui_color(B_PANEL_BACKGROUND_COLOR), B_DARKEN_3_TINT);
590 BStringView* view = new BStringView(name, label);
591 view->SetAlignment(B_ALIGN_RIGHT);
592 view->SetHighColor(kLabelColor);
594 return view;
598 BStringView*
599 InfoWin::_CreateInfo(const char* name)
601 BStringView* view = new BStringView(name, "");
602 view->SetExplicitMinSize(BSize(200, B_SIZE_UNSET));
603 view->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
604 view->SetTruncation(B_TRUNCATE_SMART);
606 return view;
610 BLayoutItem*
611 InfoWin::_CreateSeparator()
613 return BSpaceLayoutItem::CreateVerticalStrut(
614 be_control_look->ComposeSpacing(B_USE_HALF_ITEM_SPACING));
618 void
619 InfoWin::_SetVisible(BView* view, bool visible)
621 bool hidden = view->IsHidden(view);
622 if (hidden && visible)
623 view->Show();
624 else if (!hidden && !visible)
625 view->Hide();