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