xref: /haiku/src/apps/cortex/ParameterView/ParameterWindow.cpp (revision 1d9d47fc72028bb71b5f232a877231e59cfe2438)
1 // ParameterWindow.cpp
2 
3 #include "ParameterWindow.h"
4 // ParameterWindow
5 #include "ParameterContainerView.h"
6 
7 // Application Kit
8 #include <Message.h>
9 #include <Messenger.h>
10 // Interface Kit
11 #include <Alert.h>
12 #include <Menu.h>
13 #include <MenuBar.h>
14 #include <MenuItem.h>
15 #include <Screen.h>
16 #include <ScrollBar.h>
17 // Media Kit
18 #include <MediaRoster.h>
19 #include <MediaTheme.h>
20 #include <ParameterWeb.h>
21 // Storage Kit
22 #include <FilePanel.h>
23 #include <Path.h>
24 // Support Kit
25 #include <String.h>
26 
27 __USE_CORTEX_NAMESPACE
28 
29 #include <Debug.h>
30 #define D_ALLOC(x) //PRINT (x)
31 #define D_HOOK(x) //PRINT (x)
32 #define D_INTERNAL(x) //PRINT (x)
33 #define D_MESSAGE(x) //PRINT (x)
34 
35 // -------------------------------------------------------- //
36 // ctor/dtor
37 // -------------------------------------------------------- //
38 
39 ParameterWindow::ParameterWindow(
40 	BPoint position,
41 	live_node_info &nodeInfo,
42 	BMessenger *notifyTarget)
43 	: BWindow(BRect(position, position + BPoint(50.0, 50.0)),
44 			  "parameters", B_DOCUMENT_WINDOW,
45 			  B_WILL_ACCEPT_FIRST_CLICK | B_ASYNCHRONOUS_CONTROLS),
46 	  m_node(nodeInfo.node),
47 	  m_parameters(0),
48 	  m_notifyTarget(0),
49 	  m_zoomed(false),
50 	  m_zooming(false) {
51 	D_ALLOC(("ParameterWindow::ParameterWindow()\n"));
52 
53 	// add the nodes name to the title
54 	{
55 		char* title = new char[strlen(nodeInfo.name) + strlen(" parameters") + 1];
56 		sprintf(title, "%s parameters", nodeInfo.name);
57 		SetTitle(title);
58 		delete [] title;
59 	}
60 	// add the menu bar
61 	BMenuBar *menuBar = new BMenuBar(Bounds(), "ParameterWindow MenuBar");
62 
63 	BMenu *menu = new BMenu("Window");
64 	menu->AddItem(new BMenuItem("Start Control Panel",
65 								new BMessage(M_START_CONTROL_PANEL),
66 								'P', B_COMMAND_KEY | B_SHIFT_KEY));
67 	menu->AddSeparatorItem();
68 	menu->AddItem(new BMenuItem("Close",
69 								new BMessage(B_QUIT_REQUESTED),
70 								'W', B_COMMAND_KEY));
71 	menuBar->AddItem(menu);
72 
73 	// future Media Theme selection capabilities go here
74 	menu = new BMenu("Themes");
75 	BMessage *message = new BMessage(M_THEME_SELECTED);
76 	BMediaTheme *theme = BMediaTheme::PreferredTheme();
77 	message->AddInt32("themeID", theme->ID());
78 	BMenuItem *item = new BMenuItem(theme->Name(), message);
79 	item->SetMarked(true);
80 	menu->AddItem(item);
81 	menuBar->AddItem(menu);
82 	AddChild(menuBar);
83 
84 	_updateParameterView();
85 	_init();
86 
87 	// start watching for parameter web changes
88 	BMediaRoster *roster = BMediaRoster::CurrentRoster();
89 	roster->StartWatching(this, nodeInfo.node, B_MEDIA_WILDCARD);
90 
91 	if (notifyTarget) {
92 		m_notifyTarget = new BMessenger(*notifyTarget);
93 	}
94 }
95 
96 ParameterWindow::~ParameterWindow() {
97 	D_ALLOC(("ParameterWindow::~ParameterWindow()\n"));
98 
99 	if (m_notifyTarget) {
100 		delete m_notifyTarget;
101 	}
102 }
103 
104 // -------------------------------------------------------- //
105 // BWindow impl
106 // -------------------------------------------------------- //
107 
108 void ParameterWindow::FrameResized(
109 	float width,
110 	float height) {
111 	D_HOOK(("ParameterWindow::FrameResized()\n"));
112 
113 	if (!m_zooming) {
114 		m_zoomed = false;
115 	}
116 	else {
117 		m_zooming = false;
118 	}
119 }
120 
121 void ParameterWindow::MessageReceived(
122 	BMessage *message) {
123 	D_MESSAGE(("ParameterWindow::MessageReceived()\n"));
124 
125 	switch (message->what) {
126 		case M_START_CONTROL_PANEL: {
127 			D_MESSAGE((" -> M_START_CONTROL_PANEL\n"));
128 			status_t error = _startControlPanel();
129 			if (error) {
130 				BString s = "Could not start control panel";
131 				s << " (" << strerror(error) << ")";
132 				BAlert *alert = new BAlert("", s.String(), "OK", 0, 0,
133 										   B_WIDTH_AS_USUAL, B_WARNING_ALERT);
134 				alert->Go(0);
135 			}
136 			bool replace = false;
137 			if ((message->FindBool("replace", &replace) == B_OK)
138 			 && (replace == true)) {
139 				PostMessage(B_QUIT_REQUESTED);
140 			}
141 			break;
142 		}
143 		case M_THEME_SELECTED: {
144 			D_MESSAGE((" -> M_THEME_SELECTED\n"));
145 			int32 themeID;
146 			if (message->FindInt32("themeID", &themeID) != B_OK) {
147 				return;
148 			}
149 			// not yet implemented
150 			break;
151 		}
152 		case B_MEDIA_WEB_CHANGED: {
153 			D_MESSAGE((" -> B_MEDIA_WEB_CHANGED\n"));
154 			_updateParameterView();
155 			_constrainToScreen();
156 			break;
157 		}
158 		default: {
159 			BWindow::MessageReceived(message);
160 		}
161 	}
162 }
163 
164 bool ParameterWindow::QuitRequested() {
165 	D_HOOK(("ParameterWindow::QuitRequested()\n"));
166 
167 	// stop watching the MediaRoster
168 	BMediaRoster *roster = BMediaRoster::CurrentRoster();
169 	if (roster)	{
170 		roster->StopWatching(this, m_node, B_MEDIA_WILDCARD);
171 	}
172 
173 	// tell the notification target to forget about us
174 	if (m_notifyTarget && m_notifyTarget->IsValid()) {
175 		BMessage message(M_CLOSED);
176 		message.AddInt32("nodeID", m_node.node);
177 		status_t error = m_notifyTarget->SendMessage(&message);
178 		if (error) {
179 			D_HOOK((" -> error sending message (%s) !\n", strerror(error)));
180 		}
181 	}
182 
183 	return true;
184 }
185 
186 void ParameterWindow::Zoom(
187 	BPoint origin,
188 	float width,
189 	float height) {
190 	D_HOOK(("ParameterWindow::Zoom()\n"));
191 
192 	m_zooming = true;
193 
194 	BScreen screen(this);
195 	if (!screen.Frame().Contains(Frame())) {
196 		m_zoomed = false;
197 	}
198 
199 	if (!m_zoomed) {
200 		// resize to the ideal size
201 		m_manualSize = Bounds();
202 		ResizeTo(m_idealSize.Width(), m_idealSize.Height());
203 		_constrainToScreen();
204 		m_zoomed = true;
205 	}
206 	else {
207 		// resize to the most recent manual size
208 		ResizeTo(m_manualSize.Width(), m_manualSize.Height());
209 		m_zoomed = false;
210 	}
211 }
212 
213 // -------------------------------------------------------- //
214 // internal operations
215 // -------------------------------------------------------- //
216 
217 void ParameterWindow::_init() {
218 	D_INTERNAL(("ParameterWindow::_init()\n"));
219 
220 	// offset to a new position
221 	_constrainToScreen();
222 	m_manualSize = Bounds().OffsetToCopy(0.0, 0.0);
223 
224 	// add the hidden option to close this window when the
225 	// control panel has been started successfully
226 	BMessage *message = new BMessage(M_START_CONTROL_PANEL);
227 	message->AddBool("replace", true);
228 	AddShortcut('P', B_COMMAND_KEY | B_SHIFT_KEY | B_OPTION_KEY,
229 				message);
230 }
231 
232 void ParameterWindow::_updateParameterView(
233 	BMediaTheme *theme) {
234 	D_INTERNAL(("ParameterWindow::_updateParameterView()\n"));
235 
236 	// clear the old version
237 	if (m_parameters) {
238 		ParameterContainerView *view = dynamic_cast<ParameterContainerView *>(FindView("ParameterContainerView"));
239 		RemoveChild(view);
240 		delete m_parameters;
241 		m_parameters = 0;
242 		delete view;
243 	}
244 
245 	// fetch ParameterWeb from the MediaRoster
246 	BMediaRoster *roster = BMediaRoster::CurrentRoster();
247 	if (roster) {
248 		BParameterWeb *web;
249 		status_t error = roster->GetParameterWebFor(m_node, &web);
250 		if (!error && (web->CountParameters() || web->CountGroups())) {
251 			// if no theme was specified, use the preferred theme
252 			if (!theme) {
253 				theme = BMediaTheme::PreferredTheme();
254 			}
255 			// acquire the view
256 			m_parameters = BMediaTheme::ViewFor(web, 0, theme);
257 			if (m_parameters) {
258 				BMenuBar *menuBar = KeyMenuBar();
259 				m_idealSize = m_parameters->Bounds();
260 				m_idealSize.right += B_V_SCROLL_BAR_WIDTH;
261 				m_idealSize.bottom += B_H_SCROLL_BAR_HEIGHT;
262 				if (menuBar) {
263 					m_parameters->MoveTo(0.0, menuBar->Bounds().bottom + 1.0);
264 					m_idealSize.bottom += menuBar->Bounds().bottom + 1.0;
265 				}
266 			}
267 		}
268 	}
269 
270 	// limit min size to avoid funny-looking scrollbars
271 	float hMin = B_V_SCROLL_BAR_WIDTH*6, vMin = B_H_SCROLL_BAR_HEIGHT*3;
272 	// limit max size to full extents of the parameter view
273 	float hMax = m_idealSize.Width(), vMax = m_idealSize.Height();
274 	SetSizeLimits(hMin, hMax, vMin, vMax);
275 
276 	// adapt the window to the new dimensions
277 	ResizeTo(m_idealSize.Width(), m_idealSize.Height());
278 	m_zoomed = true;
279 
280 	if (m_parameters) {
281 		BRect paramRect = m_parameters->Bounds();
282 		AddChild(new ParameterContainerView(paramRect, m_parameters));
283 	}
284 }
285 
286 void ParameterWindow::_constrainToScreen() {
287 	D_INTERNAL(("ParameterWindow::_constrainToScreen()\n"));
288 
289 	BScreen screen(this);
290 	BRect screenRect = screen.Frame();
291 	BRect windowRect = Frame();
292 
293 	// if the window is outside the screen rect
294 	// move it to the default position
295 	if (!screenRect.Intersects(windowRect)) {
296 		windowRect.OffsetTo(screenRect.LeftTop());
297 		MoveTo(windowRect.LeftTop());
298 		windowRect = Frame();
299 	}
300 
301 	// if the window is larger than the screen rect
302 	// resize it to fit at each side
303 	if (!screenRect.Contains(windowRect)) {
304 		if (windowRect.left < screenRect.left) {
305 			windowRect.left = screenRect.left + 5.0;
306 			MoveTo(windowRect.LeftTop());
307 			windowRect = Frame();
308 		}
309 		if (windowRect.top < screenRect.top) {
310 			windowRect.top = screenRect.top + 5.0;
311 			MoveTo(windowRect.LeftTop());
312 			windowRect = Frame();
313 		}
314 		if (windowRect.right > screenRect.right) {
315 			windowRect.right = screenRect.right - 5.0;
316 		}
317 		if (windowRect.bottom > screenRect.bottom) {
318 			windowRect.bottom = screenRect.bottom - 5.0;
319 		}
320 		ResizeTo(windowRect.Width(), windowRect.Height());
321 	}
322 }
323 
324 status_t ParameterWindow::_startControlPanel() {
325 	D_INTERNAL(("ParameterWindow::_startControlPanel()\n"));
326 
327 	// get roster instance
328 	BMediaRoster *roster = BMediaRoster::CurrentRoster();
329 	if (!roster) {
330 		D_INTERNAL((" -> MediaRoster not available\n"));
331 		return B_ERROR;
332 	}
333 
334 	// try to StartControlPanel()
335 	BMessenger messenger;
336 	status_t error = roster->StartControlPanel(m_node, &messenger);
337 	if (error) {
338 		D_INTERNAL((" -> StartControlPanel() failed (%s)\n", strerror(error)));
339 		return error;
340 	}
341 
342 	// notify the notification target, if any
343 	if (m_notifyTarget) {
344 		BMessage message(M_CONTROL_PANEL_STARTED);
345 		message.AddInt32("nodeID", m_node.node);
346 		message.AddMessenger("messenger", messenger);
347 		error = m_notifyTarget->SendMessage(&message);
348 		if (error) {
349 			D_INTERNAL((" -> failed to notify target\n"));
350 		}
351 	}
352 
353 	return B_OK;
354 }
355 
356 // END -- ParameterWindow.cpp --
357