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->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 166 alert->Go(0); 167 } 168 bool replace = false; 169 if ((message->FindBool("replace", &replace) == B_OK) 170 && (replace == true)) { 171 PostMessage(B_QUIT_REQUESTED); 172 } 173 break; 174 } 175 case M_THEME_SELECTED: { 176 D_MESSAGE((" -> M_THEME_SELECTED\n")); 177 int32 themeID; 178 if (message->FindInt32("themeID", &themeID) != B_OK) { 179 return; 180 } 181 // not yet implemented 182 break; 183 } 184 case B_MEDIA_WEB_CHANGED: { 185 D_MESSAGE((" -> B_MEDIA_WEB_CHANGED\n")); 186 _updateParameterView(); 187 _constrainToScreen(); 188 break; 189 } 190 default: { 191 BWindow::MessageReceived(message); 192 } 193 } 194 } 195 196 bool ParameterWindow::QuitRequested() { 197 D_HOOK(("ParameterWindow::QuitRequested()\n")); 198 199 // stop watching the MediaRoster 200 BMediaRoster *roster = BMediaRoster::CurrentRoster(); 201 if (roster) { 202 roster->StopWatching(this, m_node, B_MEDIA_WILDCARD); 203 } 204 205 // tell the notification target to forget about us 206 if (m_notifyTarget && m_notifyTarget->IsValid()) { 207 BMessage message(M_CLOSED); 208 message.AddInt32("nodeID", m_node.node); 209 status_t error = m_notifyTarget->SendMessage(&message); 210 if (error) { 211 D_HOOK((" -> error sending message (%s) !\n", strerror(error))); 212 } 213 } 214 215 return true; 216 } 217 218 void ParameterWindow::Zoom( 219 BPoint origin, 220 float width, 221 float height) { 222 D_HOOK(("ParameterWindow::Zoom()\n")); 223 224 m_zooming = true; 225 226 BScreen screen(this); 227 if (!screen.Frame().Contains(Frame())) { 228 m_zoomed = false; 229 } 230 231 if (!m_zoomed) { 232 // resize to the ideal size 233 m_manualSize = Bounds(); 234 ResizeTo(m_idealSize.Width(), m_idealSize.Height()); 235 _constrainToScreen(); 236 m_zoomed = true; 237 } 238 else { 239 // resize to the most recent manual size 240 ResizeTo(m_manualSize.Width(), m_manualSize.Height()); 241 m_zoomed = false; 242 } 243 } 244 245 // -------------------------------------------------------- // 246 // internal operations 247 // -------------------------------------------------------- // 248 249 void ParameterWindow::_init() { 250 D_INTERNAL(("ParameterWindow::_init()\n")); 251 252 // offset to a new position 253 _constrainToScreen(); 254 m_manualSize = Bounds().OffsetToCopy(0.0, 0.0); 255 256 // add the hidden option to close this window when the 257 // control panel has been started successfully 258 BMessage *message = new BMessage(M_START_CONTROL_PANEL); 259 message->AddBool("replace", true); 260 AddShortcut('P', B_COMMAND_KEY | B_SHIFT_KEY | B_OPTION_KEY, 261 message); 262 } 263 264 void ParameterWindow::_updateParameterView( 265 BMediaTheme *theme) { 266 D_INTERNAL(("ParameterWindow::_updateParameterView()\n")); 267 268 // clear the old version 269 if (m_parameters) { 270 ParameterContainerView *view = dynamic_cast<ParameterContainerView *>(FindView("ParameterContainerView")); 271 RemoveChild(view); 272 delete m_parameters; 273 m_parameters = 0; 274 delete view; 275 } 276 277 // fetch ParameterWeb from the MediaRoster 278 BMediaRoster *roster = BMediaRoster::CurrentRoster(); 279 if (roster) { 280 BParameterWeb *web; 281 status_t error = roster->GetParameterWebFor(m_node, &web); 282 if (!error && (web->CountParameters() || web->CountGroups())) { 283 // if no theme was specified, use the preferred theme 284 if (!theme) { 285 theme = BMediaTheme::PreferredTheme(); 286 } 287 // acquire the view 288 m_parameters = BMediaTheme::ViewFor(web, 0, theme); 289 if (m_parameters) { 290 BMenuBar *menuBar = KeyMenuBar(); 291 m_idealSize = m_parameters->Bounds(); 292 m_idealSize.right += B_V_SCROLL_BAR_WIDTH; 293 m_idealSize.bottom += B_H_SCROLL_BAR_HEIGHT; 294 if (menuBar) { 295 m_parameters->MoveTo(0.0, menuBar->Bounds().bottom + 1.0); 296 m_idealSize.bottom += menuBar->Bounds().bottom + 1.0; 297 } 298 } 299 } 300 } 301 302 // limit min size to avoid funny-looking scrollbars 303 float hMin = B_V_SCROLL_BAR_WIDTH*6, vMin = B_H_SCROLL_BAR_HEIGHT*3; 304 // limit max size to full extents of the parameter view 305 float hMax = m_idealSize.Width(), vMax = m_idealSize.Height(); 306 SetSizeLimits(hMin, hMax, vMin, vMax); 307 308 // adapt the window to the new dimensions 309 ResizeTo(m_idealSize.Width(), m_idealSize.Height()); 310 m_zoomed = true; 311 312 if (m_parameters) { 313 BRect paramRect = m_parameters->Bounds(); 314 AddChild(new ParameterContainerView(paramRect, m_parameters)); 315 } 316 } 317 318 void ParameterWindow::_constrainToScreen() { 319 D_INTERNAL(("ParameterWindow::_constrainToScreen()\n")); 320 321 BScreen screen(this); 322 BRect screenRect = screen.Frame(); 323 BRect windowRect = Frame(); 324 325 // if the window is outside the screen rect 326 // move it to the default position 327 if (!screenRect.Intersects(windowRect)) { 328 windowRect.OffsetTo(screenRect.LeftTop()); 329 MoveTo(windowRect.LeftTop()); 330 windowRect = Frame(); 331 } 332 333 // if the window is larger than the screen rect 334 // resize it to fit at each side 335 if (!screenRect.Contains(windowRect)) { 336 if (windowRect.left < screenRect.left) { 337 windowRect.left = screenRect.left + 5.0; 338 MoveTo(windowRect.LeftTop()); 339 windowRect = Frame(); 340 } 341 if (windowRect.top < screenRect.top) { 342 windowRect.top = screenRect.top + 5.0; 343 MoveTo(windowRect.LeftTop()); 344 windowRect = Frame(); 345 } 346 if (windowRect.right > screenRect.right) { 347 windowRect.right = screenRect.right - 5.0; 348 } 349 if (windowRect.bottom > screenRect.bottom) { 350 windowRect.bottom = screenRect.bottom - 5.0; 351 } 352 ResizeTo(windowRect.Width(), windowRect.Height()); 353 } 354 } 355 356 status_t ParameterWindow::_startControlPanel() { 357 D_INTERNAL(("ParameterWindow::_startControlPanel()\n")); 358 359 // get roster instance 360 BMediaRoster *roster = BMediaRoster::CurrentRoster(); 361 if (!roster) { 362 D_INTERNAL((" -> MediaRoster not available\n")); 363 return B_ERROR; 364 } 365 366 // try to StartControlPanel() 367 BMessenger messenger; 368 status_t error = roster->StartControlPanel(m_node, &messenger); 369 if (error) { 370 D_INTERNAL((" -> StartControlPanel() failed (%s)\n", strerror(error))); 371 return error; 372 } 373 374 // notify the notification target, if any 375 if (m_notifyTarget) { 376 BMessage message(M_CONTROL_PANEL_STARTED); 377 message.AddInt32("nodeID", m_node.node); 378 message.AddMessenger("messenger", messenger); 379 error = m_notifyTarget->SendMessage(&message); 380 if (error) { 381 D_INTERNAL((" -> failed to notify target\n")); 382 } 383 } 384 385 return B_OK; 386 } 387 388 // END -- ParameterWindow.cpp -- 389