1 /*
2 * Copyright 2003-2015, Haiku, Inc.
3 * Distributed under the terms of the MIT license.
4 *
5 * Authors:
6 * Sikosis, Jérôme Duval
7 * yourpalal, Alex Wilson
8 */
9
10
11 #include "MediaWindow.h"
12
13 #include <stdio.h>
14
15 #include <Application.h>
16 #include <Autolock.h>
17 #include <Button.h>
18 #include <CardLayout.h>
19 #include <Catalog.h>
20 #include <Debug.h>
21 #include <Deskbar.h>
22 #include <IconUtils.h>
23 #include <LayoutBuilder.h>
24 #include <Locale.h>
25 #include <MediaRoster.h>
26 #include <MediaTheme.h>
27 #include <Resources.h>
28 #include <Roster.h>
29 #include <Screen.h>
30 #include <ScrollView.h>
31 #include <SeparatorView.h>
32 #include <SpaceLayoutItem.h>
33 #include <StorageKit.h>
34 #include <String.h>
35 #include <TextView.h>
36
37 #include "Media.h"
38 #include "MediaIcons.h"
39 #include "MidiSettingsView.h"
40
41 #undef B_TRANSLATION_CONTEXT
42 #define B_TRANSLATION_CONTEXT "Media Window"
43
44
45 const uint32 ML_SELECTED_NODE = 'MlSN';
46 const uint32 ML_RESTART_THREAD_FINISHED = 'MlRF';
47
48
49 class NodeListItemUpdater : public MediaListItem::Visitor {
50 public:
51 typedef void (NodeListItem::*UpdateMethod)(bool);
52
NodeListItemUpdater(NodeListItem * target,UpdateMethod action)53 NodeListItemUpdater(NodeListItem* target, UpdateMethod action)
54 :
55 fComparator(target),
56 fAction(action)
57 {
58 }
59
60
Visit(AudioMixerListItem *)61 virtual void Visit(AudioMixerListItem*){}
Visit(DeviceListItem *)62 virtual void Visit(DeviceListItem*){}
Visit(MidiListItem *)63 virtual void Visit(MidiListItem*){}
Visit(NodeListItem * item)64 virtual void Visit(NodeListItem* item)
65 {
66 item->Accept(fComparator);
67 (item->*(fAction))(fComparator.result == 0);
68 }
69
70 private:
71
72 NodeListItem::Comparator fComparator;
73 UpdateMethod fAction;
74 };
75
76
SmartNode(const BMessenger & notifyHandler)77 MediaWindow::SmartNode::SmartNode(const BMessenger& notifyHandler)
78 :
79 fNode(NULL),
80 fMessenger(notifyHandler)
81 {
82 }
83
84
~SmartNode()85 MediaWindow::SmartNode::~SmartNode()
86 {
87 _FreeNode();
88 }
89
90
91 void
SetTo(const dormant_node_info * info)92 MediaWindow::SmartNode::SetTo(const dormant_node_info* info)
93 {
94 _FreeNode();
95 if (!info)
96 return;
97
98 fNode = new media_node();
99 BMediaRoster* roster = BMediaRoster::Roster();
100
101 status_t status = B_OK;
102 media_node_id node_id;
103 if (roster->GetInstancesFor(info->addon, info->flavor_id, &node_id) == B_OK)
104 status = roster->GetNodeFor(node_id, fNode);
105 else
106 status = roster->InstantiateDormantNode(*info, fNode, B_FLAVOR_IS_GLOBAL);
107
108 if (status != B_OK) {
109 fprintf(stderr, "SmartNode::SetTo error with node %" B_PRId32
110 ": %s\n", fNode->node, strerror(status));
111 }
112
113 status = roster->StartWatching(fMessenger, *fNode, B_MEDIA_WILDCARD);
114 if (status != B_OK) {
115 fprintf(stderr, "SmartNode::SetTo can't start watching for"
116 " node %" B_PRId32 "\n", fNode->node);
117 }
118 }
119
120
121 void
SetTo(const media_node & node)122 MediaWindow::SmartNode::SetTo(const media_node& node)
123 {
124 _FreeNode();
125 fNode = new media_node(node);
126 BMediaRoster* roster = BMediaRoster::Roster();
127 roster->StartWatching(fMessenger, *fNode, B_MEDIA_WILDCARD);
128 }
129
130
131 bool
IsSet()132 MediaWindow::SmartNode::IsSet()
133 {
134 return fNode != NULL;
135 }
136
137
operator media_node()138 MediaWindow::SmartNode::operator media_node()
139 {
140 if (fNode)
141 return *fNode;
142 media_node node;
143 return node;
144 }
145
146
147 void
_FreeNode()148 MediaWindow::SmartNode::_FreeNode()
149 {
150 if (!IsSet())
151 return;
152
153 BMediaRoster* roster = BMediaRoster::Roster();
154 if (roster != NULL) {
155 status_t status = roster->StopWatching(fMessenger,
156 *fNode, B_MEDIA_WILDCARD);
157 if (status != B_OK) {
158 fprintf(stderr, "SmartNode::_FreeNode can't unwatch"
159 " media services for node %" B_PRId32 "\n", fNode->node);
160 }
161
162 roster->ReleaseNode(*fNode);
163 if (status != B_OK) {
164 fprintf(stderr, "SmartNode::_FreeNode can't release"
165 " node %" B_PRId32 "\n", fNode->node);
166 }
167 }
168 delete fNode;
169 fNode = NULL;
170 }
171
172
173 // #pragma mark -
174
175
MediaWindow(BRect frame)176 MediaWindow::MediaWindow(BRect frame)
177 :
178 BWindow(frame, B_TRANSLATE_SYSTEM_NAME("Media"), B_TITLED_WINDOW,
179 B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
180 fCurrentNode(BMessenger(this)),
181 fParamWeb(NULL),
182 fAudioInputs(5, true),
183 fAudioOutputs(5, true),
184 fVideoInputs(5, true),
185 fVideoOutputs(5, true),
186 fInitCheck(B_OK),
187 fRestartThread(-1),
188 fRestartAlert(NULL)
189 {
190 _InitWindow();
191
192 BMediaRoster* roster = BMediaRoster::Roster();
193 roster->StartWatching(BMessenger(this, this),
194 B_MEDIA_SERVER_STARTED);
195 roster->StartWatching(BMessenger(this, this),
196 B_MEDIA_SERVER_QUIT);
197 }
198
199
~MediaWindow()200 MediaWindow::~MediaWindow()
201 {
202 _EmptyNodeLists();
203 _ClearParamView();
204
205 char buffer[512];
206 BRect rect = Frame();
207 PRINT_OBJECT(rect);
208 snprintf(buffer, 512, "# MediaPrefs Settings\n rect = %i,%i,%i,%i\n",
209 int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
210
211 BPath path;
212 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
213 path.Append(SETTINGS_FILE);
214 BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
215 if (file.InitCheck() == B_OK)
216 file.Write(buffer, strlen(buffer));
217 }
218
219 BMediaRoster* roster = BMediaRoster::CurrentRoster();
220 roster->StopWatching(BMessenger(this, this),
221 B_MEDIA_SERVER_STARTED);
222 roster->StartWatching(BMessenger(this, this),
223 B_MEDIA_SERVER_QUIT);
224 }
225
226
227 status_t
InitCheck()228 MediaWindow::InitCheck()
229 {
230 return fInitCheck;
231 }
232
233
234 void
SelectNode(const dormant_node_info * node)235 MediaWindow::SelectNode(const dormant_node_info* node)
236 {
237 fCurrentNode.SetTo(node);
238 _MakeParamView();
239 fTitleView->SetLabel(node->name);
240 }
241
242
243 void
SelectAudioSettings(const char * title)244 MediaWindow::SelectAudioSettings(const char* title)
245 {
246 fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fAudioView));
247 fTitleView->SetLabel(title);
248 }
249
250
251 void
SelectVideoSettings(const char * title)252 MediaWindow::SelectVideoSettings(const char* title)
253 {
254 fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fVideoView));
255 fTitleView->SetLabel(title);
256 }
257
258
259 void
SelectAudioMixer(const char * title)260 MediaWindow::SelectAudioMixer(const char* title)
261 {
262 media_node mixerNode;
263 BMediaRoster* roster = BMediaRoster::Roster();
264 roster->GetAudioMixer(&mixerNode);
265 fCurrentNode.SetTo(mixerNode);
266 _MakeParamView();
267 fTitleView->SetLabel(title);
268 }
269
270
271 void
SelectMidiSettings(const char * title)272 MediaWindow::SelectMidiSettings(const char* title)
273 {
274 fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fMidiView));
275 fTitleView->SetLabel(title);
276 }
277
278
279 void
UpdateInputListItem(MediaListItem::media_type type,const dormant_node_info * node)280 MediaWindow::UpdateInputListItem(MediaListItem::media_type type,
281 const dormant_node_info* node)
282 {
283 NodeListItem compareTo(node, type);
284 NodeListItemUpdater updater(&compareTo, &NodeListItem::SetDefaultInput);
285 for (int32 i = 0; i < fListView->CountItems(); i++) {
286 MediaListItem* item = static_cast<MediaListItem*>(fListView->ItemAt(i));
287 item->Accept(updater);
288 }
289 fListView->Invalidate();
290 }
291
292
293 void
UpdateOutputListItem(MediaListItem::media_type type,const dormant_node_info * node)294 MediaWindow::UpdateOutputListItem(MediaListItem::media_type type,
295 const dormant_node_info* node)
296 {
297 NodeListItem compareTo(node, type);
298 NodeListItemUpdater updater(&compareTo, &NodeListItem::SetDefaultOutput);
299 for (int32 i = 0; i < fListView->CountItems(); i++) {
300 MediaListItem* item = static_cast<MediaListItem*>(fListView->ItemAt(i));
301 item->Accept(updater);
302 }
303 fListView->Invalidate();
304 }
305
306
307 bool
QuitRequested()308 MediaWindow::QuitRequested()
309 {
310 if (fRestartThread > 0) {
311 BString text(B_TRANSLATE("Quitting Media now will stop the "
312 "restarting of the media services. Flaky or unavailable media "
313 "functionality is the likely result."));
314
315 fRestartAlert = new BAlert(B_TRANSLATE("Warning!"), text,
316 B_TRANSLATE("Quit anyway"), NULL, NULL,
317 B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT);
318
319 fRestartAlert->Go();
320 }
321 // Stop watching the MediaRoster
322 fCurrentNode.SetTo(NULL);
323 be_app->PostMessage(B_QUIT_REQUESTED);
324 return true;
325 }
326
327
328 void
MessageReceived(BMessage * message)329 MediaWindow::MessageReceived(BMessage* message)
330 {
331 switch (message->what) {
332 case ML_RESTART_THREAD_FINISHED:
333 fRestartThread = -1;
334 _InitMedia(false);
335 break;
336
337 case ML_RESTART_MEDIA_SERVER:
338 {
339 fRestartThread = spawn_thread(&MediaWindow::_RestartMediaServices,
340 "restart_thread", B_NORMAL_PRIORITY, this);
341 if (fRestartThread < 0)
342 fprintf(stderr, "couldn't create restart thread\n");
343 else
344 resume_thread(fRestartThread);
345 break;
346 }
347
348 case B_MEDIA_WEB_CHANGED:
349 case ML_SELECTED_NODE:
350 {
351 PRINT_OBJECT(*message);
352
353 MediaListItem* item = static_cast<MediaListItem*>(
354 fListView->ItemAt(fListView->CurrentSelection()));
355 if (item == NULL)
356 break;
357
358 fCurrentNode.SetTo(NULL);
359 _ClearParamView();
360 item->AlterWindow(this);
361 break;
362 }
363
364 case B_MEDIA_SERVER_STARTED:
365 case B_MEDIA_SERVER_QUIT:
366 {
367 PRINT_OBJECT(*message);
368 _InitMedia(false);
369 break;
370 }
371
372 default:
373 BWindow::MessageReceived(message);
374 break;
375 }
376 }
377
378
379 // #pragma mark - private
380
381
382 void
_InitWindow()383 MediaWindow::_InitWindow()
384 {
385 fListView = new BListView("media_list_view");
386 fListView->SetSelectionMessage(new BMessage(ML_SELECTED_NODE));
387 fListView->SetExplicitMinSize(BSize(140, B_SIZE_UNSET));
388
389 // Add ScrollView to Media Menu for pretty border
390 BScrollView* scrollView = new BScrollView("listscroller",
391 fListView, 0, false, false, B_FANCY_BORDER);
392
393 // Create the Views
394 fTitleView = new BSeparatorView(B_HORIZONTAL, B_FANCY_BORDER);
395 fTitleView->SetLabel(B_TRANSLATE("Audio settings"));
396 fTitleView->SetFont(be_bold_font);
397
398 fContentLayout = new BCardLayout();
399 new BView("content view", 0, fContentLayout);
400 fContentLayout->Owner()->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
401 fContentLayout->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
402
403 fAudioView = new AudioSettingsView();
404 fContentLayout->AddView(fAudioView);
405
406 fVideoView = new VideoSettingsView();
407 fContentLayout->AddView(fVideoView);
408
409 fMidiView = new MidiSettingsView();
410 fContentLayout->AddView(fMidiView);
411
412 // Layout all views
413 BLayoutBuilder::Group<>(this, B_HORIZONTAL)
414 .SetInsets(B_USE_WINDOW_SPACING)
415 .Add(scrollView, 0.0f)
416 .AddGroup(B_VERTICAL)
417 .SetInsets(0, 0, 0, 0)
418 .Add(fTitleView)
419 .Add(fContentLayout);
420
421 // Start the window
422 fInitCheck = _InitMedia(true);
423 if (fInitCheck != B_OK)
424 PostMessage(B_QUIT_REQUESTED);
425 else if (IsHidden())
426 Show();
427 }
428
429
430 status_t
_InitMedia(bool first)431 MediaWindow::_InitMedia(bool first)
432 {
433 status_t err = B_OK;
434 BMediaRoster* roster = BMediaRoster::Roster(&err);
435
436 if (first && err != B_OK) {
437 BAlert* alert = new BAlert("start_media_server",
438 B_TRANSLATE("Could not connect to the media server.\n"
439 "Would you like to start it ?"),
440 B_TRANSLATE("Quit"),
441 B_TRANSLATE("Start media server"), NULL,
442 B_WIDTH_AS_USUAL, B_WARNING_ALERT);
443 alert->SetShortcut(0, B_ESCAPE);
444 if (alert->Go() == 0)
445 return B_ERROR;
446
447 Show();
448
449 launch_media_server();
450 }
451
452 Lock();
453
454 bool isVideoSelected = true;
455 if (!first && fListView->ItemAt(0) != NULL
456 && fListView->ItemAt(0)->IsSelected())
457 isVideoSelected = false;
458
459 while (fListView->CountItems() > 0)
460 delete fListView->RemoveItem((int32)0);
461 _EmptyNodeLists();
462
463 // Grab Media Info
464 _FindNodes();
465
466 // Add video nodes first. They might have an additional audio
467 // output or input, but still should be listed as video node.
468 _AddNodeItems(fVideoOutputs, MediaListItem::VIDEO_TYPE);
469 _AddNodeItems(fVideoInputs, MediaListItem::VIDEO_TYPE);
470 _AddNodeItems(fAudioOutputs, MediaListItem::AUDIO_TYPE);
471 _AddNodeItems(fAudioInputs, MediaListItem::AUDIO_TYPE);
472
473 fAudioView->AddOutputNodes(fAudioOutputs);
474 fAudioView->AddInputNodes(fAudioInputs);
475 fVideoView->AddOutputNodes(fVideoOutputs);
476 fVideoView->AddInputNodes(fVideoInputs);
477
478 // build our list view
479 DeviceListItem* audio = new DeviceListItem(B_TRANSLATE("Audio settings"),
480 MediaListItem::AUDIO_TYPE);
481 fListView->AddItem(audio);
482
483 MidiListItem* midi = new MidiListItem(B_TRANSLATE("MIDI Settings"));
484 fListView->AddItem(midi);
485
486 MediaListItem* video = new DeviceListItem(B_TRANSLATE("Video settings"),
487 MediaListItem::VIDEO_TYPE);
488 fListView->AddItem(video);
489
490 MediaListItem* mixer = new AudioMixerListItem(B_TRANSLATE("Audio mixer"));
491 fListView->AddItem(mixer);
492
493 fListView->SortItems(&MediaListItem::Compare);
494 _UpdateListViewMinWidth();
495
496 // Set default nodes for our setting views
497 media_node defaultNode;
498 dormant_node_info nodeInfo;
499 int32 outputID;
500 BString outputName;
501
502 if (roster->GetAudioInput(&defaultNode) == B_OK) {
503 roster->GetDormantNodeFor(defaultNode, &nodeInfo);
504 fAudioView->SetDefaultInput(&nodeInfo);
505 // this causes our listview to be updated as well
506 }
507
508 if (roster->GetAudioOutput(&defaultNode, &outputID, &outputName) == B_OK) {
509 roster->GetDormantNodeFor(defaultNode, &nodeInfo);
510 fAudioView->SetDefaultOutput(&nodeInfo);
511 fAudioView->SetDefaultChannel(outputID);
512 // this causes our listview to be updated as well
513 }
514
515 if (roster->GetVideoInput(&defaultNode) == B_OK) {
516 roster->GetDormantNodeFor(defaultNode, &nodeInfo);
517 fVideoView->SetDefaultInput(&nodeInfo);
518 // this causes our listview to be updated as well
519 }
520
521 if (roster->GetVideoOutput(&defaultNode) == B_OK) {
522 roster->GetDormantNodeFor(defaultNode, &nodeInfo);
523 fVideoView->SetDefaultOutput(&nodeInfo);
524 // this causes our listview to be updated as well
525 }
526
527 if (first)
528 fListView->Select(fListView->IndexOf(mixer));
529 else if (isVideoSelected)
530 fListView->Select(fListView->IndexOf(video));
531 else
532 fListView->Select(fListView->IndexOf(audio));
533
534 Unlock();
535
536 return B_OK;
537 }
538
539
540 void
_FindNodes()541 MediaWindow::_FindNodes()
542 {
543 _FindNodes(B_MEDIA_RAW_AUDIO, B_PHYSICAL_OUTPUT, fAudioOutputs);
544 _FindNodes(B_MEDIA_RAW_AUDIO, B_PHYSICAL_INPUT, fAudioInputs);
545 _FindNodes(B_MEDIA_ENCODED_AUDIO, B_PHYSICAL_OUTPUT, fAudioOutputs);
546 _FindNodes(B_MEDIA_ENCODED_AUDIO, B_PHYSICAL_INPUT, fAudioInputs);
547 _FindNodes(B_MEDIA_RAW_VIDEO, B_PHYSICAL_OUTPUT, fVideoOutputs);
548 _FindNodes(B_MEDIA_RAW_VIDEO, B_PHYSICAL_INPUT, fVideoInputs);
549 _FindNodes(B_MEDIA_ENCODED_VIDEO, B_PHYSICAL_OUTPUT, fVideoOutputs);
550 _FindNodes(B_MEDIA_ENCODED_VIDEO, B_PHYSICAL_INPUT, fVideoInputs);
551 }
552
553
554 void
_FindNodes(media_type type,uint64 kind,NodeList & into)555 MediaWindow::_FindNodes(media_type type, uint64 kind, NodeList& into)
556 {
557 dormant_node_info nodeInfo[64];
558 int32 nodeInfoCount = 64;
559
560 media_format format;
561 media_format* nodeInputFormat = NULL;
562 media_format* nodeOutputFormat = NULL;
563 format.type = type;
564
565 // output nodes must be BBufferConsumers => they have an input format
566 // input nodes must be BBufferProducers => they have an output format
567 if ((kind & B_PHYSICAL_OUTPUT) != 0)
568 nodeInputFormat = &format;
569 else if ((kind & B_PHYSICAL_INPUT) != 0)
570 nodeOutputFormat = &format;
571 else
572 return;
573
574 BMediaRoster* roster = BMediaRoster::Roster();
575
576 if (roster->GetDormantNodes(nodeInfo, &nodeInfoCount, nodeInputFormat,
577 nodeOutputFormat, NULL, kind) != B_OK) {
578 // TODO: better error reporting!
579 fprintf(stderr, "error\n");
580 return;
581 }
582
583 for (int32 i = 0; i < nodeInfoCount; i++) {
584 PRINT(("node : %s, media_addon %i, flavor_id %i\n",
585 nodeInfo[i].name, (int)nodeInfo[i].addon,
586 (int)nodeInfo[i].flavor_id));
587
588 dormant_node_info* info = new dormant_node_info();
589 strlcpy(info->name, nodeInfo[i].name, B_MEDIA_NAME_LENGTH);
590 info->flavor_id = nodeInfo[i].flavor_id;
591 info->addon = nodeInfo[i].addon;
592 into.AddItem(info);
593 }
594 }
595
596
597 void
_AddNodeItems(NodeList & list,MediaListItem::media_type type)598 MediaWindow::_AddNodeItems(NodeList& list, MediaListItem::media_type type)
599 {
600 int32 count = list.CountItems();
601 for (int32 i = 0; i < count; i++) {
602 dormant_node_info* info = list.ItemAt(i);
603 if (_FindNodeListItem(info) == NULL)
604 fListView->AddItem(new NodeListItem(info, type));
605 }
606 }
607
608
609 void
_EmptyNodeLists()610 MediaWindow::_EmptyNodeLists()
611 {
612 fAudioOutputs.MakeEmpty();
613 fAudioInputs.MakeEmpty();
614 fVideoOutputs.MakeEmpty();
615 fVideoInputs.MakeEmpty();
616 }
617
618
619 NodeListItem*
_FindNodeListItem(dormant_node_info * info)620 MediaWindow::_FindNodeListItem(dormant_node_info* info)
621 {
622 NodeListItem audioItem(info, MediaListItem::AUDIO_TYPE);
623 NodeListItem videoItem(info, MediaListItem::VIDEO_TYPE);
624
625 NodeListItem::Comparator audioComparator(&audioItem);
626 NodeListItem::Comparator videoComparator(&videoItem);
627
628 for (int32 i = 0; i < fListView->CountItems(); i++) {
629 MediaListItem* item = static_cast<MediaListItem*>(fListView->ItemAt(i));
630 item->Accept(audioComparator);
631 if (audioComparator.result == 0)
632 return static_cast<NodeListItem*>(item);
633
634 item->Accept(videoComparator);
635 if (videoComparator.result == 0)
636 return static_cast<NodeListItem*>(item);
637 }
638 return NULL;
639 }
640
641
642 void
_UpdateListViewMinWidth()643 MediaWindow::_UpdateListViewMinWidth()
644 {
645 float width = 0;
646 for (int32 i = 0; i < fListView->CountItems(); i++) {
647 BListItem* item = fListView->ItemAt(i);
648 width = max_c(width, item->Width());
649 }
650 fListView->SetExplicitMinSize(BSize(width, B_SIZE_UNSET));
651 fListView->InvalidateLayout();
652 }
653
654
655 status_t
_RestartMediaServices(void * data)656 MediaWindow::_RestartMediaServices(void* data)
657 {
658 MediaWindow* window = (MediaWindow*)data;
659
660 shutdown_media_server();
661
662 if (window->fRestartAlert != NULL
663 && window->fRestartAlert->Lock()) {
664 window->fRestartAlert->Quit();
665 }
666
667 return window->PostMessage(ML_RESTART_THREAD_FINISHED);
668 }
669
670
671 void
_ClearParamView()672 MediaWindow::_ClearParamView()
673 {
674 BLayoutItem* item = fContentLayout->VisibleItem();
675 if (!item)
676 return;
677
678 BView* view = item->View();
679 if (view != fVideoView && view != fAudioView && view != fMidiView) {
680 fContentLayout->RemoveItem(item);
681 delete view;
682 delete fParamWeb;
683 fParamWeb = NULL;
684 }
685 }
686
687
688 void
_MakeParamView()689 MediaWindow::_MakeParamView()
690 {
691 if (!fCurrentNode.IsSet())
692 return;
693
694 fParamWeb = NULL;
695 BMediaRoster* roster = BMediaRoster::Roster();
696 if (roster->GetParameterWebFor(fCurrentNode, &fParamWeb) == B_OK) {
697 BRect hint(fContentLayout->Frame());
698 BView* paramView = BMediaTheme::ViewFor(fParamWeb, &hint);
699 if (paramView) {
700 fContentLayout->AddView(paramView);
701 fContentLayout->SetVisibleItem(fContentLayout->CountItems() - 1);
702 return;
703 }
704 }
705
706 _MakeEmptyParamView();
707 }
708
709
710 void
_MakeEmptyParamView()711 MediaWindow::_MakeEmptyParamView()
712 {
713 fParamWeb = NULL;
714
715 BStringView* stringView = new BStringView("noControls",
716 B_TRANSLATE("This hardware has no controls."));
717
718 BSize unlimited(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
719 stringView->SetExplicitMaxSize(unlimited);
720
721 BAlignment centered(B_ALIGN_HORIZONTAL_CENTER,
722 B_ALIGN_VERTICAL_CENTER);
723 stringView->SetExplicitAlignment(centered);
724 stringView->SetAlignment(B_ALIGN_CENTER);
725
726 fContentLayout->AddView(stringView);
727 fContentLayout->SetVisibleItem(fContentLayout->CountItems() - 1);
728
729 rgb_color panel = stringView->LowColor();
730 stringView->SetHighColor(tint_color(panel,
731 B_DISABLED_LABEL_TINT));
732 }
733
734