2 * Copyright 2003-2009, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
7 #include "DefaultMediaTheme.h"
11 #include <ChannelSlider.h>
13 #include <MediaRoster.h>
14 #include <MenuField.h>
15 #include <MessageFilter.h>
16 #include <OptionPopUp.h>
17 #include <ParameterWeb.h>
18 #include <ScrollBar.h>
20 #include <StringView.h>
22 #include <TextControl.h>
28 using namespace BPrivate
;
33 class DynamicScrollView
: public BView
{
35 DynamicScrollView(const char *name
, BView
*target
);
36 virtual ~DynamicScrollView();
38 virtual void AttachedToWindow(void);
39 virtual void FrameResized(float width
, float height
);
40 virtual void FrameMoved(BPoint newPosition
);
41 virtual void GetPreferredSize(float *_width
, float *_height
);
43 void SetContentBounds(BRect bounds
);
44 BRect
ContentBounds() const { return fContentBounds
; }
49 BScrollBar
*fHorizontalScrollBar
, *fVerticalScrollBar
;
52 bool fIsDocumentScroller
;
55 class GroupView
: public BView
{
57 GroupView(BRect frame
, const char *name
);
60 virtual void AttachedToWindow();
61 virtual void AllAttached();
62 virtual void GetPreferredSize(float *_width
, float *_height
);
64 virtual BSize
MinSize();
65 virtual BSize
MaxSize();
66 virtual BSize
PreferredSize();
68 void SetContentBounds(BRect bounds
);
69 BRect
ContentBounds() const { return fContentBounds
; }
75 class TabView
: public BTabView
{
77 TabView(BRect frame
, const char *name
, button_width width
= B_WIDTH_FROM_LABEL
,
78 uint32 resizingMode
= B_FOLLOW_ALL
, uint32 flags
= B_FULL_UPDATE_ON_RESIZE
79 | B_WILL_DRAW
| B_NAVIGABLE_JUMP
| B_FRAME_EVENTS
| B_NAVIGABLE
);
81 virtual void FrameResized(float width
, float height
);
82 virtual void Select(int32 tab
);
85 class SeparatorView
: public BView
{
87 SeparatorView(BRect frame
);
88 virtual ~SeparatorView();
90 virtual void Draw(BRect updateRect
);
96 class TitleView
: public BView
{
98 TitleView(BRect frame
, const char *title
);
101 virtual void Draw(BRect updateRect
);
102 virtual void GetPreferredSize(float *width
, float *height
);
108 class CheckBox
: public BCheckBox
{
110 CheckBox(BRect area
, const char* name
, const char* label
,
111 BDiscreteParameter
¶meter
);
114 virtual void AttachedToWindow();
115 virtual void DetachedFromWindow();
117 BDiscreteParameter
&fParameter
;
120 class OptionPopUp
: public BOptionPopUp
{
122 OptionPopUp(BRect area
, const char* name
, const char* label
,
123 BDiscreteParameter
¶meter
);
124 virtual ~OptionPopUp();
126 virtual void AttachedToWindow();
127 virtual void DetachedFromWindow();
129 BDiscreteParameter
&fParameter
;
132 class Slider
: public BSlider
{
134 Slider(BRect area
, const char* name
, const char*label
, int32 minValue
,
135 int32 maxValue
, BContinuousParameter
¶meter
);
138 virtual void AttachedToWindow();
139 virtual void DetachedFromWindow();
141 BContinuousParameter
&fParameter
;
144 class ChannelSlider
: public BChannelSlider
{
146 ChannelSlider(BRect area
, const char* name
, const char* label
,
147 orientation orientation
, int32 channels
,
148 BContinuousParameter
¶meter
);
149 virtual ~ChannelSlider();
151 virtual void AttachedToWindow();
152 virtual void DetachedFromWindow();
154 BContinuousParameter
&fParameter
;
157 class MessageFilter
: public BMessageFilter
{
159 static MessageFilter
*FilterFor(BView
*view
, BParameter
¶meter
);
165 class ContinuousMessageFilter
: public MessageFilter
{
167 ContinuousMessageFilter(BControl
*control
,
168 BContinuousParameter
¶meter
);
169 virtual ~ContinuousMessageFilter();
171 virtual filter_result
Filter(BMessage
*message
, BHandler
**target
);
174 void _UpdateControl();
177 BContinuousParameter
&fParameter
;
180 class DiscreteMessageFilter
: public MessageFilter
{
182 DiscreteMessageFilter(BControl
*control
, BDiscreteParameter
¶meter
);
183 virtual ~DiscreteMessageFilter();
185 virtual filter_result
Filter(BMessage
*message
, BHandler
**target
);
188 BDiscreteParameter
&fParameter
;
191 } // namespace BPrivate
194 const uint32 kMsgParameterChanged
= '_mPC';
198 parameter_should_be_hidden(BParameter
¶meter
)
200 // ToDo: note, this is probably completely stupid, but it's the only
201 // way I could safely remove the null parameters that are not shown
202 // by the R5 media theme
203 if (parameter
.Type() != BParameter::B_NULL_PARAMETER
204 || strcmp(parameter
.Kind(), B_WEB_PHYSICAL_INPUT
))
207 for (int32 i
= 0; i
< parameter
.CountOutputs(); i
++) {
208 if (!strcmp(parameter
.OutputAt(0)->Kind(), B_INPUT_MUX
))
217 start_watching_for_parameter_changes(BControl
* control
, BParameter
¶meter
)
219 BMediaRoster
* roster
= BMediaRoster::CurrentRoster();
220 if (roster
!= NULL
) {
221 roster
->StartWatching(control
, parameter
.Web()->Node(),
222 B_MEDIA_NEW_PARAMETER_VALUE
);
228 stop_watching_for_parameter_changes(BControl
* control
, BParameter
¶meter
)
230 BMediaRoster
* roster
= BMediaRoster::CurrentRoster();
231 if (roster
!= NULL
) {
232 roster
->StopWatching(control
, parameter
.Web()->Node(),
233 B_MEDIA_NEW_PARAMETER_VALUE
);
240 DynamicScrollView::DynamicScrollView(const char *name
, BView
*target
)
241 : BView(target
->Frame(), name
, B_FOLLOW_ALL
, B_WILL_DRAW
| B_FRAME_EVENTS
),
242 fHorizontalScrollBar(NULL
),
243 fVerticalScrollBar(NULL
),
245 fIsDocumentScroller(false)
247 fContentBounds
.Set(-1, -1, -1, -1);
248 AdoptViewColors(fTarget
);
249 target
->MoveTo(B_ORIGIN
);
254 DynamicScrollView::~DynamicScrollView()
260 DynamicScrollView::AttachedToWindow(void)
262 BRect frame
= ConvertToScreen(Bounds());
263 BRect windowFrame
= Window()->Frame();
265 fIsDocumentScroller
= Parent() == NULL
267 && Window()->Look() == B_DOCUMENT_WINDOW_LOOK
268 && frame
.right
== windowFrame
.right
269 && frame
.bottom
== windowFrame
.bottom
;
276 DynamicScrollView::FrameResized(float width
, float height
)
283 DynamicScrollView::FrameMoved(BPoint newPosition
)
290 DynamicScrollView::GetPreferredSize(float *_width
, float *_height
)
293 if (fVerticalScrollBar
)
294 width
+= B_V_SCROLL_BAR_WIDTH
;
296 if (fHorizontalScrollBar
)
297 height
+= B_H_SCROLL_BAR_HEIGHT
;
306 DynamicScrollView::SetContentBounds(BRect bounds
)
308 fContentBounds
= bounds
;
315 DynamicScrollView::UpdateBars()
317 // we need the size that the view wants to have, and the one
318 // it could have (without the space for the scroll bars)
321 if (fContentBounds
== BRect(-1, -1, -1, -1))
322 fTarget
->GetPreferredSize(&width
, &height
);
324 width
= fContentBounds
.Width();
325 height
= fContentBounds
.Height();
328 BRect bounds
= Bounds();
330 // do we have to remove a scroll bar?
332 bool horizontal
= width
> bounds
.Width();
333 bool vertical
= height
> bounds
.Height();
335 if (!horizontal
&& fHorizontalScrollBar
!= NULL
) {
336 RemoveChild(fHorizontalScrollBar
);
337 delete fHorizontalScrollBar
;
338 fHorizontalScrollBar
= NULL
;
341 if (!vertical
&& fVerticalScrollBar
!= NULL
) {
342 RemoveChild(fVerticalScrollBar
);
343 delete fVerticalScrollBar
;
344 fVerticalScrollBar
= NULL
;
347 // or do we have to add a scroll bar?
349 if (horizontal
&& fHorizontalScrollBar
== NULL
) {
350 BRect rect
= Bounds();
351 rect
.top
= rect
.bottom
+ 1 - B_H_SCROLL_BAR_HEIGHT
;
352 if (vertical
|| fIsDocumentScroller
)
353 rect
.right
-= B_V_SCROLL_BAR_WIDTH
;
355 fHorizontalScrollBar
= new BScrollBar(rect
, "horizontal", fTarget
, 0,
356 width
, B_HORIZONTAL
);
357 AddChild(fHorizontalScrollBar
);
360 if (vertical
&& fVerticalScrollBar
== NULL
) {
361 BRect rect
= Bounds();
362 rect
.left
= rect
.right
+ 1 - B_V_SCROLL_BAR_WIDTH
;
363 if (horizontal
|| fIsDocumentScroller
)
364 rect
.bottom
-= B_H_SCROLL_BAR_HEIGHT
;
366 fVerticalScrollBar
= new BScrollBar(rect
, "vertical", fTarget
, 0,
368 AddChild(fVerticalScrollBar
);
371 // update the scroll bar range & proportions and layout views
374 if (fHorizontalScrollBar
!= NULL
)
375 bounds
.bottom
-= B_H_SCROLL_BAR_HEIGHT
+ 1;
376 if (fVerticalScrollBar
!= NULL
)
377 bounds
.right
-= B_V_SCROLL_BAR_WIDTH
+ 1;
379 fTarget
->MoveTo(bounds
.LeftTop());
380 fTarget
->ResizeTo(bounds
.Width(), bounds
.Height());
382 if (fHorizontalScrollBar
!= NULL
) {
383 float delta
= width
- bounds
.Width();
387 fHorizontalScrollBar
->SetRange(0, delta
);
388 fHorizontalScrollBar
->SetSteps(1, bounds
.Width());
389 fHorizontalScrollBar
->SetProportion(bounds
.Width() / width
);
391 float barWidth
= Bounds().Width();
393 // scrollbars overlap one pixel of the frame
396 if (vertical
|| fIsDocumentScroller
)
397 barWidth
-= B_V_SCROLL_BAR_WIDTH
+ 1;
399 fHorizontalScrollBar
->MoveTo(bounds
.left
, bounds
.bottom
+ 1);
400 fHorizontalScrollBar
->ResizeTo(barWidth
, B_H_SCROLL_BAR_HEIGHT
);
402 if (fVerticalScrollBar
!= NULL
) {
403 float delta
= height
- bounds
.Height();
407 fVerticalScrollBar
->SetRange(0, delta
);
408 fVerticalScrollBar
->SetSteps(1, bounds
.Height());
409 fVerticalScrollBar
->SetProportion(bounds
.Height() / height
);
411 float barHeight
= Bounds().Height();
413 // scrollbars overlap one pixel of the frame
416 if (horizontal
|| fIsDocumentScroller
)
417 barHeight
-= B_H_SCROLL_BAR_HEIGHT
+ 1;
419 fVerticalScrollBar
->MoveTo(bounds
.right
+ 1, bounds
.top
);
420 fVerticalScrollBar
->ResizeTo(B_V_SCROLL_BAR_WIDTH
, barHeight
);
428 GroupView::GroupView(BRect frame
, const char *name
)
429 : BView(frame
, name
, B_FOLLOW_NONE
, B_WILL_DRAW
)
431 SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
435 GroupView::~GroupView()
441 GroupView::AttachedToWindow()
443 for (int32 i
= CountChildren(); i
-- > 0;) {
444 BControl
*control
= dynamic_cast<BControl
*>(ChildAt(i
));
448 control
->SetTarget(control
);
454 GroupView::AllAttached()
460 GroupView::GetPreferredSize(float *_width
, float *_height
)
463 *_width
= fContentBounds
.Width();
466 *_height
= fContentBounds
.Height();
473 return BSize(100, 100);
478 GroupView::PreferredSize()
488 GetPreferredSize(&max
.width
, &max
.height
);
494 GroupView::SetContentBounds(BRect bounds
)
496 fContentBounds
= bounds
;
503 /** BTabView is really stupid - it doesn't even resize its content
504 * view when it is resized itself.
505 * This derived class fixes this issue, and also resizes all tab
506 * content views to the size of the container view when they are
507 * selected (does not take their resize flags into account, though).
510 TabView::TabView(BRect frame
, const char *name
, button_width width
,
511 uint32 resizingMode
, uint32 flags
)
512 : BTabView(frame
, name
, width
, resizingMode
, flags
)
518 TabView::FrameResized(float width
, float height
)
520 BRect rect
= Bounds();
521 rect
.top
+= TabHeight();
522 rect
.InsetBy(3.0f
, 3.0f
);
523 //ContainerView is inseted by 3.0 in BTabView::_InitObject()
525 ContainerView()->ResizeTo(rect
.Width(), rect
.Height());
530 TabView::Select(int32 tab
)
532 BTabView::Select(tab
);
534 BView
*view
= ViewForTab(Selection());
536 BRect rect
= ContainerView()->Bounds();
537 view
->ResizeTo(rect
.Width(), rect
.Height());
545 SeparatorView::SeparatorView(BRect frame
)
546 : BView(frame
, "-", B_FOLLOW_NONE
, B_WILL_DRAW
)
548 fVertical
= frame
.Width() < frame
.Height();
549 SetViewColor(B_TRANSPARENT_COLOR
);
553 SeparatorView::~SeparatorView()
559 SeparatorView::Draw(BRect updateRect
)
561 rgb_color color
= ui_color(B_PANEL_BACKGROUND_COLOR
);
562 BRect rect
= updateRect
& Bounds();
564 SetHighColor(tint_color(color
, B_DARKEN_1_TINT
));
566 StrokeLine(BPoint(0, rect
.top
), BPoint(0, rect
.bottom
));
568 StrokeLine(BPoint(rect
.left
, 0), BPoint(rect
.right
, 0));
570 SetHighColor(tint_color(color
, B_LIGHTEN_1_TINT
));
572 StrokeLine(BPoint(1, rect
.top
), BPoint(1, rect
.bottom
));
574 StrokeLine(BPoint(rect
.left
, 1), BPoint(rect
.right
, 1));
581 TitleView::TitleView(BRect frame
, const char *title
)
582 : BView(frame
, title
, B_FOLLOW_LEFT_RIGHT
, B_WILL_DRAW
)
584 fTitle
= strdup(title
);
589 TitleView::~TitleView()
591 free((char *)fTitle
);
596 TitleView::Draw(BRect updateRect
)
598 BRect
rect(Bounds());
600 SetDrawingMode(B_OP_COPY
);
601 SetHighColor(tint_color(ViewColor(), B_LIGHTEN_2_TINT
));
602 DrawString(fTitle
, BPoint(rect
.left
+ 1, rect
.bottom
- 8));
604 SetDrawingMode(B_OP_OVER
);
605 SetHighColor(80, 20, 20);
606 DrawString(fTitle
, BPoint(rect
.left
, rect
.bottom
- 9));
611 TitleView::GetPreferredSize(float *_width
, float *_height
)
614 *_width
= StringWidth(fTitle
) + 2;
617 font_height fontHeight
;
618 GetFontHeight(&fontHeight
);
620 *_height
= fontHeight
.ascent
+ fontHeight
.descent
+ fontHeight
.leading
629 CheckBox::CheckBox(BRect area
, const char* name
, const char* label
,
630 BDiscreteParameter
¶meter
)
631 : BCheckBox(area
, name
, label
, NULL
),
632 fParameter(parameter
)
637 CheckBox::~CheckBox()
643 CheckBox::AttachedToWindow()
645 start_watching_for_parameter_changes(this, fParameter
);
650 CheckBox::DetachedFromWindow()
652 stop_watching_for_parameter_changes(this, fParameter
);
656 OptionPopUp::OptionPopUp(BRect area
, const char* name
, const char* label
,
657 BDiscreteParameter
¶meter
)
658 : BOptionPopUp(area
, name
, label
, NULL
),
659 fParameter(parameter
)
664 OptionPopUp::~OptionPopUp()
670 OptionPopUp::AttachedToWindow()
672 start_watching_for_parameter_changes(this, fParameter
);
677 OptionPopUp::DetachedFromWindow()
679 stop_watching_for_parameter_changes(this, fParameter
);
683 Slider::Slider(BRect area
, const char* name
, const char* label
, int32 minValue
,
684 int32 maxValue
, BContinuousParameter
¶meter
)
685 : BSlider(area
, name
, label
, NULL
, minValue
, maxValue
),
686 fParameter(parameter
)
697 Slider::AttachedToWindow()
699 start_watching_for_parameter_changes(this, fParameter
);
704 Slider::DetachedFromWindow()
706 stop_watching_for_parameter_changes(this, fParameter
);
710 ChannelSlider::ChannelSlider(BRect area
, const char* name
, const char* label
,
711 orientation orientation
, int32 channels
, BContinuousParameter
¶meter
)
712 : BChannelSlider(area
, name
, label
, NULL
, orientation
, channels
),
713 fParameter(parameter
)
718 ChannelSlider::~ChannelSlider()
724 ChannelSlider::AttachedToWindow()
726 start_watching_for_parameter_changes(this, fParameter
);
731 ChannelSlider::DetachedFromWindow()
733 stop_watching_for_parameter_changes(this, fParameter
);
740 MessageFilter::MessageFilter()
741 : BMessageFilter(B_ANY_DELIVERY
, B_ANY_SOURCE
)
747 MessageFilter::FilterFor(BView
*view
, BParameter
¶meter
)
749 BControl
*control
= dynamic_cast<BControl
*>(view
);
753 switch (parameter
.Type()) {
754 case BParameter::B_CONTINUOUS_PARAMETER
:
755 return new ContinuousMessageFilter(control
,
756 static_cast<BContinuousParameter
&>(parameter
));
758 case BParameter::B_DISCRETE_PARAMETER
:
759 return new DiscreteMessageFilter(control
,
760 static_cast<BDiscreteParameter
&>(parameter
));
762 case BParameter::B_NULL_PARAMETER
: /* fall through */
772 ContinuousMessageFilter::ContinuousMessageFilter(BControl
*control
,
773 BContinuousParameter
¶meter
)
776 fParameter(parameter
)
778 // initialize view for us
779 control
->SetMessage(new BMessage(kMsgParameterChanged
));
781 if (BSlider
*slider
= dynamic_cast<BSlider
*>(fControl
))
782 slider
->SetModificationMessage(new BMessage(kMsgParameterChanged
));
783 else if (BChannelSlider
*slider
= dynamic_cast<BChannelSlider
*>(fControl
))
784 slider
->SetModificationMessage(new BMessage(kMsgParameterChanged
));
786 ERROR("ContinuousMessageFilter: unknown continuous parameter view\n");
793 ContinuousMessageFilter::~ContinuousMessageFilter()
799 ContinuousMessageFilter::Filter(BMessage
*message
, BHandler
**target
)
801 if (*target
!= fControl
)
802 return B_DISPATCH_MESSAGE
;
804 if (message
->what
== kMsgParameterChanged
) {
805 // update parameter from control
806 // TODO: support for response!
808 float value
[fParameter
.CountChannels()];
810 if (BSlider
*slider
= dynamic_cast<BSlider
*>(fControl
)) {
811 value
[0] = (float)(slider
->Value() / 1000.0);
812 } else if (BChannelSlider
*slider
813 = dynamic_cast<BChannelSlider
*>(fControl
)) {
814 for (int32 i
= 0; i
< fParameter
.CountChannels(); i
++)
815 value
[i
] = (float)(slider
->ValueFor(i
) / 1000.0);
818 TRACE("ContinuousMessageFilter::Filter: update view %s, %" B_PRId32
819 " channels\n", fControl
->Name(), fParameter
.CountChannels());
821 if (fParameter
.SetValue((void *)value
, sizeof(value
),
823 ERROR("ContinuousMessageFilter::Filter: Could not set parameter "
824 "value for %p\n", &fParameter
);
825 return B_DISPATCH_MESSAGE
;
827 return B_SKIP_MESSAGE
;
829 if (message
->what
== B_MEDIA_NEW_PARAMETER_VALUE
) {
830 // update view from parameter -- if the message concerns us
831 const media_node
* node
;
834 if (message
->FindInt32("parameter", ¶meterID
) != B_OK
835 || fParameter
.ID() != parameterID
836 || message
->FindData("node", B_RAW_TYPE
, (const void**)&node
,
838 || fParameter
.Web()->Node() != *node
)
839 return B_DISPATCH_MESSAGE
;
842 return B_SKIP_MESSAGE
;
845 return B_DISPATCH_MESSAGE
;
850 ContinuousMessageFilter::_UpdateControl()
852 // TODO: response support!
854 float value
[fParameter
.CountChannels()];
855 size_t size
= sizeof(value
);
856 if (fParameter
.GetValue((void *)&value
, &size
, NULL
) < B_OK
) {
857 ERROR("ContinuousMessageFilter: Could not get value for continuous "
858 "parameter %p (name '%s', node %d)\n", &fParameter
,
859 fParameter
.Name(), (int)fParameter
.Web()->Node().node
);
863 if (BSlider
*slider
= dynamic_cast<BSlider
*>(fControl
)) {
864 slider
->SetValue((int32
) (1000 * value
[0]));
865 slider
->SetModificationMessage(new BMessage(kMsgParameterChanged
));
866 } else if (BChannelSlider
*slider
867 = dynamic_cast<BChannelSlider
*>(fControl
)) {
868 for (int32 i
= 0; i
< fParameter
.CountChannels(); i
++) {
869 slider
->SetValueFor(i
, (int32
) (1000 * value
[i
]));
878 DiscreteMessageFilter::DiscreteMessageFilter(BControl
*control
,
879 BDiscreteParameter
¶meter
)
881 fParameter(parameter
)
883 // initialize view for us
884 control
->SetMessage(new BMessage(kMsgParameterChanged
));
887 size_t size
= sizeof(int32
);
889 if (parameter
.GetValue((void *)&value
, &size
, NULL
) < B_OK
) {
890 ERROR("DiscreteMessageFilter: Could not get value for discrete "
891 "parameter %p (name '%s', node %d)\n", ¶meter
,
892 parameter
.Name(), (int)(parameter
.Web()->Node().node
));
896 if (BCheckBox
*checkBox
= dynamic_cast<BCheckBox
*>(control
)) {
897 checkBox
->SetValue(value
);
898 } else if (BOptionPopUp
*popUp
= dynamic_cast<BOptionPopUp
*>(control
)) {
899 popUp
->SelectOptionFor(value
);
901 ERROR("DiscreteMessageFilter: unknown discrete parameter view\n");
905 DiscreteMessageFilter::~DiscreteMessageFilter()
911 DiscreteMessageFilter::Filter(BMessage
*message
, BHandler
**target
)
915 if ((control
= dynamic_cast<BControl
*>(*target
)) == NULL
)
916 return B_DISPATCH_MESSAGE
;
918 if (message
->what
== B_MEDIA_NEW_PARAMETER_VALUE
) {
919 TRACE("DiscreteMessageFilter::Filter: Got a new parameter value\n");
920 const media_node
* node
;
923 if (message
->FindInt32("parameter", ¶meterID
) != B_OK
924 || fParameter
.ID() != parameterID
925 || message
->FindData("node", B_RAW_TYPE
, (const void**)&node
,
927 || fParameter
.Web()->Node() != *node
)
928 return B_DISPATCH_MESSAGE
;
931 size_t valueSize
= sizeof(int32
);
932 if (fParameter
.GetValue((void*)&value
, &valueSize
, NULL
) < B_OK
) {
933 ERROR("DiscreteMessageFilter: Could not get value for continuous "
934 "parameter %p (name '%s', node %d)\n", &fParameter
,
935 fParameter
.Name(), (int)fParameter
.Web()->Node().node
);
936 return B_SKIP_MESSAGE
;
938 if (BCheckBox
* checkBox
= dynamic_cast<BCheckBox
*>(control
)) {
939 checkBox
->SetValue(value
);
940 } else if (BOptionPopUp
* popUp
= dynamic_cast<BOptionPopUp
*>(control
)) {
941 popUp
->SetValue(value
);
944 return B_SKIP_MESSAGE
;
947 if (message
->what
!= kMsgParameterChanged
)
948 return B_DISPATCH_MESSAGE
;
954 if (BCheckBox
*checkBox
= dynamic_cast<BCheckBox
*>(control
)) {
955 value
= checkBox
->Value();
956 } else if (BOptionPopUp
*popUp
= dynamic_cast<BOptionPopUp
*>(control
)) {
957 popUp
->SelectedOption(NULL
, &value
);
960 TRACE("DiscreteMessageFilter::Filter: update view %s, value = %"
961 B_PRId32
"\n", control
->Name(), value
);
963 if (fParameter
.SetValue((void *)&value
, sizeof(value
), -1) < B_OK
) {
964 ERROR("DiscreteMessageFilter::Filter: Could not set parameter value for %p\n", &fParameter
);
965 return B_DISPATCH_MESSAGE
;
968 return B_SKIP_MESSAGE
;
975 DefaultMediaTheme::DefaultMediaTheme()
976 : BMediaTheme("Haiku theme", "Haiku built-in theme version 0.1")
983 DefaultMediaTheme::MakeControlFor(BParameter
*parameter
)
987 BRect
rect(0, 0, 150, 100);
988 return MakeViewFor(parameter
, &rect
);
993 DefaultMediaTheme::MakeViewFor(BParameterWeb
*web
, const BRect
*hintRect
)
1006 // do we have more than one attached parameter group?
1007 // if so, use a tabbed view with a tab for each group
1009 TabView
*tabView
= NULL
;
1011 if (web
->CountGroups() > 1)
1012 tabView
= new TabView(rect
, "web");
1014 rect
.OffsetTo(B_ORIGIN
);
1016 for (int32 i
= 0; i
< web
->CountGroups(); i
++) {
1017 BParameterGroup
*group
= web
->GroupAt(i
);
1021 BView
*groupView
= MakeViewFor(*group
, hintRect
? &rect
: NULL
);
1022 if (groupView
== NULL
)
1025 if (GroupView
*view
= dynamic_cast<GroupView
*>(groupView
)) {
1026 // the top-level group views must not be larger than their hintRect,
1027 // but unlike their children, they should follow all sides when
1028 // their parent is resized
1029 if (hintRect
!= NULL
)
1030 view
->ResizeTo(rect
.Width() - 10, rect
.Height() - 10);
1031 view
->SetResizingMode(B_FOLLOW_ALL
);
1034 if (tabView
== NULL
) {
1035 // if we don't need a container to put that view into,
1036 // we're done here (but the groupView may span over the
1038 if (groupView
->Frame().LeftTop() == BPoint(5, 5)) {
1039 // remove insets, as they are not needed
1040 groupView
->MoveBy(-5, -5);
1041 groupView
->ResizeBy(10, 10);
1044 return new DynamicScrollView(groupView
->Name(), groupView
);
1047 DynamicScrollView
*scrollView
= new DynamicScrollView(groupView
->Name(), groupView
);
1048 tabView
->AddTab(scrollView
);
1051 bestRect
= bestRect
| scrollView
->Bounds();
1055 if (tabView
!= NULL
) {
1056 // this adjustment must be kept in sync with TabView::FrameResized
1057 bestRect
.bottom
+= tabView
->TabHeight();
1058 bestRect
.InsetBy(-3.0,-3.0);
1060 tabView
->ResizeTo(bestRect
.Width(), bestRect
.Height());
1061 tabView
->FrameResized(bestRect
.Width(), bestRect
.Height());
1062 //needed since we're not attached to a window yet
1070 DefaultMediaTheme::MakeViewFor(BParameterGroup
& group
, const BRect
* hintRect
)
1074 if (group
.Flags() & B_HIDDEN_PARAMETER
)
1078 if (hintRect
!= NULL
)
1081 GroupView
*view
= new GroupView(rect
, group
.Name());
1083 // Create the parameter views - but don't add them yet
1085 rect
.OffsetTo(B_ORIGIN
);
1086 rect
.InsetBySelf(5, 5);
1089 for (int32 i
= 0; i
< group
.CountParameters(); i
++) {
1090 BParameter
*parameter
= group
.ParameterAt(i
);
1091 if (parameter
== NULL
)
1094 BView
*parameterView
= MakeSelfHostingViewFor(*parameter
,
1095 hintRect
? &rect
: NULL
);
1096 if (parameterView
== NULL
)
1099 parameterView
->AdoptViewColors(view
);
1100 // ToDo: dunno why this is needed, but the controls
1101 // sometimes (!) have a white background without it
1103 views
.AddItem(parameterView
);
1106 // Identify a title view, and add it at the top if present
1108 TitleView
*titleView
= dynamic_cast<TitleView
*>((BView
*)views
.ItemAt(0));
1109 if (titleView
!= NULL
) {
1110 view
->AddChild(titleView
);
1111 rect
.OffsetBy(0, titleView
->Bounds().Height());
1114 // Add the sub-group views
1116 rect
.right
= rect
.left
+ 20;
1117 rect
.bottom
= rect
.top
+ 20;
1118 float lastHeight
= 0;
1120 for (int32 i
= 0; i
< group
.CountGroups(); i
++) {
1121 BParameterGroup
*subGroup
= group
.GroupAt(i
);
1122 if (subGroup
== NULL
)
1125 BView
*groupView
= MakeViewFor(*subGroup
, &rect
);
1126 if (groupView
== NULL
)
1130 // add separator view
1131 BRect
separatorRect(groupView
->Frame());
1132 separatorRect
.left
-= 3;
1133 separatorRect
.right
= separatorRect
.left
+ 1;
1134 if (lastHeight
> separatorRect
.Height())
1135 separatorRect
.bottom
= separatorRect
.top
+ lastHeight
;
1137 view
->AddChild(new SeparatorView(separatorRect
));
1140 view
->AddChild(groupView
);
1142 rect
.OffsetBy(groupView
->Bounds().Width() + 5, 0);
1144 lastHeight
= groupView
->Bounds().Height();
1145 if (lastHeight
> rect
.Height())
1146 rect
.bottom
= rect
.top
+ lastHeight
- 1;
1149 view
->ResizeTo(rect
.left
+ 10, rect
.bottom
+ 5);
1150 view
->SetContentBounds(view
->Bounds());
1152 if (group
.CountParameters() == 0)
1155 // add the parameter views part of the group
1157 if (group
.CountGroups() > 0) {
1158 rect
.top
= rect
.bottom
+ 10;
1159 rect
.bottom
= rect
.top
+ 20;
1162 bool center
= false;
1164 for (int32 i
= 0; i
< views
.CountItems(); i
++) {
1165 BView
*parameterView
= static_cast<BView
*>(views
.ItemAt(i
));
1167 if (parameterView
->Bounds().Width() + 5 > rect
.Width())
1168 rect
.right
= parameterView
->Bounds().Width() + rect
.left
+ 5;
1170 // we don't need to add the title view again
1171 if (parameterView
== titleView
)
1174 // if there is a BChannelSlider (ToDo: or any vertical slider?)
1175 // the views will be centered
1176 if (dynamic_cast<BChannelSlider
*>(parameterView
) != NULL
)
1179 parameterView
->MoveTo(parameterView
->Frame().left
, rect
.top
);
1180 view
->AddChild(parameterView
);
1182 rect
.OffsetBy(0, parameterView
->Bounds().Height() + 5);
1185 if (views
.CountItems() > (titleView
!= NULL
? 1 : 0))
1186 view
->ResizeTo(rect
.right
+ 5, rect
.top
+ 5);
1188 // center the parameter views if needed, and tweak some views
1190 float width
= view
->Bounds().Width();
1192 for (int32 i
= 0; i
< views
.CountItems(); i
++) {
1193 BView
*subView
= static_cast<BView
*>(views
.ItemAt(i
));
1194 BRect frame
= subView
->Frame();
1197 subView
->MoveTo((width
- frame
.Width()) / 2, frame
.top
);
1199 // tweak the PopUp views to look better
1200 if (dynamic_cast<BOptionPopUp
*>(subView
) != NULL
)
1201 subView
->ResizeTo(width
, frame
.Height());
1205 view
->SetContentBounds(view
->Bounds());
1210 /*! This creates a view that handles all incoming messages itself - that's
1211 what is meant with self-hosting.
1214 DefaultMediaTheme::MakeSelfHostingViewFor(BParameter
& parameter
,
1215 const BRect
* hintRect
)
1217 if (parameter
.Flags() & B_HIDDEN_PARAMETER
1218 || parameter_should_be_hidden(parameter
))
1221 BView
*view
= MakeViewFor(¶meter
, hintRect
);
1223 // The MakeViewFor() method above returns a BControl - which we
1224 // don't need for a null parameter; that's why it returns NULL.
1225 // But we want to see something anyway, so we add a string view
1227 if (parameter
.Type() == BParameter::B_NULL_PARAMETER
) {
1228 if (parameter
.Group()->ParameterAt(0) == ¶meter
) {
1229 // this is the first parameter in this group, so
1230 // let's use a nice title view
1232 TitleView
*titleView
= new TitleView(BRect(0, 0, 10, 10), parameter
.Name());
1233 titleView
->ResizeToPreferred();
1237 BStringView
*stringView
= new BStringView(BRect(0, 0, 10, 10),
1238 parameter
.Name(), parameter
.Name());
1239 stringView
->SetAlignment(B_ALIGN_CENTER
);
1240 stringView
->ResizeToPreferred();
1248 MessageFilter
*filter
= MessageFilter::FilterFor(view
, parameter
);
1250 view
->AddFilter(filter
);
1257 DefaultMediaTheme::MakeViewFor(BParameter
*parameter
, const BRect
*hintRect
)
1263 rect
.Set(0, 0, 50, 100);
1265 switch (parameter
->Type()) {
1266 case BParameter::B_NULL_PARAMETER
:
1267 // there is no default view for a null parameter
1270 case BParameter::B_DISCRETE_PARAMETER
:
1272 BDiscreteParameter
&discrete
= static_cast<BDiscreteParameter
&>(*parameter
);
1274 if (!strcmp(discrete
.Kind(), B_ENABLE
)
1275 || !strcmp(discrete
.Kind(), B_MUTE
)
1276 || discrete
.CountItems() == 0) {
1277 // create a checkbox item
1279 BCheckBox
*checkBox
= new CheckBox(rect
, discrete
.Name(),
1280 discrete
.Name(), discrete
);
1281 checkBox
->ResizeToPreferred();
1285 // create a pop up menu field
1287 // ToDo: replace BOptionPopUp (or fix it in Haiku...)
1288 // this is a workaround for a bug in BOptionPopUp - you need to
1289 // know the actual width before creating the object - very nice...
1293 for (int32 i
= 0; i
< discrete
.CountItems(); i
++) {
1294 float labelWidth
= font
.StringWidth(discrete
.ItemNameAt(i
));
1295 if (labelWidth
> width
)
1298 width
+= font
.StringWidth(discrete
.Name()) + 55;
1299 rect
.right
= rect
.left
+ width
;
1301 BOptionPopUp
*popUp
= new OptionPopUp(rect
, discrete
.Name(),
1302 discrete
.Name(), discrete
);
1304 for (int32 i
= 0; i
< discrete
.CountItems(); i
++) {
1305 popUp
->AddOption(discrete
.ItemNameAt(i
), discrete
.ItemValueAt(i
));
1308 popUp
->ResizeToPreferred();
1314 case BParameter::B_CONTINUOUS_PARAMETER
:
1316 BContinuousParameter
&continuous
= static_cast<BContinuousParameter
&>(*parameter
);
1318 if (!strcmp(continuous
.Kind(), B_MASTER_GAIN
)
1319 || !strcmp(continuous
.Kind(), B_GAIN
)) {
1320 BChannelSlider
*slider
= new ChannelSlider(rect
,
1321 continuous
.Name(), continuous
.Name(), B_VERTICAL
,
1322 continuous
.CountChannels(), continuous
);
1324 char minLabel
[64], maxLabel
[64];
1326 const char *unit
= continuous
.Unit();
1328 // if we have a unit, print it next to the limit values
1329 sprintf(minLabel
, "%g %s", continuous
.MinValue(), continuous
.Unit());
1330 sprintf(maxLabel
, "%g %s", continuous
.MaxValue(), continuous
.Unit());
1332 sprintf(minLabel
, "%g", continuous
.MinValue());
1333 sprintf(maxLabel
, "%g", continuous
.MaxValue());
1335 slider
->SetLimitLabels(minLabel
, maxLabel
);
1337 float width
, height
;
1338 slider
->GetPreferredSize(&width
, &height
);
1339 slider
->ResizeTo(width
, 190);
1341 // ToDo: take BContinuousParameter::GetResponse() & ValueStep() into account!
1343 for (int32 i
= 0; i
< continuous
.CountChannels(); i
++) {
1344 slider
->SetLimitsFor(i
, int32(continuous
.MinValue() * 1000),
1345 int32(continuous
.MaxValue() * 1000));
1351 BSlider
*slider
= new Slider(rect
, parameter
->Name(),
1352 parameter
->Name(), 0, 100, continuous
);
1354 float width
, height
;
1355 slider
->GetPreferredSize(&width
, &height
);
1356 slider
->ResizeTo(100, height
);
1362 ERROR("BMediaTheme: Don't know parameter type: 0x%x\n",