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