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