xref: /haiku/src/apps/mediaplayer/InfoWin.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2  * InfoWin.cpp - Media Player for the Haiku Operating System
3  *
4  * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  *
19  */
20 #include "InfoWin.h"
21 
22 #include <View.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <String.h>
26 #include <Debug.h>
27 #include <MediaDefs.h>
28 #include <MediaFile.h>
29 #include <MediaTrack.h>
30 #include <TextView.h>
31 #include <math.h>
32 #include "MainWin.h"
33 
34 #define NAME "File Info"
35 #define MIN_WIDTH 350
36 
37 #define BASE_HEIGHT (32+32)
38 
39 //const rgb_color kGreen = { 152, 203, 152, 255 };
40 const rgb_color kRed =   { 203, 152, 152, 255 };
41 const rgb_color kBlue =  {   0,   0, 220, 255 };
42 const rgb_color kGreen = { 171, 221, 161, 255 };
43 const rgb_color kBlack = {   0,   0,   0, 255 };
44 
45 
46 // should later draw an icon
47 class InfoView : public BView {
48 public:
49 	InfoView(BRect frame, const char *name, float divider)
50 		: BView(frame, name, B_FOLLOW_ALL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE)
51 		, fDivider(divider)
52 		{ }
53 	virtual ~InfoView()
54 		{ }
55 	void Draw(BRect updateRect);
56 	float fDivider;
57 };
58 
59 
60 void
61 InfoView::Draw(BRect updateRect)
62 {
63 	SetHighColor(kGreen);
64 	BRect r(Bounds());
65 	r.right = r.left + fDivider;
66 	FillRect(r);
67 	SetHighColor(ui_color(B_DOCUMENT_TEXT_COLOR));
68 	r.left = r.right;
69 	FillRect(r);
70 }
71 
72 
73 InfoWin::InfoWin(MainWin *mainWin)
74 	: BWindow(BRect(100,100,100+MIN_WIDTH-1,350), NAME, B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE /* | B_WILL_ACCEPT_FIRST_CLICK */),
75 	  fMainWin(mainWin),
76 	  fController()
77 {
78 	BRect rect;
79 	if (fMainWin->Lock()) {
80 		rect = fMainWin->Frame();
81 		MoveTo(rect.right, rect.top);
82 		fMainWin->Unlock();
83 	}
84 
85 	rect = Bounds();
86 
87 	// accomodate for big fonts
88 	float div;
89 	div = MAX(2*32, be_plain_font->StringWidth("Container") + 5);
90 
91 	fInfoView = new InfoView(rect, "background", div);
92 	fInfoView->SetViewColor(ui_color(B_DOCUMENT_BACKGROUND_COLOR));
93 	AddChild(fInfoView);
94 
95 	BFont bigFont(be_plain_font);
96 	bigFont.SetSize(bigFont.Size()+6);
97 	font_height fh;
98 	bigFont.GetHeight(&fh);
99 	fFilenameView = new BStringView(BRect(div+10, 20,
100 										  rect.right - 10,
101 										  20 + fh.ascent + 5),
102 									"filename", "");
103 	fFilenameView->SetFont(&bigFont);
104 	fFilenameView->SetViewColor(fInfoView->ViewColor());
105 	fFilenameView->SetLowColor(fInfoView->ViewColor());
106 #ifdef B_BEOS_VERSION_DANO /* maybe we should support that as well ? */
107 	fFilenameView->SetTruncation(B_TRUNCATE_END);
108 #endif
109 	AddChild(fFilenameView);
110 
111 
112 	rect.top = BASE_HEIGHT;
113 
114 	BRect lr(rect);
115 	BRect cr(rect);
116 	lr.right = div - 1;
117 	cr.left = div + 1;
118 	BRect tr;
119 	tr = lr.OffsetToCopy(0,0).InsetByCopy(1,1);
120 	fLabelsView = new BTextView(lr, "labels", tr, B_FOLLOW_BOTTOM);
121 	fLabelsView->SetViewColor(kGreen);
122 	fLabelsView->SetAlignment(B_ALIGN_RIGHT);
123 	fLabelsView->SetWordWrap(false);
124 	AddChild(fLabelsView);
125 	tr = cr.OffsetToCopy(0,0).InsetByCopy(1,1);
126 	fContentsView = new BTextView(cr, "contents", tr, B_FOLLOW_BOTTOM);
127 	fContentsView->SetWordWrap(false);
128 	AddChild(fContentsView);
129 
130 	fLabelsView->MakeSelectable();
131 	fContentsView->MakeSelectable();
132 
133 
134 	Show();
135 }
136 
137 
138 InfoWin::~InfoWin()
139 {
140 	printf("InfoWin::~InfoWin\n");
141 	//fInfoListView->MakeEmpty();
142 	//delete [] fInfoItems;
143 }
144 
145 
146 void
147 InfoWin::ResizeToPreferred()
148 {
149 #if 0
150 	int i;
151 	float height = BASE_HEIGHT;
152 	BListItem *li;
153 	for (i = 0; (li = fInfoListView->ItemAt(i)); i++) {
154 		height += li->Height();
155 	}
156 	ResizeTo(Bounds().Width(), height);
157 #endif
158 }
159 
160 
161 void
162 InfoWin::Update(uint32 which)
163 {
164 	status_t err;
165 	//char buf[256];
166 	printf("InfoWin::Update(0x%08lx)\n", which);
167 	rgb_color vFgCol = ui_color(B_DOCUMENT_TEXT_COLOR);
168 
169 	fLabelsView->SelectAll();
170 	fContentsView->SelectAll();
171 	fLabelsView->Clear();
172 	fContentsView->Clear();
173 	fLabelsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kBlue);
174 	fLabelsView->Insert("File Info\n");
175 	fContentsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &vFgCol);
176 	fContentsView->Insert("\n");
177 
178 	fLabelsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kRed);
179 	//fContentsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &vFgCol);
180 
181 	// lock the Main Window as we must access some fields there...
182 	if (fMainWin->LockWithTimeout(500000) < B_OK)
183 		return; // XXX: resend msg to ourselves ?
184 
185 	Controller *c = fMainWin->fController;
186 	BMediaFile *mf = c->fMediaFile;
187 
188 	if (which & INFO_VIDEO && c->VideoTrackCount() > 0) {
189 		fLabelsView->Insert("Video\n\n");
190 		BString s;
191 		media_format fmt;
192 		media_raw_video_format vfmt;
193 		float fps;
194 		err = c->fVideoTrack->EncodedFormat(&fmt);
195 		//string_for_format(fmt, buf, sizeof(buf));
196 		//printf("%s\n", buf);
197 		if (err < 0) {
198 			s << "(" << strerror(err) << ")";
199 		} else if (fmt.type == B_MEDIA_ENCODED_VIDEO) {
200 			vfmt = fmt.u.encoded_video.output;
201 			media_codec_info mci;
202 			err = c->fVideoTrack->GetCodecInfo(&mci);
203 			if (err < 0)
204 				s << "(" << strerror(err) << ")";
205 			else
206 				s << mci.pretty_name; //<< "(" << mci.short_name << ")";
207 		} else if (fmt.type == B_MEDIA_RAW_VIDEO) {
208 			vfmt = fmt.u.raw_video;
209 			s << "raw video";
210 		} else
211 			s << "unknown format";
212 		s << "\n";
213 		s << fmt.Width() << " x " << fmt.Height();
214 		// encoded has output as 1st field...
215 		fps = vfmt.field_rate;
216 		s << ", " << fps << " fps";
217 		s << "\n";
218 		fContentsView->Insert(s.String());
219 	}
220 	if (which & INFO_AUDIO && c->AudioTrackCount() > 0) {
221 		fLabelsView->Insert("Sound\n\n");
222 		BString s;
223 		media_format fmt;
224 		media_raw_audio_format afmt;
225 		err = c->fAudioTrack->EncodedFormat(&fmt);
226 		//string_for_format(fmt, buf, sizeof(buf));
227 		//printf("%s\n", buf);
228 		if (err < 0) {
229 			s << "(" << strerror(err) << ")";
230 		} else if (fmt.type == B_MEDIA_ENCODED_AUDIO) {
231 			afmt = fmt.u.encoded_audio.output;
232 			media_codec_info mci;
233 			err = c->fAudioTrack->GetCodecInfo(&mci);
234 			if (err < 0)
235 				s << "(" << strerror(err) << ")";
236 			else
237 				s << mci.pretty_name; //<< "(" << mci.short_name << ")";
238 		} else if (fmt.type == B_MEDIA_RAW_AUDIO) {
239 			afmt = fmt.u.raw_audio;
240 			s << "raw audio";
241 		} else
242 			s << "unknown format";
243 		s << "\n";
244 		uint32 bitps = 8 * (afmt.format & media_raw_audio_format::B_AUDIO_SIZE_MASK);
245 		uint32 chans = afmt.channel_count;
246 		float sr = afmt.frame_rate;
247 
248 		if (bitps)
249 			s << bitps << " Bit ";
250 		if (chans == 1)
251 			s << "Mono";
252 		else if (chans == 2)
253 			s << "Stereo";
254 		else
255 			s << chans << "Channels";
256 		s << ", ";
257 		if (sr)
258 			s << sr/1000;
259 		else
260 			s << "?";
261 		s<< " kHz";
262 		s << "\n";
263 		fContentsView->Insert(s.String());
264 	}
265 	if (which & INFO_STATS && fMainWin->fHasFile) {
266 		// TODO: check for live streams (no duration)
267 		fLabelsView->Insert("Duration\n");
268 		BString s;
269 		bigtime_t d = c->Duration();
270 		bigtime_t v;
271 
272 		//s << d << "µs; ";
273 
274 		d /= 1000;
275 
276 		v = d / (3600 * 1000);
277 		d = d % (3600 * 1000);
278 		if (v)
279 			s << v << ":";
280 		v = d / (60 * 1000);
281 		d = d % (60 * 1000);
282 		s << v << ":";
283 		v = d / 1000;
284 		d = d % 1000;
285 		s << v;
286 		if (d)
287 			s << "." << d / 10;
288 		s << "\n";
289 		fContentsView->Insert(s.String());
290 		// TODO: demux/video/audio/... perfs (Kb/s)
291 	}
292 	if (which & INFO_TRANSPORT) {
293 	}
294 	if ((which & INFO_FILE) && fMainWin->fHasFile) {
295 		media_file_format ff;
296 		if (mf && (mf->GetFileFormatInfo(&ff) == B_OK)) {
297 			fLabelsView->Insert("Container\n");
298 			BString s;
299 			s << ff.pretty_name;
300 			s << "\n";
301 			fContentsView->Insert(s.String());
302 		}
303 		fLabelsView->Insert("Location\n");
304 		// TODO: make Controller save the entry_ref (url actually).
305 		fContentsView->Insert("file://\n");
306 		fFilenameView->SetText(c->fName.String());
307 	}
308 	if (which & INFO_COPYRIGHT && mf && mf->Copyright()) {
309 
310 		fLabelsView->Insert("Copyright\n\n");
311 		BString s;
312 		s << mf->Copyright();
313 		s << "\n\n";
314 		fContentsView->Insert(s.String());
315 	}
316 
317 	// we can unlock the main window now and let it work
318 	fMainWin->Unlock();
319 
320 	// now resize the window to the list view size...
321 	ResizeToPreferred();
322 
323 	if (IsHidden())
324 		Show();
325 }
326 
327 
328 bool
329 InfoWin::QuitRequested()
330 {
331 	Hide();
332 	return false;
333 }
334 
335 
336 void
337 InfoWin::Show()
338 {
339 	// notify the main window first
340 	fMainWin->fInfoWinShowing = true;
341 	BWindow::Show();
342 	//SetPulseRate(1000000);
343 }
344 
345 
346 void
347 InfoWin::Hide()
348 {
349 	SetPulseRate(0);
350 	BWindow::Hide();
351 	fMainWin->fInfoWinShowing = false;
352 }
353 
354 
355 void
356 InfoWin::Pulse()
357 {
358 	if (IsHidden())
359 		return;
360 	Update(INFO_STATS);
361 }
362 
363 void
364 InfoWin::FrameResized(float new_width, float new_height)
365 {
366 #if 0
367 	if (new_width != Bounds().Width() || new_height != Bounds().Height()) {
368 		debugger("size wrong\n");
369 	}
370 
371 	bool no_menu = fNoMenu || fIsFullscreen;
372 	bool no_controls = fNoControls || fIsFullscreen;
373 
374 	printf("FrameResized enter: new_width %.0f, new_height %.0f\n", new_width, new_height);
375 
376 	int max_video_width  = int(new_width) + 1;
377 	int max_video_height = int(new_height) + 1 - (no_menu  ? 0 : fMenuBarHeight) - (no_controls ? 0 : fControlsHeight);
378 
379 	ASSERT(max_video_height >= 0);
380 
381 	int y = 0;
382 
383 	if (no_menu) {
384 		if (!fMenuBar->IsHidden())
385 			fMenuBar->Hide();
386 	} else {
387 //		fMenuBar->MoveTo(0, y);
388 		fMenuBar->ResizeTo(new_width, fMenuBarHeight - 1);
389 		if (fMenuBar->IsHidden())
390 			fMenuBar->Show();
391 		y += fMenuBarHeight;
392 	}
393 
394 	if (max_video_height == 0) {
395 		if (!fVideoView->IsHidden())
396 			fVideoView->Hide();
397 	} else {
398 //		fVideoView->MoveTo(0, y);
399 //		fVideoView->ResizeTo(max_video_width - 1, max_video_height - 1);
400 		ResizeVideoView(0, y, max_video_width, max_video_height);
401 		if (fVideoView->IsHidden())
402 			fVideoView->Show();
403 		y += max_video_height;
404 	}
405 
406 	if (no_controls) {
407 		if (!fControls->IsHidden())
408 			fControls->Hide();
409 	} else {
410 		fControls->MoveTo(0, y);
411 		fControls->ResizeTo(new_width, fControlsHeight - 1);
412 		if (fControls->IsHidden())
413 			fControls->Show();
414 //		y += fControlsHeight;
415 	}
416 #endif
417 
418 	printf("FrameResized leave\n");
419 }
420 
421 
422 void
423 InfoWin::MessageReceived(BMessage *msg)
424 {
425 	uint32 which;
426 	switch (msg->what) {
427 	case M_UPDATE_INFO:
428 		if (msg->FindInt32("which", (int32 *)&which) < B_OK)
429 			which = INFO_ALL;
430 		Update(which);
431 		break;
432 	default:
433 		BWindow::MessageReceived(msg);
434 		break;
435 	}
436 }
437