xref: /haiku/src/preferences/media/MediaViews.cpp (revision 4b3b81da9e459443d75329cfd08bc9a57ad02653)
1 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
2 //
3 //	Copyright (c) 2003, OpenBeOS
4 //
5 //  This software is part of the OpenBeOS distribution and is covered
6 //  by the OpenBeOS license.
7 //
8 //
9 //  File:        MediaViews.cpp
10 //  Author:      Sikosis, Jérôme Duval
11 //  Description: Media Preferences
12 //  Created :    June 25, 2003
13 //
14 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
15 
16 
17 // Includes -------------------------------------------------------------------------------------------------- //
18 #include <Box.h>
19 #include <Button.h>
20 #include <MenuField.h>
21 #include <PopUpMenu.h>
22 #include <MediaRoster.h>
23 #include <Deskbar.h>
24 #include <Entry.h>
25 #include <stdio.h>
26 #include <MediaAddOn.h>
27 #include <String.h>
28 #include <TextView.h>
29 #include <GroupView.h>
30 #include <SpaceLayoutItem.h>
31 
32 #include "MediaViews.h"
33 
34 BarView::BarView(BRect frame)
35  : BView (frame, "barView", B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW ),
36  	fDisplay(true)
37 {
38 }
39 
40 void
41 BarView::Draw(BRect updateRect)
42 {
43 	BRect r = Bounds();
44 
45 	if (fDisplay) {
46 		// Display the 3D Look Divider Bar
47 		SetHighColor(140,140,140,0);
48 		StrokeLine(BPoint(r.left,r.top),BPoint(r.right,r.top));
49 		SetHighColor(255,255,255,0);
50 		StrokeLine(BPoint(r.left,r.bottom),BPoint(r.right,r.bottom));
51 	} else {
52 		SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
53 		StrokeLine(BPoint(r.left,r.top),BPoint(r.right,r.top));
54 		StrokeLine(BPoint(r.left,r.bottom),BPoint(r.right,r.bottom));
55 	}
56 }
57 
58 
59 SettingsView::SettingsView (BRect frame, bool isVideo)
60  : BView (frame, "SettingsView", B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW ),
61 	fIsVideo(isVideo)
62 {
63 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
64 
65 	BRect rect(frame);
66 	rect.left += 10;
67 	rect.top += 12;
68 	rect.right -=21;
69 	rect.bottom = rect.top + 104;
70 	BBox *defaultsBox = new BBox(rect, "defaults");
71 	defaultsBox->SetLabel(fIsVideo ? "Default Nodes" : "Defaults");
72 
73 	// create the default box
74 	BGroupLayout* defaultBoxLayout = new BGroupLayout(B_VERTICAL, 5);
75 	float inset = defaultsBox->Frame().left - defaultsBox->InnerFrame().left;
76 	defaultBoxLayout->SetInsets(inset, defaultsBox->TopBorderOffset() * 2, inset, inset);
77 	defaultsBox->SetLayout(defaultBoxLayout);
78 	defaultBoxLayout->AddItem(BSpaceLayoutItem::CreateVerticalStrut(5));
79 
80 	BGroupView* inputField = new BGroupView(B_HORIZONTAL);
81 	BGroupView* outputField = new BGroupView(B_HORIZONTAL);
82 	defaultsBox->GetLayout()->AddView(inputField);
83 	defaultsBox->GetLayout()->AddView(outputField);
84 
85 	BRect defaultRect(20, 22, 250, 40);
86 	float divider = StringWidth(fIsVideo ? "Video Output:" : "Audio Output:") + 5;
87 	fMenu1 = new BPopUpMenu("<none>");
88 	fMenu1->SetLabelFromMarked(true);
89 	BMenuField *menuField1 = new BMenuField(defaultRect, "menuField1",
90 		fIsVideo ? "Video Input:" : "Audio Input:", fMenu1);
91 	menuField1->SetDivider(divider);
92 
93 	defaultRect.OffsetBy(0, 26);
94 	fMenu2 = new BPopUpMenu("<none>");
95 	fMenu2->SetLabelFromMarked(true);
96 	BMenuField *menuField2 = new BMenuField(defaultRect, "menuField2",
97 		fIsVideo ? "Video Output:" : "Audio Output:", fMenu2);
98 	menuField2->SetDivider(divider);
99 
100 	inputField->GroupLayout()->AddView(menuField1);
101 	outputField->GroupLayout()->AddView(menuField2);
102 
103 	BMenuField *menuField3 = NULL;
104 	if (!fIsVideo) {
105 		defaultRect.OffsetBy(186, 0);
106 		defaultRect.right -= 30;
107 		fMenu3 = new BPopUpMenu("<none>");
108 		fMenu3->SetLabelFromMarked(true);
109 		menuField3 = new BMenuField(defaultRect, "menuField3",
110 			"Channel:", fMenu3);
111 		outputField->GroupLayout()->AddView(menuField3);
112 		menuField3->SetDivider(StringWidth("Channel:")+5);
113 		defaultRect.right += 30;
114 		defaultRect.OffsetBy(-186, 0);
115 	}
116 
117 	defaultRect.OffsetBy(0, 32);
118 	defaultRect.right += 100;
119 	rgb_color red_color = {222, 32, 33};
120 	fRestartView = new BStringView(defaultRect, "restartStringView", "Restart the Media Server to apply changes.",
121 		B_FOLLOW_ALL, B_WILL_DRAW);
122 	fRestartView->SetHighColor(red_color);
123 	defaultsBox->AddChild(fRestartView);
124 	fRestartView->Hide();
125 
126 	// create the realtime box
127 	rect.top = rect.bottom + 10;
128 	rect.bottom = rect.top + 162;
129 	BBox *realtimeBox = new BBox(rect, "realtime");
130 	realtimeBox->SetLabel("Real-Time");
131 
132 	BMessage *message = new BMessage(ML_ENABLE_REAL_TIME);
133 	message->AddBool("isVideo", fIsVideo);
134 	BRect rect2(22,20, frame.Width() - 22, 40);
135 	fRealtimeCheckBox = new BCheckBox(rect2, "realtimeCheckBox",
136 		fIsVideo ? "Enable Real-Time Video" : "Enable Real-Time Audio", message);
137 
138 	uint32 flags;
139 	BMediaRoster::Roster()->GetRealtimeFlags(&flags);
140 	if (flags & (fIsVideo ? B_MEDIA_REALTIME_VIDEO : B_MEDIA_REALTIME_AUDIO))
141 		fRealtimeCheckBox->SetValue(B_CONTROL_ON);
142 
143 	rect2.top += 26;
144 	rect2.bottom = rect.Height() - 5;
145 	BRect textRect(3, 3, rect2.Width() - 3, rect2.Height() - 3);
146 	BTextView *textView = new BTextView(rect2, "stringView", textRect, B_FOLLOW_ALL, B_WILL_DRAW);
147 	textView->Insert(fIsVideo ? "Enabling Real-Time Video allows the BeOS to perform video operations as fast and smoothly as possible.  It achieves optimum performance by using more RAM."
148 		"\n\nOnly enable this feature if you need the lowest latency possible."
149 		: "Enabling Real-time Audio allows BeOS to record and play audio as fast as possible.  It achieves this performance by using more CPU and RAM."
150 		"\n\nOnly enable this feature if you need the lowest latency possible.");
151 	textView->MakeEditable(false);
152 	textView->MakeSelectable(false);
153 	textView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
154 
155 	BGroupLayout* realtimeBoxLayout = new BGroupLayout(B_VERTICAL, 5);
156 	inset = realtimeBox->Frame().left - realtimeBox->InnerFrame().left;
157 	realtimeBoxLayout->SetInsets(inset, defaultsBox->TopBorderOffset() * 2, inset, inset);
158 	realtimeBox->SetLayout(realtimeBoxLayout);
159 
160 	realtimeBoxLayout->AddItem(BSpaceLayoutItem::CreateVerticalStrut(5));
161 	realtimeBoxLayout->AddView(fRealtimeCheckBox);
162 	realtimeBoxLayout->AddView(textView);
163 
164 	// create the bottom line: volumen in deskbar checkbox and restart button
165 	BGroupView* bottomView = new BGroupView(B_HORIZONTAL);
166 	rect.top = rect.bottom + 11;
167 	rect.bottom = rect.top + 20;
168 	rect.left = rect.right - StringWidth("Restart Media Services") - 20;
169 	BButton *restartButton = new BButton(rect, "restartButton",
170 		"Restart Media Services", new BMessage(ML_RESTART_MEDIA_SERVER));
171 
172 	if (!fIsVideo) {
173 		rect.right = rect.left - 10;
174 		rect.top += 4;
175 		rect.left = frame.left + 33;
176 		if (StringWidth("Show Volume Control on Deskbar") > rect.Width() - 30)
177 			rect.left -= 10;
178 		fVolumeCheckBox = new BCheckBox(rect, "volumeCheckBox",
179 			"Show Volume Control on Deskbar", new BMessage(ML_SHOW_VOLUME_CONTROL));
180 		bottomView->GroupLayout()->AddView(fVolumeCheckBox);
181 		if (BDeskbar().HasItem("MediaReplicant"))
182 			fVolumeCheckBox->SetValue(B_CONTROL_ON);
183 	}
184 	else{
185 		bottomView->GroupLayout()->AddItem(BSpaceLayoutItem::CreateGlue());
186 	}
187 	bottomView->GroupLayout()->AddView(restartButton);
188 
189 	// compose all stuff
190 	BGroupLayout* rootlayout = new BGroupLayout(B_VERTICAL, 5);
191 	SetLayout(rootlayout);
192 
193 	rootlayout->AddView(defaultsBox);
194 	rootlayout->AddView(realtimeBox);
195 	rootlayout->AddView(bottomView);
196 }
197 
198 void
199 SettingsView::AddNodes(BList &list, bool isInput)
200 {
201 	BMenu *menu = isInput ? fMenu1 : fMenu2;
202 	void *item;
203 	while ((item = menu->RemoveItem((int32)0)) != NULL)
204 		delete static_cast<dormant_node_info *>(item);
205 
206 	BMessage message(ML_DEFAULT_CHANGE);
207 	message.AddBool("isVideo", fIsVideo);
208 	message.AddBool("isInput", isInput);
209 
210 	for (int32 i = 0; i < list.CountItems(); i++) {
211 		dormant_node_info *info = static_cast<dormant_node_info *>(list.ItemAt(i));
212 		menu->AddItem(new SettingsItem(info, new BMessage(message)));
213 	}
214 }
215 
216 void
217 SettingsView::SetDefault(dormant_node_info &info, bool isInput, int32 outputID)
218 {
219 	BMenu *menu = isInput ? fMenu1 : fMenu2;
220 
221 	for (int32 i = 0; i < menu->CountItems(); i++) {
222 		SettingsItem *item = static_cast<SettingsItem *>(menu->ItemAt(i));
223 		if (item->fInfo && item->fInfo->addon == info.addon && item->fInfo->flavor_id == info.flavor_id) {
224 			item->SetMarked(true);
225 			break;
226 		}
227 	}
228 
229 	if (!fIsVideo&&!isInput&&outputID>-1) {
230 		BMenuItem *item;
231 		while ((item = fMenu3->RemoveItem((int32)0)) != NULL)
232 			delete item;
233 		BMediaRoster *roster = BMediaRoster::Roster();
234 		media_node node;
235 		media_node_id node_id;
236 		status_t err;
237 		if (roster->GetInstancesFor(info.addon, info.flavor_id, &node_id)!=B_OK)
238 			err = roster->InstantiateDormantNode(info, &node, B_FLAVOR_IS_GLOBAL);
239 		else
240 			err = roster->GetNodeFor(node_id, &node);
241 
242 		if (err == B_OK) {
243 			media_input inputs[16];
244 			int32 inputCount = 16;
245 			if (roster->GetAllInputsFor(node, inputs, 16, &inputCount)==B_OK) {
246 				BMessage message(ML_DEFAULTOUTPUT_CHANGE);
247 
248 				for (int32 i = 0; i < inputCount; i++) {
249 					media_input *input = new media_input();
250 					memcpy(input, &inputs[i], sizeof(*input));
251 					fMenu3->AddItem(item = new Settings2Item(&info, input, new BMessage(message)));
252 					if (inputs[i].destination.id == outputID)
253 						item->SetMarked(true);
254 				}
255 			}
256 		}
257 	}
258 }
259 
260 SettingsItem::SettingsItem(dormant_node_info *info, BMessage *message,
261 			char shortcut, uint32 modifiers)
262 	: BMenuItem(info->name, message, shortcut, modifiers),
263 	fInfo(info)
264 {
265 
266 }
267 
268 
269 status_t
270 SettingsItem::Invoke(BMessage *message)
271 {
272 	if (IsMarked())
273 		return B_OK;
274 	return BMenuItem::Invoke(message);
275 }
276 
277 
278 Settings2Item::Settings2Item(dormant_node_info *info, media_input *input, BMessage *message,
279 			char shortcut, uint32 modifiers)
280 	: BMenuItem(input->name, message, shortcut, modifiers),
281 	fInfo(info),
282 	fInput(input)
283 {
284 
285 }
286 
287 
288 Settings2Item::~Settings2Item()
289 {
290 	delete fInput;
291 }
292 
293 
294 status_t
295 Settings2Item::Invoke(BMessage *message)
296 {
297 	if (IsMarked())
298 		return B_OK;
299 	return BMenuItem::Invoke(message);
300 }
301 
302