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
parameter_should_be_hidden(BParameter & parameter)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
start_watching_for_parameter_changes(BControl * control,BParameter & parameter)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
stop_watching_for_parameter_changes(BControl * control,BParameter & parameter)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
SeparatorView(orientation orientation)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
~SeparatorView()242 SeparatorView::~SeparatorView()
243 {
244 }
245
246
247 void
Draw(BRect updateRect)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
TitleView(const char * title)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
~TitleView()278 TitleView::~TitleView()
279 {
280 }
281
282
283 void
Draw(BRect updateRect)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
GetPreferredSize(float * _width,float * _height)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
CheckBox(const char * name,const char * label,BDiscreteParameter & parameter)318 CheckBox::CheckBox(const char* name, const char* label,
319 BDiscreteParameter ¶meter)
320 : BCheckBox(name, label, NULL),
321 fParameter(parameter)
322 {
323 }
324
325
~CheckBox()326 CheckBox::~CheckBox()
327 {
328 }
329
330
331 void
AttachedToWindow()332 CheckBox::AttachedToWindow()
333 {
334 BCheckBox::AttachedToWindow();
335
336 SetTarget(this);
337 start_watching_for_parameter_changes(this, fParameter);
338 }
339
340
341 void
DetachedFromWindow()342 CheckBox::DetachedFromWindow()
343 {
344 stop_watching_for_parameter_changes(this, fParameter);
345 }
346
347
OptionPopUp(const char * name,const char * label,BDiscreteParameter & parameter)348 OptionPopUp::OptionPopUp(const char* name, const char* label,
349 BDiscreteParameter ¶meter)
350 : BOptionPopUp(name, label, NULL),
351 fParameter(parameter)
352 {
353 }
354
355
~OptionPopUp()356 OptionPopUp::~OptionPopUp()
357 {
358 }
359
360
361 void
AttachedToWindow()362 OptionPopUp::AttachedToWindow()
363 {
364 BOptionPopUp::AttachedToWindow();
365
366 SetTarget(this);
367 start_watching_for_parameter_changes(this, fParameter);
368 }
369
370
371 void
DetachedFromWindow()372 OptionPopUp::DetachedFromWindow()
373 {
374 stop_watching_for_parameter_changes(this, fParameter);
375 }
376
377
Slider(const char * name,const char * label,int32 minValue,int32 maxValue,BContinuousParameter & parameter)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
~Slider()386 Slider::~Slider()
387 {
388 }
389
390
391 void
AttachedToWindow()392 Slider::AttachedToWindow()
393 {
394 BSlider::AttachedToWindow();
395
396 SetTarget(this);
397 start_watching_for_parameter_changes(this, fParameter);
398 }
399
400
401 void
DetachedFromWindow()402 Slider::DetachedFromWindow()
403 {
404 stop_watching_for_parameter_changes(this, fParameter);
405 }
406
407
ChannelSlider(const char * name,const char * label,orientation orientation,int32 channels,BContinuousParameter & parameter)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
~ChannelSlider()416 ChannelSlider::~ChannelSlider()
417 {
418 }
419
420
421 void
AttachedToWindow()422 ChannelSlider::AttachedToWindow()
423 {
424 BChannelSlider::AttachedToWindow();
425
426 SetTarget(this);
427 start_watching_for_parameter_changes(this, fParameter);
428 }
429
430
431 void
DetachedFromWindow()432 ChannelSlider::DetachedFromWindow()
433 {
434 stop_watching_for_parameter_changes(this, fParameter);
435
436 BChannelSlider::DetachedFromWindow();
437 }
438
439
TextControl(const char * name,const char * label,BTextParameter & parameter)440 TextControl::TextControl(const char* name, const char* label,
441 BTextParameter ¶meter)
442 : BTextControl(name, label, "", NULL),
443 fParameter(parameter)
444 {
445 }
446
447
~TextControl()448 TextControl::~TextControl()
449 {
450 }
451
452
453 void
AttachedToWindow()454 TextControl::AttachedToWindow()
455 {
456 BTextControl::AttachedToWindow();
457
458 SetTarget(this);
459 start_watching_for_parameter_changes(this, fParameter);
460 }
461
462
463 void
DetachedFromWindow()464 TextControl::DetachedFromWindow()
465 {
466 stop_watching_for_parameter_changes(this, fParameter);
467 }
468
469
470 // #pragma mark -
471
472
MessageFilter()473 MessageFilter::MessageFilter()
474 : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE)
475 {
476 }
477
478
479 MessageFilter *
FilterFor(BView * view,BParameter & parameter)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
ContinuousMessageFilter(BControl * control,BContinuousParameter & parameter)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
~ContinuousMessageFilter()530 ContinuousMessageFilter::~ContinuousMessageFilter()
531 {
532 }
533
534
535 filter_result
Filter(BMessage * message,BHandler ** target)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
_UpdateControl()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
DiscreteMessageFilter(BControl * control,BDiscreteParameter & parameter)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
~DiscreteMessageFilter()642 DiscreteMessageFilter::~DiscreteMessageFilter()
643 {
644 }
645
646
647 filter_result
Filter(BMessage * message,BHandler ** target)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
TextMessageFilter(BControl * control,BTextParameter & parameter)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
~TextMessageFilter()740 TextMessageFilter::~TextMessageFilter()
741 {
742 }
743
744
745 filter_result
Filter(BMessage * message,BHandler ** target)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
DefaultMediaTheme()806 DefaultMediaTheme::DefaultMediaTheme()
807 : BMediaTheme("Haiku theme", "Haiku built-in theme version 0.1")
808 {
809 CALLED();
810 }
811
812
813 BControl *
MakeControlFor(BParameter * parameter)814 DefaultMediaTheme::MakeControlFor(BParameter *parameter)
815 {
816 CALLED();
817
818 return MakeViewFor(parameter);
819 }
820
821
822 BView *
MakeViewFor(BParameterWeb * web,const BRect * hintRect)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 *
MakeViewFor(BParameterGroup & group)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 *
MakeSelfHostingViewFor(BParameter & parameter)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 *
MakeViewFor(BParameter * parameter)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