repository_infos: Enable automatic updates on the main Haiku repostiory.
[haiku.git] / src / apps / mediaplayer / InfoWin.cpp
bloba14babdd6672b08ba66016b2b70418b60c20e0a1
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 * Released under the terms of the MIT license.
8 */
11 #include "InfoWin.h"
13 #include <math.h>
14 #include <stdio.h>
15 #include <string.h>
17 #include <Bitmap.h>
18 #include <Catalog.h>
19 #include <ControlLook.h>
20 #include <Debug.h>
21 #include <LayoutBuilder.h>
22 #include <MediaDefs.h>
23 #include <MessageFormat.h>
24 #include <Mime.h>
25 #include <NodeInfo.h>
26 #include <Screen.h>
27 #include <String.h>
28 #include <StringForRate.h>
29 #include <StringView.h>
30 #include <TextView.h>
32 #include "Controller.h"
33 #include "ControllerObserver.h"
34 #include "PlaylistItem.h"
37 #define MIN_WIDTH 500
40 #undef B_TRANSLATION_CONTEXT
41 #define B_TRANSLATION_CONTEXT "MediaPlayer-InfoWin"
44 class IconView : public BView {
45 public:
46 IconView(const char* name, int32 iconSize);
47 virtual ~IconView();
49 status_t SetIcon(const PlaylistItem* item);
50 status_t SetIcon(const char* mimeType);
51 void SetGenericIcon();
53 virtual void GetPreferredSize(float* _width, float* _height);
54 virtual void AttachedToWindow();
55 virtual void Draw(BRect updateRect);
57 private:
58 BBitmap* fIconBitmap;
62 IconView::IconView(const char* name, int32 iconSize)
64 BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
65 fIconBitmap(NULL)
67 fIconBitmap = new BBitmap(BRect(0, 0, iconSize - 1, iconSize - 1),
68 B_RGBA32);
69 SetExplicitMaxSize(PreferredSize());
73 IconView::~IconView()
75 delete fIconBitmap;
79 status_t
80 IconView::SetIcon(const PlaylistItem* item)
82 return item->GetIcon(fIconBitmap, B_LARGE_ICON);
86 status_t
87 IconView::SetIcon(const char* mimeTypeString)
89 if (!mimeTypeString)
90 return B_BAD_VALUE;
92 // get type icon
93 BMimeType mimeType(mimeTypeString);
94 status_t status = mimeType.GetIcon(fIconBitmap, B_LARGE_ICON);
96 // get supertype icon
97 if (status != B_OK) {
98 BMimeType superType;
99 status = mimeType.GetSupertype(&superType);
100 if (status == B_OK)
101 status = superType.GetIcon(fIconBitmap, B_LARGE_ICON);
104 return status;
108 void
109 IconView::SetGenericIcon()
111 // get default icon
112 BMimeType genericType(B_FILE_MIME_TYPE);
113 if (genericType.GetIcon(fIconBitmap, B_LARGE_ICON) != B_OK) {
114 // clear bitmap
115 uint8 transparent = 0;
116 if (fIconBitmap->ColorSpace() == B_CMAP8)
117 transparent = B_TRANSPARENT_MAGIC_CMAP8;
119 memset(fIconBitmap->Bits(), transparent, fIconBitmap->BitsLength());
124 void
125 IconView::GetPreferredSize(float* _width, float* _height)
127 if (_width != NULL) {
128 *_width = fIconBitmap->Bounds().Width()
129 + 2 * be_control_look->DefaultItemSpacing();
131 if (_height != NULL) {
132 *_height = fIconBitmap->Bounds().Height()
133 + 2 * be_control_look->DefaultItemSpacing();
138 void
139 IconView::AttachedToWindow()
141 if (Parent() != NULL)
142 SetViewColor(Parent()->ViewColor());
143 else
144 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
148 void
149 IconView::Draw(BRect updateRect)
151 BRect rect(Bounds());
153 if (fIconBitmap != NULL) {
154 // Draw bitmap centered within the view
155 SetDrawingMode(B_OP_ALPHA);
156 DrawBitmap(fIconBitmap, BPoint(rect.left
157 + (rect.Width() - fIconBitmap->Bounds().Width()) / 2,
158 rect.top + (rect.Height() - fIconBitmap->Bounds().Height()) / 2));
163 // #pragma mark -
166 InfoWin::InfoWin(BPoint leftTop, Controller* controller)
168 BWindow(BRect(leftTop.x, leftTop.y, leftTop.x + MIN_WIDTH - 1,
169 leftTop.y + 300), B_TRANSLATE("File info"), B_TITLED_WINDOW,
170 B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_ZOOMABLE),
171 fController(controller),
172 fControllerObserver(new ControllerObserver(this,
173 OBSERVE_FILE_CHANGES | OBSERVE_TRACK_CHANGES | OBSERVE_STAT_CHANGES))
175 fIconView = new IconView("background", B_LARGE_ICON);
177 fFilenameView = _CreateInfo("filename");
178 BFont bigFont(be_plain_font);
179 bigFont.SetSize(bigFont.Size() * 1.5f);
180 fFilenameView->SetFont(&bigFont);
182 // Create info views
184 BStringView* containerLabel = _CreateLabel("containerLabel",
185 B_TRANSLATE("Container"));
186 fContainerInfo = _CreateInfo("container");
188 fVideoSeparator = _CreateSeparator();
189 fVideoLabel = _CreateLabel("videoLabel", B_TRANSLATE("Video"));
190 fVideoFormatInfo = _CreateInfo("videoFormat");
191 fVideoConfigInfo = _CreateInfo("videoConfig");
192 fDisplayModeLabel = _CreateLabel("displayModeLabel",
193 B_TRANSLATE("Display mode"));
194 fDisplayModeInfo = _CreateInfo("displayMode");
196 fAudioSeparator = _CreateSeparator();
197 fAudioLabel = _CreateLabel("audioLabel", B_TRANSLATE("Audio"));
198 fAudioFormatInfo = _CreateInfo("audioFormat");
199 fAudioConfigInfo = _CreateInfo("audioConfig");
201 BStringView* durationLabel = _CreateLabel("durationLabel",
202 B_TRANSLATE("Duration"));
203 fDurationInfo = _CreateInfo("duration");
205 BStringView* locationLabel = _CreateLabel("locationLabel",
206 B_TRANSLATE("Location"));
207 fLocationInfo = _CreateInfo("location");
209 fCopyrightSeparator = _CreateSeparator();
210 fCopyrightLabel = _CreateLabel("copyrightLabel", B_TRANSLATE("Copyright"));
211 fCopyrightInfo = _CreateInfo("copyright");
213 BLayoutBuilder::Group<>(this, B_VERTICAL)
214 .SetInsets(B_USE_DEFAULT_SPACING)
215 .AddGroup(B_HORIZONTAL)
216 .Add(fIconView, 0)
217 .Add(fFilenameView, 1)
218 .End()
219 .AddGrid(2, 13)
220 .Add(containerLabel, 0, 0)
221 .Add(fContainerInfo, 1, 0)
222 .Add(fVideoSeparator, 0, 1)
223 .Add(fVideoLabel, 0, 2)
224 .Add(fVideoFormatInfo, 1, 2)
225 .Add(fVideoConfigInfo, 1, 3)
226 .Add(fDisplayModeLabel, 0, 4)
227 .Add(fDisplayModeInfo, 1, 4)
228 .Add(fAudioSeparator, 0, 5)
229 .Add(fAudioLabel, 0, 6)
230 .Add(fAudioFormatInfo, 1, 6)
231 .Add(fAudioConfigInfo, 1, 7)
232 .Add(_CreateSeparator(), 0, 8)
233 .Add(durationLabel, 0, 9)
234 .Add(fDurationInfo, 1, 9)
235 .Add(_CreateSeparator(), 0, 10)
236 .Add(locationLabel, 0, 11)
237 .Add(fLocationInfo, 1, 11)
238 .Add(fCopyrightSeparator, 0, 12)
239 .Add(fCopyrightLabel, 0, 12)
240 .Add(fCopyrightInfo, 1, 12)
241 .SetColumnWeight(0, 0)
242 .SetColumnWeight(1, 1)
243 .SetSpacing(B_USE_DEFAULT_SPACING, 0)
244 .SetExplicitMinSize(BSize(MIN_WIDTH, B_SIZE_UNSET));
246 fController->AddListener(fControllerObserver);
247 Update();
249 UpdateSizeLimits();
251 // Move window on screen if needed
252 BScreen screen(this);
253 if (screen.Frame().bottom < Frame().bottom)
254 MoveBy(0, screen.Frame().bottom - Frame().bottom);
255 if (screen.Frame().right < Frame().right)
256 MoveBy(0, screen.Frame().right - Frame().right);
258 Show();
262 InfoWin::~InfoWin()
264 fController->RemoveListener(fControllerObserver);
265 delete fControllerObserver;
269 void
270 InfoWin::MessageReceived(BMessage* msg)
272 switch (msg->what) {
273 case MSG_CONTROLLER_FILE_FINISHED:
274 break;
275 case MSG_CONTROLLER_FILE_CHANGED:
276 Update(INFO_ALL);
277 break;
278 case MSG_CONTROLLER_VIDEO_TRACK_CHANGED:
279 Update(INFO_VIDEO | INFO_STATS);
280 break;
281 case MSG_CONTROLLER_AUDIO_TRACK_CHANGED:
282 Update(INFO_AUDIO | INFO_STATS);
283 break;
284 case MSG_CONTROLLER_VIDEO_STATS_CHANGED:
285 case MSG_CONTROLLER_AUDIO_STATS_CHANGED:
286 Update(INFO_STATS);
287 break;
288 default:
289 BWindow::MessageReceived(msg);
290 break;
295 bool
296 InfoWin::QuitRequested()
298 Hide();
299 return false;
303 void
304 InfoWin::Pulse()
306 if (IsHidden())
307 return;
308 Update(INFO_STATS);
312 // #pragma mark -
315 void
316 InfoWin::Update(uint32 which)
318 if (!fController->Lock())
319 return;
321 if ((which & INFO_FILE) != 0)
322 _UpdateFile();
324 // video track format information
325 if ((which & INFO_VIDEO) != 0)
326 _UpdateVideo();
328 // audio track format information
329 if ((which & INFO_AUDIO) != 0)
330 _UpdateAudio();
332 // statistics
333 if ((which & INFO_STATS) != 0) {
334 _UpdateDuration();
335 // TODO: demux/video/audio/... perfs (Kb/info)
338 if ((which & INFO_TRANSPORT) != 0) {
339 // Transport protocol info (file, http, rtsp, ...)
342 if ((which & INFO_COPYRIGHT)!=0)
343 _UpdateCopyright();
345 fController->Unlock();
349 void
350 InfoWin::_UpdateFile()
352 bool iconSet = false;
353 if (fController->HasFile()) {
354 const PlaylistItem* item = fController->Item();
355 iconSet = fIconView->SetIcon(item) == B_OK;
356 media_file_format fileFormat;
357 status_t status = fController->GetFileFormatInfo(&fileFormat);
358 if (status == B_OK) {
359 fContainerInfo->SetText(fileFormat.pretty_name);
360 if (!iconSet)
361 iconSet = fIconView->SetIcon(fileFormat.mime_type) == B_OK;
362 } else
363 fContainerInfo->SetText(strerror(status));
365 BString info;
366 if (fController->GetLocation(&info) != B_OK)
367 info = B_TRANSLATE("<unknown>");
368 fLocationInfo->SetText(info.String());
369 fLocationInfo->SetToolTip(info.String());
371 if (fController->GetName(&info) != B_OK || info.IsEmpty())
372 info = B_TRANSLATE("<unnamed media>");
373 fFilenameView->SetText(info.String());
374 fFilenameView->SetToolTip(info.String());
375 } else {
376 fFilenameView->SetText(B_TRANSLATE("<no media>"));
377 fContainerInfo->SetText("-");
378 fLocationInfo->SetText("-");
381 if (!iconSet)
382 fIconView->SetGenericIcon();
386 void
387 InfoWin::_UpdateVideo()
389 bool visible = fController->VideoTrackCount() > 0;
390 if (visible) {
391 BString info;
392 media_format format;
393 media_raw_video_format videoFormat = {};
394 status_t status = fController->GetEncodedVideoFormat(&format);
395 if (status != B_OK) {
396 info << "(" << strerror(status) << ")\n";
397 } else if (format.type == B_MEDIA_ENCODED_VIDEO) {
398 videoFormat = format.u.encoded_video.output;
399 media_codec_info mci;
400 status = fController->GetVideoCodecInfo(&mci);
401 if (status != B_OK) {
402 if (format.user_data_type == B_CODEC_TYPE_INFO) {
403 info << (char *)format.user_data << " "
404 << B_TRANSLATE("(not supported)");
405 } else
406 info = strerror(status);
407 } else
408 info << mci.pretty_name; //<< "(" << mci.short_name << ")";
409 } else if (format.type == B_MEDIA_RAW_VIDEO) {
410 videoFormat = format.u.raw_video;
411 info << B_TRANSLATE("raw video");
412 } else
413 info << B_TRANSLATE("unknown format");
415 fVideoFormatInfo->SetText(info.String());
417 info.SetToFormat("%" B_PRIu32 " x %" B_PRIu32, format.Width(),
418 format.Height());
420 // encoded has output as 1st field...
421 char fpsString[20];
422 snprintf(fpsString, sizeof(fpsString), B_TRANSLATE("%.3f fps"),
423 videoFormat.field_rate);
424 info << ", " << fpsString;
426 fVideoConfigInfo->SetText(info.String());
428 if (fController->IsOverlayActive())
429 fDisplayModeInfo->SetText(B_TRANSLATE("Overlay"));
430 else
431 fDisplayModeInfo->SetText(B_TRANSLATE("DrawBitmap"));
434 fVideoSeparator->SetVisible(visible);
435 _SetVisible(fVideoLabel, visible);
436 _SetVisible(fVideoFormatInfo, visible);
437 _SetVisible(fVideoConfigInfo, visible);
438 _SetVisible(fDisplayModeLabel, visible);
439 _SetVisible(fDisplayModeInfo, visible);
443 void
444 InfoWin::_UpdateAudio()
446 bool visible = fController->AudioTrackCount() > 0;
447 if (visible) {
448 BString info;
449 media_format format;
450 media_raw_audio_format audioFormat = {};
452 status_t status = fController->GetEncodedAudioFormat(&format);
453 if (status != B_OK) {
454 info << "(" << strerror(status) << ")\n";
455 } else if (format.type == B_MEDIA_ENCODED_AUDIO) {
456 audioFormat = format.u.encoded_audio.output;
457 media_codec_info mci;
458 status = fController->GetAudioCodecInfo(&mci);
459 if (status != B_OK) {
460 if (format.user_data_type == B_CODEC_TYPE_INFO) {
461 info << (char *)format.user_data << " "
462 << B_TRANSLATE("(not supported)");
463 } else
464 info = strerror(status);
465 } else
466 info = mci.pretty_name;
467 } else if (format.type == B_MEDIA_RAW_AUDIO) {
468 audioFormat = format.u.raw_audio;
469 info = B_TRANSLATE("raw audio");
470 } else
471 info = B_TRANSLATE("unknown format");
473 fAudioFormatInfo->SetText(info.String());
475 uint32 bitsPerSample = 8 * (audioFormat.format
476 & media_raw_audio_format::B_AUDIO_SIZE_MASK);
477 uint32 channelCount = audioFormat.channel_count;
478 float sr = audioFormat.frame_rate;
480 info.Truncate(0);
482 if (bitsPerSample > 0) {
483 char bitString[20];
484 snprintf(bitString, sizeof(bitString), B_TRANSLATE("%d Bit"),
485 bitsPerSample);
486 info << bitString << " ";
489 static BMessageFormat channelFormat(B_TRANSLATE(
490 "{0, plural, =1{Mono} =2{Stereo} other{# Channels}}"));
491 channelFormat.Format(info, channelCount);
493 info << ", ";
494 if (sr > 0.0) {
495 char rateString[20];
496 snprintf(rateString, sizeof(rateString),
497 B_TRANSLATE("%.3f kHz"), sr / 1000);
498 info << rateString;
499 } else {
500 BString rateString = B_TRANSLATE("%d kHz");
501 rateString.ReplaceFirst("%d", "??");
502 info << rateString;
504 if (format.type == B_MEDIA_ENCODED_AUDIO) {
505 float br = format.u.encoded_audio.bit_rate;
506 char string[20] = "";
507 if (br > 0.0)
508 info << ", " << string_for_rate(br, string, sizeof(string));
511 fAudioConfigInfo->SetText(info.String());
514 fAudioSeparator->SetVisible(visible);
515 _SetVisible(fAudioLabel, visible);
516 _SetVisible(fAudioFormatInfo, visible);
517 _SetVisible(fAudioConfigInfo, visible);
521 void
522 InfoWin::_UpdateDuration()
524 if (!fController->HasFile()) {
525 fDurationInfo->SetText("-");
526 return;
529 BString info;
531 bigtime_t d = fController->TimeDuration() / 1000;
532 bigtime_t v = d / (3600 * 1000);
533 d = d % (3600 * 1000);
534 bool hours = v > 0;
535 if (hours)
536 info << v << ":";
537 v = d / (60 * 1000);
538 d = d % (60 * 1000);
539 info << v << ":";
540 v = d / 1000;
541 if (v < 10)
542 info << '0';
543 info << v;
544 if (hours)
545 info << " " << B_TRANSLATE_COMMENT("h", "Hours");
546 else
547 info << " " << B_TRANSLATE_COMMENT("min", "Minutes");
549 fDurationInfo->SetText(info.String());
553 void
554 InfoWin::_UpdateCopyright()
556 BString info;
558 bool visible = fController->HasFile()
559 && fController->GetCopyright(&info) == B_OK && !info.IsEmpty();
560 if (visible)
561 fCopyrightInfo->SetText(info.String());
563 fCopyrightSeparator->SetVisible(visible);
564 _SetVisible(fCopyrightLabel, visible);
565 _SetVisible(fCopyrightInfo, visible);
569 // #pragma mark -
572 BStringView*
573 InfoWin::_CreateLabel(const char* name, const char* label)
575 static const rgb_color kLabelColor = tint_color(
576 ui_color(B_PANEL_BACKGROUND_COLOR), B_DARKEN_3_TINT);
578 BStringView* view = new BStringView(name, label);
579 view->SetAlignment(B_ALIGN_RIGHT);
580 view->SetHighColor(kLabelColor);
582 return view;
586 BStringView*
587 InfoWin::_CreateInfo(const char* name)
589 BStringView* view = new BStringView(name, "");
590 view->SetExplicitMinSize(BSize(200, B_SIZE_UNSET));
591 view->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
592 view->SetTruncation(B_TRUNCATE_SMART);
594 return view;
598 BLayoutItem*
599 InfoWin::_CreateSeparator()
601 return BSpaceLayoutItem::CreateVerticalStrut(
602 be_control_look->ComposeSpacing(B_USE_HALF_ITEM_SPACING));
606 void
607 InfoWin::_SetVisible(BView* view, bool visible)
609 bool hidden = view->IsHidden(view);
610 if (hidden && visible)
611 view->Show();
612 else if (!hidden && !visible)
613 view->Hide();