1 /* 2 * Copyright 2003-2009, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2019, Haiku, Inc. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include "DefaultMediaTheme.h" 9 10 #include <Box.h> 11 #include <Button.h> 12 #include <ChannelSlider.h> 13 #include <CheckBox.h> 14 #include <GroupView.h> 15 #include <MediaRoster.h> 16 #include <MenuField.h> 17 #include <MessageFilter.h> 18 #include <OptionPopUp.h> 19 #include <ParameterWeb.h> 20 #include <ScrollBar.h> 21 #include <ScrollView.h> 22 #include <Slider.h> 23 #include <SpaceLayoutItem.h> 24 #include <StringView.h> 25 #include <TabView.h> 26 #include <TextControl.h> 27 #include <Window.h> 28 29 #include "MediaDebug.h" 30 31 32 using namespace BPrivate; 33 34 35 namespace BPrivate { 36 37 namespace DefaultMediaControls { 38 39 class SeparatorView : public BView { 40 public: 41 SeparatorView(orientation orientation); 42 virtual ~SeparatorView(); 43 44 virtual void Draw(BRect updateRect); 45 46 private: 47 bool fVertical; 48 }; 49 50 class TitleView : public BView { 51 public: 52 TitleView(const char *title); 53 virtual ~TitleView(); 54 55 virtual void Draw(BRect updateRect); 56 virtual void GetPreferredSize(float *width, float *height); 57 58 private: 59 BString fTitle; 60 }; 61 62 class CheckBox : public BCheckBox { 63 public: 64 CheckBox(const char* name, const char* label, 65 BDiscreteParameter ¶meter); 66 virtual ~CheckBox(); 67 68 virtual void AttachedToWindow(); 69 virtual void DetachedFromWindow(); 70 private: 71 BDiscreteParameter &fParameter; 72 }; 73 74 class OptionPopUp : public BOptionPopUp { 75 public: 76 OptionPopUp(const char* name, const char* label, 77 BDiscreteParameter ¶meter); 78 virtual ~OptionPopUp(); 79 80 virtual void AttachedToWindow(); 81 virtual void DetachedFromWindow(); 82 private: 83 BDiscreteParameter &fParameter; 84 }; 85 86 class Slider : public BSlider { 87 public: 88 Slider(const char* name, const char*label, int32 minValue, 89 int32 maxValue, BContinuousParameter ¶meter); 90 virtual ~Slider(); 91 92 virtual void AttachedToWindow(); 93 virtual void DetachedFromWindow(); 94 private: 95 BContinuousParameter &fParameter; 96 }; 97 98 class ChannelSlider : public BChannelSlider { 99 public: 100 ChannelSlider(const char* name, const char* label, 101 orientation orientation, int32 channels, 102 BContinuousParameter ¶meter); 103 virtual ~ChannelSlider(); 104 105 virtual void AttachedToWindow(); 106 virtual void DetachedFromWindow(); 107 private: 108 BContinuousParameter &fParameter; 109 }; 110 111 class MessageFilter : public BMessageFilter { 112 public: 113 static MessageFilter *FilterFor(BView *view, BParameter ¶meter); 114 115 protected: 116 MessageFilter(); 117 }; 118 119 class ContinuousMessageFilter : public MessageFilter { 120 public: 121 ContinuousMessageFilter(BControl *control, 122 BContinuousParameter ¶meter); 123 virtual ~ContinuousMessageFilter(); 124 125 virtual filter_result Filter(BMessage *message, BHandler **target); 126 127 private: 128 void _UpdateControl(); 129 130 BControl *fControl; 131 BContinuousParameter &fParameter; 132 }; 133 134 class DiscreteMessageFilter : public MessageFilter { 135 public: 136 DiscreteMessageFilter(BControl *control, BDiscreteParameter ¶meter); 137 virtual ~DiscreteMessageFilter(); 138 139 virtual filter_result Filter(BMessage *message, BHandler **target); 140 141 private: 142 BDiscreteParameter &fParameter; 143 }; 144 145 }; 146 147 using namespace DefaultMediaControls; 148 149 } // namespace BPrivate 150 151 152 const uint32 kMsgParameterChanged = '_mPC'; 153 154 155 static bool 156 parameter_should_be_hidden(BParameter ¶meter) 157 { 158 // ToDo: note, this is probably completely stupid, but it's the only 159 // way I could safely remove the null parameters that are not shown 160 // by the R5 media theme 161 if (parameter.Type() != BParameter::B_NULL_PARAMETER 162 || strcmp(parameter.Kind(), B_WEB_PHYSICAL_INPUT)) 163 return false; 164 165 for (int32 i = 0; i < parameter.CountOutputs(); i++) { 166 if (!strcmp(parameter.OutputAt(0)->Kind(), B_INPUT_MUX)) 167 return true; 168 } 169 170 return false; 171 } 172 173 174 static void 175 start_watching_for_parameter_changes(BControl* control, BParameter ¶meter) 176 { 177 BMediaRoster* roster = BMediaRoster::CurrentRoster(); 178 if (roster == NULL) 179 return; 180 181 if (roster->StartWatching(control, parameter.Web()->Node(), 182 B_MEDIA_NEW_PARAMETER_VALUE) != B_OK) { 183 fprintf(stderr, "DefaultMediaTheme: Failed to start watching parameter" 184 "\"%s\"\n", parameter.Name()); 185 return; 186 } 187 } 188 189 190 static void 191 stop_watching_for_parameter_changes(BControl* control, BParameter ¶meter) 192 { 193 BMediaRoster* roster = BMediaRoster::CurrentRoster(); 194 if (roster == NULL) 195 return; 196 197 roster->StopWatching(control, parameter.Web()->Node(), 198 B_MEDIA_NEW_PARAMETER_VALUE); 199 } 200 201 202 // #pragma mark - 203 204 205 SeparatorView::SeparatorView(orientation orientation) 206 : BView("-", B_WILL_DRAW), 207 fVertical(orientation == B_VERTICAL) 208 { 209 if (fVertical) { 210 SetExplicitMinSize(BSize(5, 0)); 211 SetExplicitMaxSize(BSize(5, MaxSize().height)); 212 } else { 213 SetExplicitMinSize(BSize(0, 5)); 214 SetExplicitMaxSize(BSize(MaxSize().width, 5)); 215 } 216 } 217 218 219 SeparatorView::~SeparatorView() 220 { 221 } 222 223 224 void 225 SeparatorView::Draw(BRect updateRect) 226 { 227 rgb_color color = ui_color(B_PANEL_BACKGROUND_COLOR); 228 BRect rect = updateRect & Bounds(); 229 230 SetHighColor(tint_color(color, B_DARKEN_1_TINT)); 231 if (fVertical) 232 StrokeLine(BPoint(0, rect.top), BPoint(0, rect.bottom)); 233 else 234 StrokeLine(BPoint(rect.left, 0), BPoint(rect.right, 0)); 235 236 SetHighColor(tint_color(color, B_LIGHTEN_1_TINT)); 237 if (fVertical) 238 StrokeLine(BPoint(1, rect.top), BPoint(1, rect.bottom)); 239 else 240 StrokeLine(BPoint(rect.left, 1), BPoint(rect.right, 1)); 241 } 242 243 244 // #pragma mark - 245 246 247 TitleView::TitleView(const char *title) 248 : BView(title, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), 249 fTitle(title) 250 { 251 AdoptSystemColors(); 252 } 253 254 255 TitleView::~TitleView() 256 { 257 } 258 259 260 void 261 TitleView::Draw(BRect updateRect) 262 { 263 BRect rect(Bounds()); 264 rect.left = (rect.Width() - StringWidth(fTitle)) / 2; 265 266 SetDrawingMode(B_OP_COPY); 267 SetHighColor(tint_color(ViewColor(), B_LIGHTEN_2_TINT)); 268 DrawString(fTitle, BPoint(rect.left + 1, rect.bottom - 8)); 269 270 SetDrawingMode(B_OP_OVER); 271 SetHighColor(80, 20, 20); 272 DrawString(fTitle, BPoint(rect.left, rect.bottom - 9)); 273 } 274 275 276 void 277 TitleView::GetPreferredSize(float *_width, float *_height) 278 { 279 if (_width) 280 *_width = StringWidth(fTitle) + 2; 281 282 if (_height) { 283 font_height fontHeight; 284 GetFontHeight(&fontHeight); 285 286 *_height = fontHeight.ascent + fontHeight.descent + fontHeight.leading 287 + 8; 288 } 289 } 290 291 292 // #pragma mark - 293 294 295 CheckBox::CheckBox(const char* name, const char* label, 296 BDiscreteParameter ¶meter) 297 : BCheckBox(name, label, NULL), 298 fParameter(parameter) 299 { 300 } 301 302 303 CheckBox::~CheckBox() 304 { 305 } 306 307 308 void 309 CheckBox::AttachedToWindow() 310 { 311 BCheckBox::AttachedToWindow(); 312 313 SetTarget(this); 314 start_watching_for_parameter_changes(this, fParameter); 315 } 316 317 318 void 319 CheckBox::DetachedFromWindow() 320 { 321 stop_watching_for_parameter_changes(this, fParameter); 322 } 323 324 325 OptionPopUp::OptionPopUp(const char* name, const char* label, 326 BDiscreteParameter ¶meter) 327 : BOptionPopUp(name, label, NULL), 328 fParameter(parameter) 329 { 330 } 331 332 333 OptionPopUp::~OptionPopUp() 334 { 335 } 336 337 338 void 339 OptionPopUp::AttachedToWindow() 340 { 341 BOptionPopUp::AttachedToWindow(); 342 343 SetTarget(this); 344 start_watching_for_parameter_changes(this, fParameter); 345 } 346 347 348 void 349 OptionPopUp::DetachedFromWindow() 350 { 351 stop_watching_for_parameter_changes(this, fParameter); 352 } 353 354 355 Slider::Slider(const char* name, const char* label, int32 minValue, 356 int32 maxValue, BContinuousParameter ¶meter) 357 : BSlider(name, label, NULL, minValue, maxValue, B_HORIZONTAL), 358 fParameter(parameter) 359 { 360 } 361 362 363 Slider::~Slider() 364 { 365 } 366 367 368 void 369 Slider::AttachedToWindow() 370 { 371 BSlider::AttachedToWindow(); 372 373 SetTarget(this); 374 start_watching_for_parameter_changes(this, fParameter); 375 } 376 377 378 void 379 Slider::DetachedFromWindow() 380 { 381 stop_watching_for_parameter_changes(this, fParameter); 382 } 383 384 385 ChannelSlider::ChannelSlider(const char* name, const char* label, 386 orientation orientation, int32 channels, BContinuousParameter ¶meter) 387 : BChannelSlider(name, label, NULL, orientation, channels), 388 fParameter(parameter) 389 { 390 } 391 392 393 ChannelSlider::~ChannelSlider() 394 { 395 } 396 397 398 void 399 ChannelSlider::AttachedToWindow() 400 { 401 BChannelSlider::AttachedToWindow(); 402 403 SetTarget(this); 404 start_watching_for_parameter_changes(this, fParameter); 405 } 406 407 408 void 409 ChannelSlider::DetachedFromWindow() 410 { 411 stop_watching_for_parameter_changes(this, fParameter); 412 413 BChannelSlider::DetachedFromWindow(); 414 } 415 416 417 // #pragma mark - 418 419 420 MessageFilter::MessageFilter() 421 : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE) 422 { 423 } 424 425 426 MessageFilter * 427 MessageFilter::FilterFor(BView *view, BParameter ¶meter) 428 { 429 BControl *control = dynamic_cast<BControl *>(view); 430 if (control == NULL) 431 return NULL; 432 433 switch (parameter.Type()) { 434 case BParameter::B_CONTINUOUS_PARAMETER: 435 return new ContinuousMessageFilter(control, 436 static_cast<BContinuousParameter &>(parameter)); 437 438 case BParameter::B_DISCRETE_PARAMETER: 439 return new DiscreteMessageFilter(control, 440 static_cast<BDiscreteParameter &>(parameter)); 441 442 case BParameter::B_NULL_PARAMETER: /* fall through */ 443 default: 444 return NULL; 445 } 446 } 447 448 449 // #pragma mark - 450 451 452 ContinuousMessageFilter::ContinuousMessageFilter(BControl *control, 453 BContinuousParameter ¶meter) 454 : MessageFilter(), 455 fControl(control), 456 fParameter(parameter) 457 { 458 // initialize view for us 459 control->SetMessage(new BMessage(kMsgParameterChanged)); 460 461 if (BSlider *slider = dynamic_cast<BSlider *>(fControl)) 462 slider->SetModificationMessage(new BMessage(kMsgParameterChanged)); 463 else if (BChannelSlider *slider = dynamic_cast<BChannelSlider *>(fControl)) 464 slider->SetModificationMessage(new BMessage(kMsgParameterChanged)); 465 else 466 ERROR("ContinuousMessageFilter: unknown continuous parameter view\n"); 467 468 // set initial value 469 _UpdateControl(); 470 } 471 472 473 ContinuousMessageFilter::~ContinuousMessageFilter() 474 { 475 } 476 477 478 filter_result 479 ContinuousMessageFilter::Filter(BMessage *message, BHandler **target) 480 { 481 if (*target != fControl) 482 return B_DISPATCH_MESSAGE; 483 484 if (message->what == kMsgParameterChanged) { 485 // update parameter from control 486 // TODO: support for response! 487 488 float value[fParameter.CountChannels()]; 489 490 if (BSlider *slider = dynamic_cast<BSlider *>(fControl)) { 491 value[0] = (float)(slider->Value() / 1000.0); 492 } else if (BChannelSlider *slider 493 = dynamic_cast<BChannelSlider *>(fControl)) { 494 for (int32 i = 0; i < fParameter.CountChannels(); i++) 495 value[i] = (float)(slider->ValueFor(i) / 1000.0); 496 } 497 498 TRACE("ContinuousMessageFilter::Filter: update view %s, %" B_PRId32 499 " channels\n", fControl->Name(), fParameter.CountChannels()); 500 501 if (fParameter.SetValue((void *)value, sizeof(value), 502 -1) < B_OK) { 503 ERROR("ContinuousMessageFilter::Filter: Could not set parameter " 504 "value for %p\n", &fParameter); 505 return B_DISPATCH_MESSAGE; 506 } 507 return B_SKIP_MESSAGE; 508 } 509 if (message->what == B_MEDIA_NEW_PARAMETER_VALUE) { 510 // update view from parameter -- if the message concerns us 511 const media_node* node; 512 int32 parameterID; 513 ssize_t size; 514 if (message->FindInt32("parameter", ¶meterID) != B_OK 515 || fParameter.ID() != parameterID 516 || message->FindData("node", B_RAW_TYPE, (const void**)&node, 517 &size) != B_OK 518 || fParameter.Web()->Node() != *node) 519 return B_DISPATCH_MESSAGE; 520 521 _UpdateControl(); 522 return B_SKIP_MESSAGE; 523 } 524 525 return B_DISPATCH_MESSAGE; 526 } 527 528 529 void 530 ContinuousMessageFilter::_UpdateControl() 531 { 532 // TODO: response support! 533 534 float value[fParameter.CountChannels()]; 535 size_t size = sizeof(value); 536 if (fParameter.GetValue((void *)&value, &size, NULL) < B_OK) { 537 ERROR("ContinuousMessageFilter: Could not get value for continuous " 538 "parameter %p (name '%s', node %d)\n", &fParameter, 539 fParameter.Name(), (int)fParameter.Web()->Node().node); 540 return; 541 } 542 543 if (BSlider *slider = dynamic_cast<BSlider *>(fControl)) { 544 slider->SetValue((int32) (1000 * value[0])); 545 slider->SetModificationMessage(new BMessage(kMsgParameterChanged)); 546 } else if (BChannelSlider *slider 547 = dynamic_cast<BChannelSlider *>(fControl)) { 548 for (int32 i = 0; i < fParameter.CountChannels(); i++) { 549 slider->SetValueFor(i, (int32) (1000 * value[i])); 550 } 551 } 552 } 553 554 555 // #pragma mark - 556 557 558 DiscreteMessageFilter::DiscreteMessageFilter(BControl *control, 559 BDiscreteParameter ¶meter) 560 : MessageFilter(), 561 fParameter(parameter) 562 { 563 // initialize view for us 564 control->SetMessage(new BMessage(kMsgParameterChanged)); 565 566 // set initial value 567 size_t size = sizeof(int32); 568 int32 value; 569 if (parameter.GetValue((void *)&value, &size, NULL) < B_OK) { 570 ERROR("DiscreteMessageFilter: Could not get value for discrete " 571 "parameter %p (name '%s', node %d)\n", ¶meter, 572 parameter.Name(), (int)(parameter.Web()->Node().node)); 573 return; 574 } 575 576 if (BCheckBox *checkBox = dynamic_cast<BCheckBox *>(control)) { 577 checkBox->SetValue(value); 578 } else if (BOptionPopUp *popUp = dynamic_cast<BOptionPopUp *>(control)) { 579 popUp->SelectOptionFor(value); 580 } else 581 ERROR("DiscreteMessageFilter: unknown discrete parameter view\n"); 582 } 583 584 585 DiscreteMessageFilter::~DiscreteMessageFilter() 586 { 587 } 588 589 590 filter_result 591 DiscreteMessageFilter::Filter(BMessage *message, BHandler **target) 592 { 593 BControl *control; 594 595 if ((control = dynamic_cast<BControl *>(*target)) == NULL) 596 return B_DISPATCH_MESSAGE; 597 598 if (message->what == B_MEDIA_NEW_PARAMETER_VALUE) { 599 TRACE("DiscreteMessageFilter::Filter: Got a new parameter value\n"); 600 const media_node* node; 601 int32 parameterID; 602 ssize_t size; 603 if (message->FindInt32("parameter", ¶meterID) != B_OK 604 || fParameter.ID() != parameterID 605 || message->FindData("node", B_RAW_TYPE, (const void**)&node, 606 &size) != B_OK 607 || fParameter.Web()->Node() != *node) 608 return B_DISPATCH_MESSAGE; 609 610 int32 value = 0; 611 size_t valueSize = sizeof(int32); 612 if (fParameter.GetValue((void*)&value, &valueSize, NULL) < B_OK) { 613 ERROR("DiscreteMessageFilter: Could not get value for continuous " 614 "parameter %p (name '%s', node %d)\n", &fParameter, 615 fParameter.Name(), (int)fParameter.Web()->Node().node); 616 return B_SKIP_MESSAGE; 617 } 618 if (BCheckBox* checkBox = dynamic_cast<BCheckBox*>(control)) { 619 checkBox->SetValue(value); 620 } else if (BOptionPopUp* popUp = dynamic_cast<BOptionPopUp*>(control)) { 621 popUp->SetValue(value); 622 } 623 624 return B_SKIP_MESSAGE; 625 } 626 627 if (message->what != kMsgParameterChanged) 628 return B_DISPATCH_MESSAGE; 629 630 // update view 631 632 int32 value = 0; 633 634 if (BCheckBox *checkBox = dynamic_cast<BCheckBox *>(control)) { 635 value = checkBox->Value(); 636 } else if (BOptionPopUp *popUp = dynamic_cast<BOptionPopUp *>(control)) { 637 popUp->SelectedOption(NULL, &value); 638 } 639 640 TRACE("DiscreteMessageFilter::Filter: update view %s, value = %" 641 B_PRId32 "\n", control->Name(), value); 642 643 if (fParameter.SetValue((void *)&value, sizeof(value), -1) < B_OK) { 644 ERROR("DiscreteMessageFilter::Filter: Could not set parameter value for %p\n", &fParameter); 645 return B_DISPATCH_MESSAGE; 646 } 647 648 return B_SKIP_MESSAGE; 649 } 650 651 652 // #pragma mark - 653 654 655 DefaultMediaTheme::DefaultMediaTheme() 656 : BMediaTheme("Haiku theme", "Haiku built-in theme version 0.1") 657 { 658 CALLED(); 659 } 660 661 662 BControl * 663 DefaultMediaTheme::MakeControlFor(BParameter *parameter) 664 { 665 CALLED(); 666 667 return MakeViewFor(parameter); 668 } 669 670 671 BView * 672 DefaultMediaTheme::MakeViewFor(BParameterWeb *web, const BRect *hintRect) 673 { 674 CALLED(); 675 676 if (web == NULL) 677 return NULL; 678 679 // do we have more than one attached parameter group? 680 // if so, use a tabbed view with a tab for each group 681 682 BTabView *tabView = NULL; 683 if (web->CountGroups() > 1) 684 tabView = new BTabView("web"); 685 686 for (int32 i = 0; i < web->CountGroups(); i++) { 687 BParameterGroup *group = web->GroupAt(i); 688 if (group == NULL) 689 continue; 690 691 BView *groupView = MakeViewFor(*group); 692 if (groupView == NULL) 693 continue; 694 695 BScrollView *scrollView = new BScrollView(groupView->Name(), groupView, 0, 696 true, true, B_NO_BORDER); 697 scrollView->SetExplicitMinSize(BSize(B_V_SCROLL_BAR_WIDTH, 698 B_H_SCROLL_BAR_HEIGHT)); 699 if (tabView == NULL) { 700 if (hintRect != NULL) { 701 scrollView->MoveTo(hintRect->LeftTop()); 702 scrollView->ResizeTo(hintRect->Size()); 703 } else { 704 scrollView->ResizeTo(600, 400); 705 // See comment below. 706 } 707 return scrollView; 708 } 709 tabView->AddTab(scrollView); 710 } 711 712 if (hintRect != NULL) { 713 tabView->MoveTo(hintRect->LeftTop()); 714 tabView->ResizeTo(hintRect->Size()); 715 } else { 716 // Apps not using layouted views may expect PreferredSize() to return 717 // a sane value right away, and use this to set the maximum size of 718 // things. Layouted views return their current size until the view has 719 // been attached to the window, so in order to prevent breakage, we set 720 // a default view size here. 721 tabView->ResizeTo(600, 400); 722 } 723 return tabView; 724 } 725 726 727 BView * 728 DefaultMediaTheme::MakeViewFor(BParameterGroup& group) 729 { 730 CALLED(); 731 732 if (group.Flags() & B_HIDDEN_PARAMETER) 733 return NULL; 734 735 BGroupView *view = new BGroupView(group.Name(), B_HORIZONTAL, 736 B_USE_HALF_ITEM_SPACING); 737 BGroupLayout *layout = view->GroupLayout(); 738 layout->SetInsets(B_USE_HALF_ITEM_INSETS); 739 740 // Create and add the parameter views 741 if (group.CountParameters() > 0) { 742 BGroupView *paramView = new BGroupView(group.Name(), B_VERTICAL, 743 B_USE_HALF_ITEM_SPACING); 744 BGroupLayout *paramLayout = paramView->GroupLayout(); 745 paramLayout->SetInsets(0); 746 747 for (int32 i = 0; i < group.CountParameters(); i++) { 748 BParameter *parameter = group.ParameterAt(i); 749 if (parameter == NULL) 750 continue; 751 752 BView *parameterView = MakeSelfHostingViewFor(*parameter); 753 if (parameterView == NULL) 754 continue; 755 756 paramLayout->AddView(parameterView); 757 } 758 paramLayout->AddItem(BSpaceLayoutItem::CreateHorizontalStrut(10)); 759 layout->AddView(paramView); 760 } 761 762 // Add the sub-group views 763 for (int32 i = 0; i < group.CountGroups(); i++) { 764 BParameterGroup *subGroup = group.GroupAt(i); 765 if (subGroup == NULL) 766 continue; 767 768 BView *groupView = MakeViewFor(*subGroup); 769 if (groupView == NULL) 770 continue; 771 772 if (i > 0) 773 layout->AddView(new SeparatorView(B_VERTICAL)); 774 775 layout->AddView(groupView); 776 } 777 778 layout->AddItem(BSpaceLayoutItem::CreateGlue()); 779 return view; 780 } 781 782 783 /*! This creates a view that handles all incoming messages itself - that's 784 what is meant with self-hosting. 785 */ 786 BView * 787 DefaultMediaTheme::MakeSelfHostingViewFor(BParameter& parameter) 788 { 789 if (parameter.Flags() & B_HIDDEN_PARAMETER 790 || parameter_should_be_hidden(parameter)) 791 return NULL; 792 793 BView *view = MakeViewFor(¶meter); 794 if (view == NULL) { 795 // The MakeViewFor() method above returns a BControl - which we 796 // don't need for a null parameter; that's why it returns NULL. 797 // But we want to see something anyway, so we add a string view 798 // here. 799 if (parameter.Type() == BParameter::B_NULL_PARAMETER) { 800 if (parameter.Group()->ParameterAt(0) == ¶meter) { 801 // this is the first parameter in this group, so 802 // let's use a nice title view 803 return new TitleView(parameter.Name()); 804 } 805 BStringView *stringView = new BStringView(parameter.Name(), 806 parameter.Name()); 807 stringView->SetAlignment(B_ALIGN_CENTER); 808 809 return stringView; 810 } 811 812 return NULL; 813 } 814 815 MessageFilter *filter = MessageFilter::FilterFor(view, parameter); 816 if (filter != NULL) 817 view->AddFilter(filter); 818 819 return view; 820 } 821 822 823 BControl * 824 DefaultMediaTheme::MakeViewFor(BParameter *parameter) 825 { 826 switch (parameter->Type()) { 827 case BParameter::B_NULL_PARAMETER: 828 // there is no default view for a null parameter 829 return NULL; 830 831 case BParameter::B_DISCRETE_PARAMETER: 832 { 833 BDiscreteParameter &discrete 834 = static_cast<BDiscreteParameter &>(*parameter); 835 836 if (!strcmp(discrete.Kind(), B_ENABLE) 837 || !strcmp(discrete.Kind(), B_MUTE) 838 || discrete.CountItems() == 0) { 839 return new CheckBox(discrete.Name(), discrete.Name(), discrete); 840 } else { 841 BOptionPopUp *popUp = new OptionPopUp(discrete.Name(), 842 discrete.Name(), discrete); 843 844 for (int32 i = 0; i < discrete.CountItems(); i++) { 845 popUp->AddOption(discrete.ItemNameAt(i), 846 discrete.ItemValueAt(i)); 847 } 848 849 return popUp; 850 } 851 } 852 853 case BParameter::B_CONTINUOUS_PARAMETER: 854 { 855 BContinuousParameter &continuous 856 = static_cast<BContinuousParameter &>(*parameter); 857 858 if (!strcmp(continuous.Kind(), B_MASTER_GAIN) 859 || !strcmp(continuous.Kind(), B_GAIN)) { 860 BChannelSlider *slider = new ChannelSlider( 861 continuous.Name(), continuous.Name(), B_VERTICAL, 862 continuous.CountChannels(), continuous); 863 864 BString minLabel, maxLabel; 865 const char *unit = continuous.Unit(); 866 if (unit[0]) { 867 // if we have a unit, print it next to the limit values 868 minLabel.SetToFormat("%g %s", continuous.MinValue(), continuous.Unit()); 869 maxLabel.SetToFormat("%g %s", continuous.MaxValue(), continuous.Unit()); 870 } else { 871 minLabel.SetToFormat("%g", continuous.MinValue()); 872 maxLabel.SetToFormat("%g", continuous.MaxValue()); 873 } 874 slider->SetLimitLabels(minLabel, maxLabel); 875 876 // ToDo: take BContinuousParameter::GetResponse() & ValueStep() into account! 877 878 for (int32 i = 0; i < continuous.CountChannels(); i++) { 879 slider->SetLimitsFor(i, int32(continuous.MinValue() * 1000), 880 int32(continuous.MaxValue() * 1000)); 881 } 882 883 return slider; 884 } 885 886 BSlider *slider = new Slider(parameter->Name(), 887 parameter->Name(), int32(continuous.MinValue() * 1000), 888 int32(continuous.MaxValue() * 1000), continuous); 889 890 return slider; 891 } 892 893 default: 894 ERROR("BMediaTheme: Don't know parameter type: 0x%x\n", 895 parameter->Type()); 896 } 897 return NULL; 898 } 899 900