xref: /haiku/src/preferences/media/MediaViews.cpp (revision a906d0a031e721e2f2ec9d95274103e74a3a774f)
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 #include "MediaViews.h"
18 
19 #include <Box.h>
20 #include <Button.h>
21 #include <Catalog.h>
22 #include <Deskbar.h>
23 #include <Entry.h>
24 #include <GridView.h>
25 #include <GroupView.h>
26 #include <Locale.h>
27 #include <MediaAddOn.h>
28 #include <MediaRoster.h>
29 #include <MenuField.h>
30 #include <PopUpMenu.h>
31 #include <SpaceLayoutItem.h>
32 #include <String.h>
33 #include <TextView.h>
34 
35 #include <stdio.h>
36 
37 
38 #undef B_TRANSLATE_CONTEXT
39 #define B_TRANSLATE_CONTEXT "Media views"
40 
41 
42 SettingsView::SettingsView (bool isVideo)
43 	:
44 	BView("SettingsView", B_WILL_DRAW | B_SUPPORTS_LAYOUT),
45 	fIsVideo(isVideo)
46 {
47 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
48 
49 	// create the default box
50 
51 	// input menu
52 	fInputMenu = new BPopUpMenu(B_TRANSLATE("<none>"));
53 	fInputMenu->SetLabelFromMarked(true);
54 	BMenuField* inputMenuField = new BMenuField("inputMenuField",
55 		fIsVideo ? B_TRANSLATE("Video input:")
56 			: B_TRANSLATE("Audio input:"), fInputMenu, NULL);
57 
58 	// output menu
59 	fOutputMenu = new BPopUpMenu(B_TRANSLATE("<none>"));
60 	fOutputMenu->SetLabelFromMarked(true);
61 	BMenuField* outputMenuField = new BMenuField("outputMenuField",
62 		fIsVideo ? B_TRANSLATE("Video output:")
63 			: B_TRANSLATE("Audio output:"), fOutputMenu, NULL);
64 
65 	// channel menu (audio only)
66 	BMenuField* channelMenuField = NULL;
67 	if (!fIsVideo) {
68 		fChannelMenu = new BPopUpMenu(B_TRANSLATE("<none>"));
69 		fChannelMenu->SetLabelFromMarked(true);
70 		channelMenuField = new BMenuField("channelMenuField",
71 			B_TRANSLATE("Channel:"), fChannelMenu, NULL);
72 		channelMenuField->SetDivider(StringWidth(B_TRANSLATE("Channel:"))+5);
73 	}
74 
75 	BBox* defaultsBox = new BBox("defaults");
76 	defaultsBox->SetLabel(fIsVideo ? B_TRANSLATE("Default nodes")
77 		: B_TRANSLATE("Defaults"));
78 
79 	// put our menus in a BGridView in our BBox, this way, the BBox makes sure
80 	// we have are not blocking the label.
81 	BGridView* defaultsGridView = new BGridView();
82 	defaultsBox->AddChild(defaultsGridView);
83 
84 	BGridLayout* defaultsGrid = defaultsGridView->GridLayout();
85 	defaultsGrid->SetInsets(B_USE_DEFAULT_SPACING, 0, B_USE_DEFAULT_SPACING,
86 		B_USE_DEFAULT_SPACING);
87 
88 	BLayoutItem* labelItem = inputMenuField->CreateLabelLayoutItem();
89 	BLayoutItem* menuItem = inputMenuField->CreateMenuBarLayoutItem();
90 	defaultsGrid->AddItem(labelItem, 0, 0, 1, 1);
91 	defaultsGrid->AddItem(menuItem, 1, 0, 3, 1);
92 
93 	int32 outputMenuWidth = 3;
94 	if (channelMenuField) {
95 		outputMenuWidth = 1;
96 		labelItem = channelMenuField->CreateLabelLayoutItem();
97 		menuItem = channelMenuField->CreateMenuBarLayoutItem();
98 		defaultsGrid->AddItem(labelItem, 2, 1, 1, 1);
99 		defaultsGrid->AddItem(menuItem, 3, 1, 1, 1);
100 	}
101 
102 	labelItem = outputMenuField->CreateLabelLayoutItem();
103 	menuItem = outputMenuField->CreateMenuBarLayoutItem();
104 	defaultsGrid->AddItem(labelItem, 0, 1, 1, 1);
105 	defaultsGrid->AddItem(menuItem, 1, 1, outputMenuWidth, 1);
106 
107 
108 	rgb_color red_color = {222, 32, 33};
109 	fRestartView = new BStringView("restartStringView",
110 		B_TRANSLATE("Restart the media server to apply changes."));
111 	fRestartView->SetHighColor(red_color);
112 	defaultsBox->AddChild(fRestartView);
113 	fRestartView->Hide();
114 
115 	// create the realtime box
116 	BBox* realtimeBox = new BBox("realtime");
117 	realtimeBox->SetLabel(B_TRANSLATE("Real-time"));
118 
119 	BMessage* message = new BMessage(ML_ENABLE_REAL_TIME);
120 	message->AddBool("isVideo", fIsVideo);
121 	fRealtimeCheckBox = new BCheckBox("realtimeCheckBox",
122 		fIsVideo ? B_TRANSLATE("Enable real-time video")
123 			: B_TRANSLATE("Enable real-time audio"),
124 		message);
125 
126 	uint32 flags;
127 	BMediaRoster::Roster()->GetRealtimeFlags(&flags);
128 	if (flags & (fIsVideo ? B_MEDIA_REALTIME_VIDEO : B_MEDIA_REALTIME_AUDIO))
129 		fRealtimeCheckBox->SetValue(B_CONTROL_ON);
130 
131 	BTextView* textView = new BTextView("stringView");
132 	textView->Insert(fIsVideo ? B_TRANSLATE(
133 		"Enabling real-time video allows system to "
134 		"perform video operations as fast and smoothly as possible.  It "
135 		"achieves optimum performance by using more RAM."
136 		"\n\nOnly enable this feature if you need the lowest latency possible.")
137 		: B_TRANSLATE(
138 		"Enabling real-time audio allows system to record and play audio "
139 		"as fast as possible.  It achieves this performance by using more"
140 		" CPU and RAM.\n\nOnly enable this feature if you need the lowest"
141 		" latency possible."));
142 
143 	textView->MakeEditable(false);
144 	textView->MakeSelectable(false);
145 	textView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
146 
147 	BGroupLayout* realtimeBoxLayout = new BGroupLayout(B_VERTICAL, 5);
148 	realtimeBoxLayout->SetInsets(10,10,10,10);
149 	realtimeBox->SetLayout(realtimeBoxLayout);
150 
151 	realtimeBoxLayout->AddItem(BSpaceLayoutItem::CreateVerticalStrut(5));
152 	realtimeBoxLayout->AddView(fRealtimeCheckBox);
153 	realtimeBoxLayout->AddView(textView);
154 
155 	// create the bottom line: volume in deskbar checkbox and restart button
156 	BGroupView* bottomView = new BGroupView(B_HORIZONTAL);
157 	BButton* restartButton = new BButton("restartButton",
158 		B_TRANSLATE("Restart media services"),
159 		new BMessage(ML_RESTART_MEDIA_SERVER));
160 
161 	if (!fIsVideo) {
162 		fVolumeCheckBox = new BCheckBox("volumeCheckBox",
163 			B_TRANSLATE("Show volume control on Deskbar"),
164 			new BMessage(ML_SHOW_VOLUME_CONTROL));
165 		bottomView->GroupLayout()->AddView(fVolumeCheckBox);
166 		if (BDeskbar().HasItem("MediaReplicant"))
167 			fVolumeCheckBox->SetValue(B_CONTROL_ON);
168 	}
169 	else{
170 		bottomView->GroupLayout()->AddItem(BSpaceLayoutItem::CreateGlue());
171 	}
172 	bottomView->GroupLayout()->AddView(restartButton);
173 
174 	// compose all stuff
175 	BGroupLayout* rootlayout = new BGroupLayout(B_VERTICAL, 5);
176 	SetLayout(rootlayout);
177 
178 	rootlayout->AddView(defaultsBox);
179 	rootlayout->AddView(realtimeBox);
180 	rootlayout->AddView(bottomView);
181 }
182 
183 
184 void
185 SettingsView::AddNodes(NodeList& list, bool isInput)
186 {
187 	BMenu* menu = isInput ? fInputMenu : fOutputMenu;
188 
189 	for (BMenuItem* item; (item = menu->RemoveItem((int32)0)) != NULL;)
190 		delete item;
191 
192 	BMessage message(ML_DEFAULT_CHANGE);
193 	message.AddBool("isVideo", fIsVideo);
194 	message.AddBool("isInput", isInput);
195 
196 	for (int32 i = 0; i < list.CountItems(); i++) {
197 		dormant_node_info* info = list.ItemAt(i);
198 		menu->AddItem(new SettingsItem(info, new BMessage(message)));
199 	}
200 }
201 
202 
203 void
204 SettingsView::SetDefault(dormant_node_info &info, bool isInput, int32 outputID)
205 {
206 	BMenu* menu = isInput ? fInputMenu : fOutputMenu;
207 
208 	for (int32 i = 0; i < menu->CountItems(); i++) {
209 		SettingsItem* item = static_cast<SettingsItem*>(menu->ItemAt(i));
210 		if (item->fInfo && item->fInfo->addon == info.addon
211 			&& item->fInfo->flavor_id == info.flavor_id) {
212 			item->SetMarked(true);
213 			break;
214 		}
215 	}
216 
217 	if (!fIsVideo && !isInput && outputID >= 0) {
218 		BMenuItem* item;
219 		while ((item = fChannelMenu->RemoveItem((int32)0)) != NULL)
220 			delete item;
221 
222 		BMediaRoster* roster = BMediaRoster::Roster();
223 		media_node node;
224 		media_node_id node_id;
225 		status_t err;
226 		if (roster->GetInstancesFor(info.addon, info.flavor_id,
227 			&node_id) != B_OK) {
228 			err = roster->InstantiateDormantNode(info, &node,
229 				B_FLAVOR_IS_GLOBAL);
230 		} else {
231 			err = roster->GetNodeFor(node_id, &node);
232 		}
233 
234 		if (err == B_OK) {
235 			media_input inputs[16];
236 			int32 inputCount = 16;
237 			if (roster->GetAllInputsFor(node, inputs, 16, &inputCount)==B_OK) {
238 				BMessage message(ML_DEFAULTOUTPUT_CHANGE);
239 
240 				for (int32 i = 0; i < inputCount; i++) {
241 					media_input* input = new media_input();
242 					memcpy(input, &inputs[i], sizeof(*input));
243 					item = new Settings2Item(&info, input,
244 						new BMessage(message));
245 					fChannelMenu->AddItem(item);
246 					if (inputs[i].destination.id == outputID)
247 						item->SetMarked(true);
248 				}
249 			}
250 		}
251 	}
252 }
253 
254 
255 SettingsItem::SettingsItem(dormant_node_info* info, BMessage* message,
256 		char shortcut, uint32 modifiers)
257 	:
258 	BMenuItem(info->name, message, shortcut, modifiers),
259 	fInfo(info)
260 {
261 
262 }
263 
264 
265 status_t
266 SettingsItem::Invoke(BMessage* message)
267 {
268 	if (IsMarked())
269 		return B_OK;
270 	return BMenuItem::Invoke(message);
271 }
272 
273 
274 Settings2Item::Settings2Item(dormant_node_info* info, media_input* input,
275 		BMessage* message, char shortcut, uint32 modifiers)
276 	:
277 	BMenuItem(input->name, message, shortcut, modifiers),
278 	fInfo(info),
279 	fInput(input)
280 {
281 }
282 
283 
284 Settings2Item::~Settings2Item()
285 {
286 	delete fInput;
287 }
288 
289 
290 status_t
291 Settings2Item::Invoke(BMessage* message)
292 {
293 	if (IsMarked())
294 		return B_OK;
295 	return BMenuItem::Invoke(message);
296 }
297 
298