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 // RouteWindow.cpp 33 // e.moon 14may99 34 35 #include "RouteApp.h" 36 #include "RouteWindow.h" 37 #include "MediaRoutingView.h" 38 #include "StatusView.h" 39 40 #include "DormantNodeWindow.h" 41 #include "TransportWindow.h" 42 43 #include "RouteAppNodeManager.h" 44 #include "NodeGroup.h" 45 #include "TipManager.h" 46 47 #include <Alert.h> 48 #include <Autolock.h> 49 #include <Debug.h> 50 #include <Font.h> 51 #include <MenuBar.h> 52 #include <Menu.h> 53 #include <MenuItem.h> 54 #include <Message.h> 55 #include <Messenger.h> 56 #include <Roster.h> 57 #include <Screen.h> 58 #include <ScrollView.h> 59 #include <StringView.h> 60 61 #include <algorithm> 62 63 #include "debug_tools.h" 64 #define D_HOOK(x) //PRINT (x) 65 #define D_INTERNAL(x) //PRINT (x) 66 67 __USE_CORTEX_NAMESPACE 68 69 70 const char* const RouteWindow::s_windowName = "Cortex"; 71 72 const BRect RouteWindow::s_initFrame(100,100,700,550); 73 74 const char* const g_aboutText = 75 "Cortex/Route 2.1.2\n\n" 76 "Copyright 1999-2000 Eric Moon\n" 77 "All rights reserved.\n\n" 78 "The Cortex Team:\n\n" 79 "Christopher Lenz: UI\n" 80 "Eric Moon: UI, back-end\n\n" 81 "Thanks to:\nJohn Ashmun\nJon Watte\nDoug Wright\n<your name here>\n\n" 82 "Certain icons used herein are the property of\n" 83 "Be, Inc. and are used by permission."; 84 85 86 RouteWindow::~RouteWindow() 87 { 88 } 89 90 91 RouteWindow::RouteWindow(RouteAppNodeManager* manager) 92 : 93 BWindow(s_initFrame, s_windowName, B_DOCUMENT_WINDOW, 0), 94 m_hScrollBar(0), 95 m_vScrollBar(0), 96 m_transportWindow(0), 97 m_dormantNodeWindow(0), 98 m_selectedGroupID(0), 99 m_zoomed(false), 100 m_zooming(false) 101 { 102 BRect b = Bounds(); 103 104 // initialize the menu bar: add all menus that target this window 105 BMenuBar* pMenuBar = new BMenuBar(b, "menuBar"); 106 BMenu* pFileMenu = new BMenu("File"); 107 BMenuItem* item = new BMenuItem("Open" B_UTF8_ELLIPSIS, 108 new BMessage(RouteApp::M_SHOW_OPEN_PANEL), 'O'); 109 item->SetTarget(be_app); 110 pFileMenu->AddItem(item); 111 pFileMenu->AddItem(new BSeparatorItem()); 112 item = new BMenuItem("Save nodes" B_UTF8_ELLIPSIS, 113 new BMessage(RouteApp::M_SHOW_SAVE_PANEL), 'S'); 114 item->SetTarget(be_app); 115 pFileMenu->AddItem(item); 116 pFileMenu->AddItem(new BSeparatorItem()); 117 pFileMenu->AddItem(new BMenuItem("About Cortex/Route" B_UTF8_ELLIPSIS, 118 new BMessage(B_ABOUT_REQUESTED))); 119 pFileMenu->AddItem(new BSeparatorItem()); 120 pFileMenu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED))); 121 pMenuBar->AddItem(pFileMenu); 122 AddChild(pMenuBar); 123 124 // build the routing view 125 BRect rvBounds = b; 126 rvBounds.top = pMenuBar->Frame().bottom+1; 127 rvBounds.right -= B_V_SCROLL_BAR_WIDTH; 128 rvBounds.bottom -= B_H_SCROLL_BAR_HEIGHT; 129 m_routingView = new MediaRoutingView(manager, rvBounds, "routingView"); 130 131 BRect hsBounds = rvBounds; 132 hsBounds.left = rvBounds.left + 199; 133 hsBounds.top = hsBounds.bottom + 1; 134 hsBounds.right++; 135 hsBounds.bottom = b.bottom + 1; 136 137 m_hScrollBar = new BScrollBar(hsBounds, "hScrollBar", m_routingView, 138 0, 0, B_HORIZONTAL); 139 AddChild(m_hScrollBar); 140 141 BRect vsBounds = rvBounds; 142 vsBounds.left = vsBounds.right + 1; 143 vsBounds.top--; 144 vsBounds.right = b.right + 1; 145 vsBounds.bottom++; 146 147 m_vScrollBar = new BScrollBar(vsBounds, "vScrollBar", m_routingView, 148 0, 0, B_VERTICAL); 149 AddChild(m_vScrollBar); 150 151 BRect svBounds = rvBounds; 152 svBounds.left -= 1; 153 svBounds.right = hsBounds.left - 1; 154 svBounds.top = svBounds.bottom + 1; 155 svBounds.bottom = b.bottom + 1; 156 157 m_statusView = new StatusView(svBounds, manager, m_hScrollBar); 158 AddChild(m_statusView); 159 160 AddChild(m_routingView); 161 162 float minWidth, maxWidth, minHeight, maxHeight; 163 GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight); 164 minWidth = m_statusView->Frame().Width() + 6 * B_V_SCROLL_BAR_WIDTH; 165 minHeight = 6 * B_H_SCROLL_BAR_HEIGHT; 166 SetSizeLimits(minWidth, maxWidth, minHeight, maxHeight); 167 168 // construct the Window menu 169 BMenu* windowMenu = new BMenu("Window"); 170 m_transportWindowItem = new BMenuItem( 171 "Show transport", 172 new BMessage(M_TOGGLE_TRANSPORT_WINDOW)); 173 windowMenu->AddItem(m_transportWindowItem); 174 175 m_dormantNodeWindowItem = new BMenuItem( 176 "Show add-ons", 177 new BMessage(M_TOGGLE_DORMANT_NODE_WINDOW)); 178 windowMenu->AddItem(m_dormantNodeWindowItem); 179 180 windowMenu->AddItem(new BSeparatorItem()); 181 182 m_pullPalettesItem = new BMenuItem( 183 "Pull palettes", 184 new BMessage(M_TOGGLE_PULLING_PALETTES)); 185 windowMenu->AddItem(m_pullPalettesItem); 186 187 pMenuBar->AddItem(windowMenu); 188 189 // create the dormant-nodes palette 190 _toggleDormantNodeWindow(); 191 192 // display group inspector 193 _toggleTransportWindow(); 194 } 195 196 197 // #pragma mark - operations 198 199 200 /*! Enable/disable palette position-locking (when the main 201 window is moved, all palettes follow). 202 */ 203 bool 204 RouteWindow::isPullPalettes() const 205 { 206 return m_pullPalettesItem->IsMarked(); 207 } 208 209 210 void 211 RouteWindow::setPullPalettes(bool enabled) 212 { 213 m_pullPalettesItem->SetMarked(enabled); 214 } 215 216 217 void 218 RouteWindow::constrainToScreen() 219 { 220 BScreen screen(this); 221 222 const BRect sr = screen.Frame(); 223 224 // [c.lenz 1mar2000] this should be handled by every window 225 // itself. will probably change soon ;-) 226 _constrainToScreen(); 227 /* // main window 228 BRect r = Frame(); 229 BPoint offset(0.0, 0.0); 230 if(r.left < 0.0) 231 offset.x = -r.left; 232 if(r.top < 0.0) 233 offset.y = -r.top; 234 if(r.left >= (sr.right - 20.0)) 235 offset.x -= (r.left - (sr.Width()/2)); 236 if(r.top >= (sr.bottom - 20.0)) 237 offset.y -= (r.top - (sr.Height()/2)); 238 if(offset.x != 0.0 || offset.y != 0.0) { 239 setPullPalettes(false); 240 MoveBy(offset.x, offset.y); 241 }*/ 242 243 // transport window 244 BPoint offset = BPoint(0.0, 0.0); 245 BRect r = (m_transportWindow) ? 246 m_transportWindow->Frame() : 247 m_transportWindowFrame; 248 if(r.left < 0.0) 249 offset.x = (sr.Width()*.75) - r.left; 250 if(r.top < 0.0) 251 offset.y = (sr.Height()*.25) - r.top; 252 if(r.left >= (sr.right - 20.0)) 253 offset.x -= (r.left - (sr.Width()/2)); 254 if(r.top >= (sr.bottom - 20.0)) 255 offset.y -= (r.top - (sr.Height()/2)); 256 257 if(offset.x != 0.0 || offset.y != 0.0) { 258 if(m_transportWindow) 259 m_transportWindow->MoveBy(offset.x, offset.y); 260 else 261 m_transportWindowFrame.OffsetBy(offset.x, offset.y); 262 } 263 264 // addon palette 265 offset = BPoint(0.0, 0.0); 266 r = (m_dormantNodeWindow) ? 267 m_dormantNodeWindow->Frame() : 268 m_dormantNodeWindowFrame; 269 if(r.left < 0.0) 270 offset.x = (sr.Width()*.25) - r.left; 271 if(r.top < 0.0) 272 offset.y = (sr.Height()*.125) - r.top; 273 if(r.left >= (sr.right - 20.0)) 274 offset.x -= (r.left - (sr.Width()/2)); 275 if(r.top >= (sr.bottom - 20.0)) 276 offset.y -= (r.top - (sr.Height()/2)); 277 278 if(offset.x != 0.0 || offset.y != 0.0) { 279 if(m_dormantNodeWindow) 280 m_dormantNodeWindow->MoveBy(offset.x, offset.y); 281 else 282 m_dormantNodeWindowFrame.OffsetBy(offset.x, offset.y); 283 } 284 285 } 286 287 288 // #pragma mark - BWindow implementation 289 290 291 void 292 RouteWindow::FrameMoved(BPoint point) 293 { 294 // ignore notification if the window isn't yet visible 295 if(IsHidden()) 296 return; 297 298 BPoint delta = point - m_lastFramePosition; 299 m_lastFramePosition = point; 300 301 302 if (m_pullPalettesItem->IsMarked()) 303 _movePalettesBy(delta.x, delta.y); 304 } 305 306 307 void 308 RouteWindow::FrameResized(float width, float height) 309 { 310 D_HOOK(("RouteWindow::FrameResized()\n")); 311 312 if (!m_zooming) { 313 m_zoomed = false; 314 } 315 else { 316 m_zooming = false; 317 } 318 } 319 320 321 bool 322 RouteWindow::QuitRequested() 323 { 324 be_app->PostMessage(B_QUIT_REQUESTED); 325 return false; // [e.moon 20oct99] app now quits window 326 } 327 328 329 void 330 RouteWindow::Zoom(BPoint origin, float width, float height) 331 { 332 D_HOOK(("RouteWindow::Zoom()\n")); 333 334 m_zooming = true; 335 336 BScreen screen(this); 337 if (!screen.Frame().Contains(Frame())) { 338 m_zoomed = false; 339 } 340 341 if (!m_zoomed) { 342 // resize to the ideal size 343 m_manualSize = Bounds(); 344 float width, height; 345 m_routingView->GetPreferredSize(&width, &height); 346 width += B_V_SCROLL_BAR_WIDTH; 347 height += B_H_SCROLL_BAR_HEIGHT; 348 if (KeyMenuBar()) { 349 height += KeyMenuBar()->Frame().Height(); 350 } 351 ResizeTo(width, height); 352 _constrainToScreen(); 353 m_zoomed = true; 354 } 355 else { 356 // resize to the most recent manual size 357 ResizeTo(m_manualSize.Width(), m_manualSize.Height()); 358 m_zoomed = false; 359 } 360 } 361 362 363 // #pragma mark - BHandler implemenation 364 365 366 void 367 RouteWindow::MessageReceived(BMessage* pMsg) 368 { 369 // PRINT(( 370 // "RouteWindow::MessageReceived()\n")); 371 // pMsg->PrintToStream(); 372 // 373 switch (pMsg->what) { 374 case B_ABOUT_REQUESTED: 375 (new BAlert("About", g_aboutText, "OK"))->Go(); 376 break; 377 378 case MediaRoutingView::M_GROUP_SELECTED: 379 _handleGroupSelected(pMsg); 380 break; 381 382 case MediaRoutingView::M_SHOW_ERROR_MESSAGE: 383 _handleShowErrorMessage(pMsg); 384 break; 385 386 case M_TOGGLE_TRANSPORT_WINDOW: 387 _toggleTransportWindow(); 388 break; 389 390 case M_REFRESH_TRANSPORT_SETTINGS: 391 _refreshTransportSettings(pMsg); 392 break; 393 394 case M_TOGGLE_PULLING_PALETTES: 395 _togglePullPalettes(); 396 break; 397 398 case M_TOGGLE_DORMANT_NODE_WINDOW: 399 _toggleDormantNodeWindow(); 400 break; 401 402 case M_TOGGLE_GROUP_ROLLING: 403 _toggleGroupRolling(); 404 break; 405 406 default: 407 _inherited::MessageReceived(pMsg); 408 break; 409 } 410 } 411 412 413 // #pragma mark - IStateArchivable 414 415 416 status_t 417 RouteWindow::importState(const BMessage* archive) 418 { 419 status_t err; 420 421 // frame rect 422 BRect r; 423 err = archive->FindRect("frame", &r); 424 if(err == B_OK) { 425 MoveTo(r.LeftTop()); 426 ResizeTo(r.Width(), r.Height()); 427 m_lastFramePosition = r.LeftTop(); 428 } 429 430 // status view width 431 int32 i; 432 err = archive->FindInt32("statusViewWidth", &i); 433 if (err == B_OK) { 434 float diff = i - m_statusView->Bounds().IntegerWidth(); 435 m_statusView->ResizeBy(diff, 0.0); 436 m_hScrollBar->ResizeBy(-diff, 0.0); 437 m_hScrollBar->MoveBy(diff, 0.0); 438 } 439 440 // settings 441 bool b; 442 err = archive->FindBool("pullPalettes", &b); 443 if(err == B_OK) 444 m_pullPalettesItem->SetMarked(b); 445 446 // const char* p; 447 // err = archive->FindString("saveDir", &p); 448 // if(err == B_OK) { 449 // m_openPanel.SetPanelDirectory(p); 450 // m_savePanel.SetPanelDirectory(p); 451 // } 452 // 453 // dormant-node window 454 err = archive->FindRect("addonPaletteFrame", &r); 455 if (err == B_OK) 456 m_dormantNodeWindowFrame = r; 457 err = archive->FindBool("addonPaletteVisible", &b); 458 if (err == B_OK && (b != (m_dormantNodeWindow != 0))) { 459 _toggleDormantNodeWindow(); 460 if(!m_dormantNodeWindow) 461 m_dormantNodeWindowFrame = r; 462 } 463 464 if (m_dormantNodeWindow) { 465 m_dormantNodeWindow->MoveTo(m_dormantNodeWindowFrame.LeftTop()); 466 m_dormantNodeWindow->ResizeTo( 467 m_dormantNodeWindowFrame.Width(), 468 m_dormantNodeWindowFrame.Height()); 469 } 470 471 // transport window 472 err = archive->FindRect("transportFrame", &r); 473 if (err == B_OK) 474 m_transportWindowFrame = r; 475 err = archive->FindBool("transportVisible", &b); 476 if (err == B_OK && (b != (m_transportWindow != 0))) { 477 _toggleTransportWindow(); 478 if (!m_transportWindow) 479 m_transportWindowFrame = r; 480 } 481 482 if (m_transportWindow) { 483 m_transportWindow->MoveTo(m_transportWindowFrame.LeftTop()); 484 m_transportWindow->ResizeTo( 485 m_transportWindowFrame.Width(), 486 m_transportWindowFrame.Height()); 487 } 488 489 return B_OK; 490 } 491 492 493 status_t 494 RouteWindow::exportState(BMessage* archive) const 495 { 496 BRect r = Frame(); 497 archive->AddRect("frame", r); 498 archive->AddBool("pullPalettes", m_pullPalettesItem->IsMarked()); 499 500 bool b = (m_dormantNodeWindow != 0); 501 r = b ? m_dormantNodeWindow->Frame() : m_dormantNodeWindowFrame; 502 archive->AddRect("addonPaletteFrame", r); 503 archive->AddBool("addonPaletteVisible", b); 504 505 b = (m_transportWindow != 0); 506 r = b ? m_transportWindow->Frame() : m_transportWindowFrame; 507 508 archive->AddRect("transportFrame", r); 509 archive->AddBool("transportVisible", b); 510 511 // [c.lenz 23may00] remember status view width 512 int i = m_statusView->Bounds().IntegerWidth(); 513 archive->AddInt32("statusViewWidth", i); 514 515 // entry_ref saveRef; 516 // m_savePanel.GetPanelDirectory(&saveRef); 517 // BEntry saveEntry(&saveRef); 518 // if(saveEntry.InitCheck() == B_OK) { 519 // BPath p; 520 // saveEntry.GetPath(&p); 521 // archive->AddString("saveDir", p.Path()); 522 // } 523 524 return B_OK; 525 } 526 527 528 // #pragma mark - implementation 529 530 531 void 532 RouteWindow::_constrainToScreen() 533 { 534 D_INTERNAL(("RouteWindow::_constrainToScreen()\n")); 535 536 BScreen screen(this); 537 BRect screenRect = screen.Frame(); 538 BRect windowRect = Frame(); 539 540 // if the window is outside the screen rect 541 // move it to the default position 542 if (!screenRect.Intersects(windowRect)) { 543 windowRect.OffsetTo(screenRect.LeftTop()); 544 MoveTo(windowRect.LeftTop()); 545 windowRect = Frame(); 546 } 547 548 // if the window is larger than the screen rect 549 // resize it to fit at each side 550 if (!screenRect.Contains(windowRect)) { 551 if (windowRect.left < screenRect.left) { 552 windowRect.left = screenRect.left + 5.0; 553 MoveTo(windowRect.LeftTop()); 554 windowRect = Frame(); 555 } 556 if (windowRect.top < screenRect.top) { 557 windowRect.top = screenRect.top + 5.0; 558 MoveTo(windowRect.LeftTop()); 559 windowRect = Frame(); 560 } 561 if (windowRect.right > screenRect.right) { 562 windowRect.right = screenRect.right - 5.0; 563 } 564 if (windowRect.bottom > screenRect.bottom) { 565 windowRect.bottom = screenRect.bottom - 5.0; 566 } 567 ResizeTo(windowRect.Width(), windowRect.Height()); 568 } 569 } 570 571 572 void 573 RouteWindow::_toggleTransportWindow() 574 { 575 if (m_transportWindow) { 576 m_transportWindowFrame = m_transportWindow->Frame(); 577 m_transportWindow->Lock(); 578 m_transportWindow->Quit(); 579 m_transportWindow = 0; 580 m_transportWindowItem->SetMarked(false); 581 } else { 582 m_transportWindow = new TransportWindow(m_routingView->manager, 583 this, "Transport"); 584 585 // ask for a selection update 586 BMessenger(m_routingView).SendMessage( 587 MediaRoutingView::M_BROADCAST_SELECTION); 588 589 // place & display the window 590 if (m_transportWindowFrame.IsValid()) { 591 m_transportWindow->MoveTo(m_transportWindowFrame.LeftTop()); 592 m_transportWindow->ResizeTo(m_transportWindowFrame.Width(), 593 m_transportWindowFrame.Height()); 594 } 595 596 m_transportWindow->Show(); 597 m_transportWindowItem->SetMarked(true); 598 } 599 } 600 601 602 void 603 RouteWindow::_togglePullPalettes() 604 { 605 m_pullPalettesItem->SetMarked(!m_pullPalettesItem->IsMarked()); 606 } 607 608 609 void 610 RouteWindow::_toggleDormantNodeWindow() 611 { 612 if (m_dormantNodeWindow) { 613 m_dormantNodeWindowFrame = m_dormantNodeWindow->Frame(); 614 m_dormantNodeWindow->Lock(); 615 m_dormantNodeWindow->Quit(); 616 m_dormantNodeWindow = 0; 617 m_dormantNodeWindowItem->SetMarked(false); 618 } else { 619 m_dormantNodeWindow = new DormantNodeWindow(this); 620 if (m_dormantNodeWindowFrame.IsValid()) { 621 m_dormantNodeWindow->MoveTo(m_dormantNodeWindowFrame.LeftTop()); 622 m_dormantNodeWindow->ResizeTo(m_dormantNodeWindowFrame.Width(), 623 m_dormantNodeWindowFrame.Height()); 624 } 625 m_dormantNodeWindow->Show(); 626 m_dormantNodeWindowItem->SetMarked(true); 627 } 628 } 629 630 631 void 632 RouteWindow::_handleGroupSelected(BMessage* message) 633 { 634 status_t err; 635 uint32 groupID; 636 637 err = message->FindInt32("groupID", (int32*)&groupID); 638 if (err < B_OK) { 639 PRINT(( 640 "! RouteWindow::_handleGroupSelected(): no groupID in message!\n")); 641 return; 642 } 643 644 if (!m_transportWindow) 645 return; 646 647 BMessage m(TransportWindow::M_SELECT_GROUP); 648 m.AddInt32("groupID", groupID); 649 BMessenger(m_transportWindow).SendMessage(&m); 650 651 m_selectedGroupID = groupID; 652 } 653 654 655 void 656 RouteWindow::_handleShowErrorMessage(BMessage* message) 657 { 658 status_t err; 659 BString text; 660 661 err = message->FindString("text", &text); 662 if (err < B_OK) { 663 PRINT(( 664 "! RouteWindow::_handleShowErrorMessage(): no text in message!\n")); 665 return; 666 } 667 668 m_statusView->setErrorMessage(text.String(), message->HasBool("error")); 669 } 670 671 672 //! Refresh the transport window for the given group, if any 673 void 674 RouteWindow::_refreshTransportSettings(BMessage* message) 675 { 676 status_t err; 677 uint32 groupID; 678 679 err = message->FindInt32("groupID", (int32*)&groupID); 680 if (err < B_OK) { 681 PRINT(( 682 "! RouteWindow::_refreshTransportSettings(): no groupID in message!\n")); 683 return; 684 } 685 686 if(m_transportWindow) { 687 // relay the message 688 BMessenger(m_transportWindow).SendMessage(message); 689 } 690 } 691 692 693 void 694 RouteWindow::_closePalettes() 695 { 696 BAutolock _l(this); 697 698 if (m_transportWindow) { 699 m_transportWindow->Lock(); 700 m_transportWindow->Quit(); 701 m_transportWindow = 0; 702 } 703 } 704 705 706 //! Move all palette windows by the specified amounts 707 void RouteWindow::_movePalettesBy(float xDelta, float yDelta) 708 { 709 if (m_transportWindow) 710 m_transportWindow->MoveBy(xDelta, yDelta); 711 712 if (m_dormantNodeWindow) 713 m_dormantNodeWindow->MoveBy(xDelta, yDelta); 714 } 715 716 717 //! Toggle group playback 718 void 719 RouteWindow::_toggleGroupRolling() 720 { 721 if (!m_selectedGroupID) 722 return; 723 724 NodeGroup* g; 725 status_t err = m_routingView->manager->findGroup(m_selectedGroupID, &g); 726 if (err < B_OK) 727 return; 728 729 Autolock _l(g); 730 uint32 startAction = (g->runMode() == BMediaNode::B_OFFLINE) 731 ? NodeGroup::M_ROLL : NodeGroup::M_START; 732 733 BMessenger m(g); 734 switch (g->transportState()) { 735 case NodeGroup::TRANSPORT_STOPPED: 736 m.SendMessage(startAction); 737 break; 738 739 case NodeGroup::TRANSPORT_RUNNING: 740 case NodeGroup::TRANSPORT_ROLLING: 741 m.SendMessage(NodeGroup::M_STOP); 742 break; 743 744 default: 745 break; 746 } 747 } 748