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