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 TextControl : public BTextControl { 112 public: 113 TextControl(const char* name, const char* label, 114 BTextParameter ¶meter); 115 virtual ~TextControl(); 116 117 virtual void AttachedToWindow(); 118 virtual void DetachedFromWindow(); 119 private: 120 BTextParameter &fParameter; 121 }; 122 123 class MessageFilter : public BMessageFilter { 124 public: 125 static MessageFilter *FilterFor(BView *view, BParameter ¶meter); 126 127 protected: 128 MessageFilter(); 129 }; 130 131 class ContinuousMessageFilter : public MessageFilter { 132 public: 133 ContinuousMessageFilter(BControl *control, 134 BContinuousParameter ¶meter); 135 virtual ~ContinuousMessageFilter(); 136 137 virtual filter_result Filter(BMessage *message, BHandler **target); 138 139 private: 140 void _UpdateControl(); 141 142 BControl *fControl; 143 BContinuousParameter &fParameter; 144 }; 145 146 class DiscreteMessageFilter : public MessageFilter { 147 public: 148 DiscreteMessageFilter(BControl *control, BDiscreteParameter ¶meter); 149 virtual ~DiscreteMessageFilter(); 150 151 virtual filter_result Filter(BMessage *message, BHandler **target); 152 153 private: 154 BDiscreteParameter &fParameter; 155 }; 156 157 class TextMessageFilter : public MessageFilter { 158 public: 159 TextMessageFilter(BControl *control, BTextParameter ¶meter); 160 virtual ~TextMessageFilter(); 161 162 virtual filter_result Filter(BMessage *message, BHandler **target); 163 164 private: 165 BTextParameter &fParameter; 166 }; 167 168 }; 169 170 using namespace DefaultMediaControls; 171 172 } // namespace BPrivate 173 174 175 const uint32 kMsgParameterChanged = '_mPC'; 176 177 178 static bool 179 parameter_should_be_hidden(BParameter ¶meter) 180 { 181 // ToDo: note, this is probably completely stupid, but it's the only 182 // way I could safely remove the null parameters that are not shown 183 // by the R5 media theme 184 if (parameter.Type() != BParameter::B_NULL_PARAMETER 185 || strcmp(parameter.Kind(), B_WEB_PHYSICAL_INPUT)) 186 return false; 187 188 for (int32 i = 0; i < parameter.CountOutputs(); i++) { 189 if (!strcmp(parameter.OutputAt(0)->Kind(), B_INPUT_MUX)) 190 return true; 191 } 192 193 return false; 194 } 195 196 197 static void 198 start_watching_for_parameter_changes(BControl* control, BParameter ¶meter) 199 { 200 BMediaRoster* roster = BMediaRoster::CurrentRoster(); 201 if (roster == NULL) 202 return; 203 204 if (roster->StartWatching(control, parameter.Web()->Node(), 205 B_MEDIA_NEW_PARAMETER_VALUE) != B_OK) { 206 fprintf(stderr, "DefaultMediaTheme: Failed to start watching parameter" 207 "\"%s\"\n", parameter.Name()); 208 return; 209 } 210 } 211 212 213 static void 214 stop_watching_for_parameter_changes(BControl* control, BParameter ¶meter) 215 { 216 BMediaRoster* roster = BMediaRoster::CurrentRoster(); 217 if (roster == NULL) 218 return; 219 220 roster->StopWatching(control, parameter.Web()->Node(), 221 B_MEDIA_NEW_PARAMETER_VALUE); 222 } 223 224 225 // #pragma mark - 226 227 228 SeparatorView::SeparatorView(orientation orientation) 229 : BView("-", B_WILL_DRAW), 230 fVertical(orientation == B_VERTICAL) 231 { 232 if (fVertical) { 233 SetExplicitMinSize(BSize(5, 0)); 234 SetExplicitMaxSize(BSize(5, MaxSize().height)); 235 } else { 236 SetExplicitMinSize(BSize(0, 5)); 237 SetExplicitMaxSize(BSize(MaxSize().width, 5)); 238 } 239 } 240 241 242 SeparatorView::~SeparatorView() 243 { 244 } 245 246 247 void 248 SeparatorView::Draw(BRect updateRect) 249 { 250 rgb_color color = ui_color(B_PANEL_BACKGROUND_COLOR); 251 BRect rect = updateRect & Bounds(); 252 253 SetHighColor(tint_color(color, B_DARKEN_1_TINT)); 254 if (fVertical) 255 StrokeLine(BPoint(0, rect.top), BPoint(0, rect.bottom)); 256 else 257 StrokeLine(BPoint(rect.left, 0), BPoint(rect.right, 0)); 258 259 SetHighColor(tint_color(color, B_LIGHTEN_1_TINT)); 260 if (fVertical) 261 StrokeLine(BPoint(1, rect.top), BPoint(1, rect.bottom)); 262 else 263 StrokeLine(BPoint(rect.left, 1), BPoint(rect.right, 1)); 264 } 265 266 267 // #pragma mark - 268 269 270 TitleView::TitleView(const char *title) 271 : BView(title, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), 272 fTitle(title) 273 { 274 AdoptSystemColors(); 275 } 276 277 278 TitleView::~TitleView() 279 { 280 } 281 282 283 void 284 TitleView::Draw(BRect updateRect) 285 { 286 BRect rect(Bounds()); 287 rect.left = (rect.Width() - StringWidth(fTitle)) / 2; 288 289 SetDrawingMode(B_OP_COPY); 290 SetHighColor(tint_color(ViewColor(), B_LIGHTEN_2_TINT)); 291 DrawString(fTitle, BPoint(rect.left + 1, rect.bottom - 8)); 292 293 SetDrawingMode(B_OP_OVER); 294 SetHighColor(80, 20, 20); 295 DrawString(fTitle, BPoint(rect.left, rect.bottom - 9)); 296 } 297 298 299 void 300 TitleView::GetPreferredSize(float *_width, float *_height) 301 { 302 if (_width) 303 *_width = StringWidth(fTitle) + 2; 304 305 if (_height) { 306 font_height fontHeight; 307 GetFontHeight(&fontHeight); 308 309 *_height = fontHeight.ascent + fontHeight.descent + fontHeight.leading 310 + 8; 311 } 312 } 313 314 315 // #pragma mark - 316 317 318 CheckBox::CheckBox(const char* name, const char* label, 319 BDiscreteParameter ¶meter) 320 : BCheckBox(name, label, NULL), 321 fParameter(parameter) 322 { 323 } 324 325 326 CheckBox::~CheckBox() 327 { 328 } 329 330 331 void 332 CheckBox::AttachedToWindow() 333 { 334 BCheckBox::AttachedToWindow(); 335 336 SetTarget(this); 337 start_watching_for_parameter_changes(this, fParameter); 338 } 339 340 341 void 342 CheckBox::DetachedFromWindow() 343 { 344 stop_watching_for_parameter_changes(this, fParameter); 345 } 346 347 348 OptionPopUp::OptionPopUp(const char* name, const char* label, 349 BDiscreteParameter ¶meter) 350 : BOptionPopUp(name, label, NULL), 351 fParameter(parameter) 352 { 353 } 354 355 356 OptionPopUp::~OptionPopUp() 357 { 358 } 359 360 361 void 362 OptionPopUp::AttachedToWindow() 363 { 364 BOptionPopUp::AttachedToWindow(); 365 366 SetTarget(this); 367 start_watching_for_parameter_changes(this, fParameter); 368 } 369 370 371 void 372 OptionPopUp::DetachedFromWindow() 373 { 374 stop_watching_for_parameter_changes(this, fParameter); 375 } 376 377 378 Slider::Slider(const char* name, const char* label, int32 minValue, 379 int32 maxValue, BContinuousParameter ¶meter) 380 : BSlider(name, label, NULL, minValue, maxValue, B_HORIZONTAL), 381 fParameter(parameter) 382 { 383 } 384 385 386 Slider::~Slider() 387 { 388 } 389 390 391 void 392 Slider::AttachedToWindow() 393 { 394 BSlider::AttachedToWindow(); 395 396 SetTarget(this); 397 start_watching_for_parameter_changes(this, fParameter); 398 } 399 400 401 void 402 Slider::DetachedFromWindow() 403 { 404 stop_watching_for_parameter_changes(this, fParameter); 405 } 406 407 408 ChannelSlider::ChannelSlider(const char* name, const char* label, 409 orientation orientation, int32 channels, BContinuousParameter ¶meter) 410 : BChannelSlider(name, label, NULL, orientation, channels), 411 fParameter(parameter) 412 { 413 } 414 415 416 ChannelSlider::~ChannelSlider() 417 { 418 } 419 420 421 void 422 ChannelSlider::AttachedToWindow() 423 { 424 BChannelSlider::AttachedToWindow(); 425 426 SetTarget(this); 427 start_watching_for_parameter_changes(this, fParameter); 428 } 429 430 431 void 432 ChannelSlider::DetachedFromWindow() 433 { 434 stop_watching_for_parameter_changes(this, fParameter); 435 436 BChannelSlider::DetachedFromWindow(); 437 } 438 439 440 TextControl::TextControl(const char* name, const char* label, 441 BTextParameter ¶meter) 442 : BTextControl(name, label, "", NULL), 443 fParameter(parameter) 444 { 445 } 446 447 448 TextControl::~TextControl() 449 { 450 } 451 452 453 void 454 TextControl::AttachedToWindow() 455 { 456 BTextControl::AttachedToWindow(); 457 458 SetTarget(this); 459 start_watching_for_parameter_changes(this, fParameter); 460 } 461 462 463 void 464 TextControl::DetachedFromWindow() 465 { 466 stop_watching_for_parameter_changes(this, fParameter); 467 } 468 469 470 // #pragma mark - 471 472 473 MessageFilter::MessageFilter() 474 : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE) 475 { 476 } 477 478 479 MessageFilter * 480 MessageFilter::FilterFor(BView *view, BParameter ¶meter) 481 { 482 BControl *control = dynamic_cast<BControl *>(view); 483 if (control == NULL) 484 return NULL; 485 486 switch (parameter.Type()) { 487 case BParameter::B_CONTINUOUS_PARAMETER: 488 return new ContinuousMessageFilter(control, 489 static_cast<BContinuousParameter &>(parameter)); 490 491 case BParameter::B_DISCRETE_PARAMETER: 492 return new DiscreteMessageFilter(control, 493 static_cast<BDiscreteParameter &>(parameter)); 494 495 case BParameter::B_TEXT_PARAMETER: 496 return new TextMessageFilter(control, 497 static_cast<BTextParameter &>(parameter)); 498 499 case BParameter::B_NULL_PARAMETER: /* fall through */ 500 default: 501 return NULL; 502 } 503 } 504 505 506 // #pragma mark - 507 508 509 ContinuousMessageFilter::ContinuousMessageFilter(BControl *control, 510 BContinuousParameter ¶meter) 511 : MessageFilter(), 512 fControl(control), 513 fParameter(parameter) 514 { 515 // initialize view for us 516 control->SetMessage(new BMessage(kMsgParameterChanged)); 517 518 if (BSlider *slider = dynamic_cast<BSlider *>(fControl)) 519 slider->SetModificationMessage(new BMessage(kMsgParameterChanged)); 520 else if (BChannelSlider *slider = dynamic_cast<BChannelSlider *>(fControl)) 521 slider->SetModificationMessage(new BMessage(kMsgParameterChanged)); 522 else 523 ERROR("ContinuousMessageFilter: unknown continuous parameter view\n"); 524 525 // set initial value 526 _UpdateControl(); 527 } 528 529 530 ContinuousMessageFilter::~ContinuousMessageFilter() 531 { 532 } 533 534 535 filter_result 536 ContinuousMessageFilter::Filter(BMessage *message, BHandler **target) 537 { 538 if (*target != fControl) 539 return B_DISPATCH_MESSAGE; 540 541 if (message->what == kMsgParameterChanged) { 542 // update parameter from control 543 // TODO: support for response! 544 545 float value[fParameter.CountChannels()]; 546 547 if (BSlider *slider = dynamic_cast<BSlider *>(fControl)) { 548 value[0] = (float)(slider->Value() / 1000.0); 549 } else if (BChannelSlider *slider 550 = dynamic_cast<BChannelSlider *>(fControl)) { 551 for (int32 i = 0; i < fParameter.CountChannels(); i++) 552 value[i] = (float)(slider->ValueFor(i) / 1000.0); 553 } 554 555 TRACE("ContinuousMessageFilter::Filter: update view %s, %" B_PRId32 556 " channels\n", fControl->Name(), fParameter.CountChannels()); 557 558 if (fParameter.SetValue((void *)value, sizeof(value), 559 -1) < B_OK) { 560 ERROR("ContinuousMessageFilter::Filter: Could not set parameter " 561 "value for %p\n", &fParameter); 562 return B_DISPATCH_MESSAGE; 563 } 564 return B_SKIP_MESSAGE; 565 } 566 if (message->what == B_MEDIA_NEW_PARAMETER_VALUE) { 567 // update view from parameter -- if the message concerns us 568 const media_node* node; 569 int32 parameterID; 570 ssize_t size; 571 if (message->FindInt32("parameter", ¶meterID) != B_OK 572 || fParameter.ID() != parameterID 573 || message->FindData("node", B_RAW_TYPE, (const void**)&node, 574 &size) != B_OK 575 || fParameter.Web()->Node() != *node) 576 return B_DISPATCH_MESSAGE; 577 578 _UpdateControl(); 579 return B_SKIP_MESSAGE; 580 } 581 582 return B_DISPATCH_MESSAGE; 583 } 584 585 586 void 587 ContinuousMessageFilter::_UpdateControl() 588 { 589 // TODO: response support! 590 591 float value[fParameter.CountChannels()]; 592 size_t size = sizeof(value); 593 if (fParameter.GetValue((void *)&value, &size, NULL) < B_OK) { 594 ERROR("ContinuousMessageFilter: Could not get value for continuous " 595 "parameter %p (name '%s', node %d)\n", &fParameter, 596 fParameter.Name(), (int)fParameter.Web()->Node().node); 597 return; 598 } 599 600 if (BSlider *slider = dynamic_cast<BSlider *>(fControl)) { 601 slider->SetValue((int32) (1000 * value[0])); 602 slider->SetModificationMessage(new BMessage(kMsgParameterChanged)); 603 } else if (BChannelSlider *slider 604 = dynamic_cast<BChannelSlider *>(fControl)) { 605 for (int32 i = 0; i < fParameter.CountChannels(); i++) { 606 slider->SetValueFor(i, (int32) (1000 * value[i])); 607 } 608 } 609 } 610 611 612 // #pragma mark - 613 614 615 DiscreteMessageFilter::DiscreteMessageFilter(BControl *control, 616 BDiscreteParameter ¶meter) 617 : MessageFilter(), 618 fParameter(parameter) 619 { 620 // initialize view for us 621 control->SetMessage(new BMessage(kMsgParameterChanged)); 622 623 // set initial value 624 size_t size = sizeof(int32); 625 int32 value; 626 if (parameter.GetValue((void *)&value, &size, NULL) < B_OK) { 627 ERROR("DiscreteMessageFilter: Could not get value for discrete " 628 "parameter %p (name '%s', node %d)\n", ¶meter, 629 parameter.Name(), (int)(parameter.Web()->Node().node)); 630 return; 631 } 632 633 if (BCheckBox *checkBox = dynamic_cast<BCheckBox *>(control)) { 634 checkBox->SetValue(value); 635 } else if (BOptionPopUp *popUp = dynamic_cast<BOptionPopUp *>(control)) { 636 popUp->SelectOptionFor(value); 637 } else 638 ERROR("DiscreteMessageFilter: unknown discrete parameter view\n"); 639 } 640 641 642 DiscreteMessageFilter::~DiscreteMessageFilter() 643 { 644 } 645 646 647 filter_result 648 DiscreteMessageFilter::Filter(BMessage *message, BHandler **target) 649 { 650 BControl *control; 651 652 if ((control = dynamic_cast<BControl *>(*target)) == NULL) 653 return B_DISPATCH_MESSAGE; 654 655 if (message->what == B_MEDIA_NEW_PARAMETER_VALUE) { 656 TRACE("DiscreteMessageFilter::Filter: Got a new parameter value\n"); 657 const media_node* node; 658 int32 parameterID; 659 ssize_t size; 660 if (message->FindInt32("parameter", ¶meterID) != B_OK 661 || fParameter.ID() != parameterID 662 || message->FindData("node", B_RAW_TYPE, (const void**)&node, 663 &size) != B_OK 664 || fParameter.Web()->Node() != *node) 665 return B_DISPATCH_MESSAGE; 666 667 int32 value = 0; 668 size_t valueSize = sizeof(int32); 669 if (fParameter.GetValue((void*)&value, &valueSize, NULL) < B_OK) { 670 ERROR("DiscreteMessageFilter: Could not get value for continuous " 671 "parameter %p (name '%s', node %d)\n", &fParameter, 672 fParameter.Name(), (int)fParameter.Web()->Node().node); 673 return B_SKIP_MESSAGE; 674 } 675 if (BCheckBox* checkBox = dynamic_cast<BCheckBox*>(control)) { 676 checkBox->SetValue(value); 677 } else if (BOptionPopUp* popUp = dynamic_cast<BOptionPopUp*>(control)) { 678 popUp->SetValue(value); 679 } 680 681 return B_SKIP_MESSAGE; 682 } 683 684 if (message->what != kMsgParameterChanged) 685 return B_DISPATCH_MESSAGE; 686 687 // update view 688 689 int32 value = 0; 690 691 if (BCheckBox *checkBox = dynamic_cast<BCheckBox *>(control)) { 692 value = checkBox->Value(); 693 } else if (BOptionPopUp *popUp = dynamic_cast<BOptionPopUp *>(control)) { 694 popUp->SelectedOption(NULL, &value); 695 } 696 697 TRACE("DiscreteMessageFilter::Filter: update view %s, value = %" 698 B_PRId32 "\n", control->Name(), value); 699 700 if (fParameter.SetValue((void *)&value, sizeof(value), -1) < B_OK) { 701 ERROR("DiscreteMessageFilter::Filter: Could not set parameter value for %p\n", &fParameter); 702 return B_DISPATCH_MESSAGE; 703 } 704 705 return B_SKIP_MESSAGE; 706 } 707 708 709 // #pragma mark - 710 711 712 TextMessageFilter::TextMessageFilter(BControl *control, 713 BTextParameter ¶meter) 714 : MessageFilter(), 715 fParameter(parameter) 716 { 717 // initialize view for us 718 control->SetMessage(new BMessage(kMsgParameterChanged)); 719 720 // set initial value 721 if (BTextControl *textControl = dynamic_cast<BTextControl *>(control)) { 722 size_t valueSize = parameter.MaxBytes(); 723 char* value = new char[valueSize + 1]; 724 725 if (parameter.GetValue((void *)value, &valueSize, NULL) < B_OK) { 726 ERROR("TextMessageFilter: Could not get value for text " 727 "parameter %p (name '%s', node %d)\n", ¶meter, 728 parameter.Name(), (int)(parameter.Web()->Node().node)); 729 } else { 730 textControl->SetText(value); 731 } 732 733 delete[] value; 734 } 735 736 ERROR("TextMessageFilter: unknown text parameter view\n"); 737 } 738 739 740 TextMessageFilter::~TextMessageFilter() 741 { 742 } 743 744 745 filter_result 746 TextMessageFilter::Filter(BMessage *message, BHandler **target) 747 { 748 BControl *control; 749 750 if ((control = dynamic_cast<BControl *>(*target)) == NULL) 751 return B_DISPATCH_MESSAGE; 752 753 if (message->what == B_MEDIA_NEW_PARAMETER_VALUE) { 754 TRACE("TextMessageFilter::Filter: Got a new parameter value\n"); 755 const media_node* node; 756 int32 parameterID; 757 ssize_t size; 758 if (message->FindInt32("parameter", ¶meterID) != B_OK 759 || fParameter.ID() != parameterID 760 || message->FindData("node", B_RAW_TYPE, (const void**)&node, 761 &size) != B_OK 762 || fParameter.Web()->Node() != *node) 763 return B_DISPATCH_MESSAGE; 764 765 if (BTextControl *textControl = dynamic_cast<BTextControl *>(control)) { 766 size_t valueSize = fParameter.MaxBytes(); 767 char* value = new char[valueSize + 1]; 768 if (fParameter.GetValue((void *)value, &valueSize, NULL) < B_OK) { 769 ERROR("TextMessageFilter: Could not get value for text " 770 "parameter %p (name '%s', node %d)\n", &fParameter, 771 fParameter.Name(), (int)(fParameter.Web()->Node().node)); 772 } else { 773 textControl->SetText(value); 774 } 775 776 delete[] value; 777 778 return B_SKIP_MESSAGE; 779 } 780 781 return B_DISPATCH_MESSAGE; 782 } 783 784 if (message->what != kMsgParameterChanged) 785 return B_DISPATCH_MESSAGE; 786 787 // update parameter value 788 789 if (BTextControl *textControl = dynamic_cast<BTextControl *>(control)) { 790 BString value = textControl->Text(); 791 TRACE("TextMessageFilter::Filter: update view %s, value = %s\n", 792 control->Name(), value.String()); 793 if (fParameter.SetValue((void *)value.String(), value.Length() + 1, -1) < B_OK) { 794 ERROR("TextMessageFilter::Filter: Could not set parameter value for %p\n", &fParameter); 795 return B_DISPATCH_MESSAGE; 796 } 797 } 798 799 return B_SKIP_MESSAGE; 800 } 801 802 803 // #pragma mark - 804 805 806 DefaultMediaTheme::DefaultMediaTheme() 807 : BMediaTheme("Haiku theme", "Haiku built-in theme version 0.1") 808 { 809 CALLED(); 810 } 811 812 813 BControl * 814 DefaultMediaTheme::MakeControlFor(BParameter *parameter) 815 { 816 CALLED(); 817 818 return MakeViewFor(parameter); 819 } 820 821 822 BView * 823 DefaultMediaTheme::MakeViewFor(BParameterWeb *web, const BRect *hintRect) 824 { 825 CALLED(); 826 827 if (web == NULL) 828 return NULL; 829 830 // do we have more than one attached parameter group? 831 // if so, use a tabbed view with a tab for each group 832 833 BTabView *tabView = NULL; 834 if (web->CountGroups() > 1) 835 tabView = new BTabView("web"); 836 837 for (int32 i = 0; i < web->CountGroups(); i++) { 838 BParameterGroup *group = web->GroupAt(i); 839 if (group == NULL) 840 continue; 841 842 BView *groupView = MakeViewFor(*group); 843 if (groupView == NULL) 844 continue; 845 846 BScrollView *scrollView = new BScrollView(groupView->Name(), groupView, 0, 847 true, true, B_NO_BORDER); 848 scrollView->SetExplicitMinSize(BSize(B_V_SCROLL_BAR_WIDTH, 849 B_H_SCROLL_BAR_HEIGHT)); 850 if (tabView == NULL) { 851 if (hintRect != NULL) { 852 scrollView->MoveTo(hintRect->LeftTop()); 853 scrollView->ResizeTo(hintRect->Size()); 854 } else { 855 scrollView->ResizeTo(600, 400); 856 // See comment below. 857 } 858 return scrollView; 859 } 860 tabView->AddTab(scrollView); 861 } 862 863 if (hintRect != NULL) { 864 tabView->MoveTo(hintRect->LeftTop()); 865 tabView->ResizeTo(hintRect->Size()); 866 } else { 867 // Apps not using layouted views may expect PreferredSize() to return 868 // a sane value right away, and use this to set the maximum size of 869 // things. Layouted views return their current size until the view has 870 // been attached to the window, so in order to prevent breakage, we set 871 // a default view size here. 872 tabView->ResizeTo(600, 400); 873 } 874 return tabView; 875 } 876 877 878 BView * 879 DefaultMediaTheme::MakeViewFor(BParameterGroup& group) 880 { 881 CALLED(); 882 883 if (group.Flags() & B_HIDDEN_PARAMETER) 884 return NULL; 885 886 BGroupView *view = new BGroupView(group.Name(), B_HORIZONTAL, 887 B_USE_HALF_ITEM_SPACING); 888 BGroupLayout *layout = view->GroupLayout(); 889 layout->SetInsets(B_USE_HALF_ITEM_INSETS); 890 891 // Create and add the parameter views 892 if (group.CountParameters() > 0) { 893 BGroupView *paramView = new BGroupView(group.Name(), B_VERTICAL, 894 B_USE_HALF_ITEM_SPACING); 895 BGroupLayout *paramLayout = paramView->GroupLayout(); 896 paramLayout->SetInsets(0); 897 898 for (int32 i = 0; i < group.CountParameters(); i++) { 899 BParameter *parameter = group.ParameterAt(i); 900 if (parameter == NULL) 901 continue; 902 903 BView *parameterView = MakeSelfHostingViewFor(*parameter); 904 if (parameterView == NULL) 905 continue; 906 907 paramLayout->AddView(parameterView); 908 } 909 paramLayout->AddItem(BSpaceLayoutItem::CreateHorizontalStrut(10)); 910 layout->AddView(paramView); 911 } 912 913 // Add the sub-group views 914 for (int32 i = 0; i < group.CountGroups(); i++) { 915 BParameterGroup *subGroup = group.GroupAt(i); 916 if (subGroup == NULL) 917 continue; 918 919 BView *groupView = MakeViewFor(*subGroup); 920 if (groupView == NULL) 921 continue; 922 923 if (i > 0) 924 layout->AddView(new SeparatorView(B_VERTICAL)); 925 926 layout->AddView(groupView); 927 } 928 929 layout->AddItem(BSpaceLayoutItem::CreateGlue()); 930 return view; 931 } 932 933 934 /*! This creates a view that handles all incoming messages itself - that's 935 what is meant with self-hosting. 936 */ 937 BView * 938 DefaultMediaTheme::MakeSelfHostingViewFor(BParameter& parameter) 939 { 940 if (parameter.Flags() & B_HIDDEN_PARAMETER 941 || parameter_should_be_hidden(parameter)) 942 return NULL; 943 944 BView *view = MakeViewFor(¶meter); 945 if (view == NULL) { 946 // The MakeViewFor() method above returns a BControl - which we 947 // don't need for a null parameter; that's why it returns NULL. 948 // But we want to see something anyway, so we add a string view 949 // here. 950 if (parameter.Type() == BParameter::B_NULL_PARAMETER) { 951 if (parameter.Group()->ParameterAt(0) == ¶meter) { 952 // this is the first parameter in this group, so 953 // let's use a nice title view 954 return new TitleView(parameter.Name()); 955 } 956 BStringView *stringView = new BStringView(parameter.Name(), 957 parameter.Name()); 958 stringView->SetAlignment(B_ALIGN_CENTER); 959 960 return stringView; 961 } 962 963 return NULL; 964 } 965 966 MessageFilter *filter = MessageFilter::FilterFor(view, parameter); 967 if (filter != NULL) 968 view->AddFilter(filter); 969 970 return view; 971 } 972 973 974 BControl * 975 DefaultMediaTheme::MakeViewFor(BParameter *parameter) 976 { 977 switch (parameter->Type()) { 978 case BParameter::B_NULL_PARAMETER: 979 // there is no default view for a null parameter 980 return NULL; 981 982 case BParameter::B_DISCRETE_PARAMETER: 983 { 984 BDiscreteParameter &discrete 985 = static_cast<BDiscreteParameter &>(*parameter); 986 987 if (!strcmp(discrete.Kind(), B_ENABLE) 988 || !strcmp(discrete.Kind(), B_MUTE) 989 || discrete.CountItems() == 0) { 990 return new CheckBox(discrete.Name(), discrete.Name(), discrete); 991 } else { 992 BOptionPopUp *popUp = new OptionPopUp(discrete.Name(), 993 discrete.Name(), discrete); 994 995 for (int32 i = 0; i < discrete.CountItems(); i++) { 996 popUp->AddOption(discrete.ItemNameAt(i), 997 discrete.ItemValueAt(i)); 998 } 999 1000 return popUp; 1001 } 1002 } 1003 1004 case BParameter::B_CONTINUOUS_PARAMETER: 1005 { 1006 BContinuousParameter &continuous 1007 = static_cast<BContinuousParameter &>(*parameter); 1008 1009 if (!strcmp(continuous.Kind(), B_MASTER_GAIN) 1010 || !strcmp(continuous.Kind(), B_GAIN)) { 1011 BChannelSlider *slider = new ChannelSlider( 1012 continuous.Name(), continuous.Name(), B_VERTICAL, 1013 continuous.CountChannels(), continuous); 1014 1015 BString minLabel, maxLabel; 1016 const char *unit = continuous.Unit(); 1017 if (unit[0]) { 1018 // if we have a unit, print it next to the limit values 1019 minLabel.SetToFormat("%g %s", continuous.MinValue(), continuous.Unit()); 1020 maxLabel.SetToFormat("%g %s", continuous.MaxValue(), continuous.Unit()); 1021 } else { 1022 minLabel.SetToFormat("%g", continuous.MinValue()); 1023 maxLabel.SetToFormat("%g", continuous.MaxValue()); 1024 } 1025 slider->SetLimitLabels(minLabel, maxLabel); 1026 1027 // ToDo: take BContinuousParameter::GetResponse() & ValueStep() into account! 1028 1029 for (int32 i = 0; i < continuous.CountChannels(); i++) { 1030 slider->SetLimitsFor(i, int32(continuous.MinValue() * 1000), 1031 int32(continuous.MaxValue() * 1000)); 1032 } 1033 1034 return slider; 1035 } 1036 1037 BSlider *slider = new Slider(parameter->Name(), 1038 parameter->Name(), int32(continuous.MinValue() * 1000), 1039 int32(continuous.MaxValue() * 1000), continuous); 1040 1041 return slider; 1042 } 1043 1044 case BParameter::B_TEXT_PARAMETER: 1045 { 1046 BTextParameter &text 1047 = static_cast<BTextParameter &>(*parameter); 1048 return new TextControl(text.Name(), text.Name(), text); 1049 } 1050 1051 default: 1052 ERROR("BMediaTheme: Don't know parameter type: 0x%x\n", 1053 parameter->Type()); 1054 } 1055 return NULL; 1056 } 1057 1058