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 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 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 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 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 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 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 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 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 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 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