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 // MediaRoutingView.cpp 33 34 #include "MediaRoutingView.h" 35 36 // RouteApp 37 #include "RouteApp.h" 38 #include "RouteAppNodeManager.h" 39 #include "RouteWindow.h" 40 #include "NodeSetIOContext.h" 41 // DormantNodeView 42 #include "DormantNodeView.h" 43 // InfoWindow 44 #include "InfoWindowManager.h" 45 // TransportWindow 46 #include "TransportWindow.h" 47 // MediaRoutingView 48 #include "MediaNodePanel.h" 49 #include "MediaWire.h" 50 // NodeManager 51 #include "NodeGroup.h" 52 #include "NodeRef.h" 53 #include "Connection.h" 54 // ParameterWindow 55 #include "ParameterWindowManager.h" 56 57 // Application Kit 58 #include <Application.h> 59 // Interface Kit 60 #include <Alert.h> 61 #include <Bitmap.h> 62 #include <MenuItem.h> 63 #include <PopUpMenu.h> 64 #include <Window.h> 65 // Locale Kit 66 #undef B_CATALOG 67 #define B_CATALOG (&sCatalog) 68 #include <Catalog.h> 69 // Media Kit 70 #include <MediaRoster.h> 71 // Storage Kit 72 #include <File.h> 73 #include <NodeInfo.h> 74 #include <Path.h> 75 // Translation Kit 76 #include <BitmapStream.h> 77 #include <TranslatorRoster.h> 78 79 #undef B_TRANSLATION_CONTEXT 80 #define B_TRANSLATION_CONTEXT "MediaRoutingView" 81 82 __USE_CORTEX_NAMESPACE 83 84 #include <Debug.h> 85 #define D_METHOD(x) //PRINT (x) 86 #define D_MESSAGE(x) //PRINT (x) 87 #define D_MOUSE(x) //PRINT (x) 88 #define D_KEY(x) //PRINT (x) 89 90 static BCatalog sCatalog("x-vnd.Cortex.MediaRoutingView"); 91 92 // ---------------------------------------------------------------- // 93 // constants 94 // ---------------------------------------------------------------- // 95 96 float MediaRoutingView::M_CLEANUP_H_GAP = 25.0; 97 float MediaRoutingView::M_CLEANUP_V_GAP = 10.0; 98 float MediaRoutingView::M_CLEANUP_H_MARGIN = 15.0; 99 float MediaRoutingView::M_CLEANUP_V_MARGIN = 10.0; 100 101 // ---------------------------------------------------------------- // 102 // m_inactiveNodeState content 103 // ---------------------------------------------------------------- // 104 105 struct _inactive_node_state_entry { 106 _inactive_node_state_entry( 107 const char* _name, int32 _kind, const BMessage& _state) : 108 name(_name), kind(_kind), state(_state) {} 109 110 BString name; 111 uint32 kind; 112 BMessage state; 113 }; 114 115 // ---------------------------------------------------------------- // 116 // ctor/dtor 117 // ---------------------------------------------------------------- // 118 119 MediaRoutingView::MediaRoutingView( 120 RouteAppNodeManager *nodeManager, 121 BRect frame, 122 const char *name, 123 uint32 resizeMode) 124 : DiagramView(frame, "MediaRoutingView", true, B_FOLLOW_ALL_SIDES), 125 manager(nodeManager), 126 m_layout(M_ICON_VIEW), 127 m_nextGroupNumber(1), 128 m_lastDroppedNode(0), 129 m_draggedWire(0) 130 { 131 D_METHOD(("MediaRoutingView::MediaRoutingView()\n")); 132 ASSERT(manager); 133 134 setBackgroundColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_DARKEN_2_TINT)); 135 SetItemAlignment(5.0, 5.0); 136 _initLayout(); 137 } 138 139 MediaRoutingView::~MediaRoutingView() { 140 D_METHOD(("MediaRoutingView::~MediaRoutingView()\n")); 141 142 _emptyInactiveNodeState(); 143 144 // quit ParameterWindowManager if necessary 145 ParameterWindowManager::shutDown(); 146 147 // quit InfoWindowManager if necessary 148 InfoWindowManager::shutDown(); 149 } 150 151 // -------------------------------------------------------- // 152 // *** derived from DiagramView 153 // -------------------------------------------------------- // 154 155 void MediaRoutingView::connectionAborted( 156 DiagramEndPoint *fromWhich) 157 { 158 D_METHOD(("MediaRoutingView::connectionAborted()\n")); 159 160 be_app->SetCursor(B_HAND_CURSOR); 161 } 162 163 void MediaRoutingView::connectionEstablished( 164 DiagramEndPoint *fromWhich, 165 DiagramEndPoint *toWhich) 166 { 167 D_METHOD(("MediaRoutingView::connectionEstablished()\n")); 168 169 be_app->SetCursor(B_HAND_CURSOR); 170 } 171 172 DiagramWire *MediaRoutingView::createWire( 173 DiagramEndPoint *fromWhich, 174 DiagramEndPoint *toWhich) 175 { 176 D_METHOD(("MediaRoutingView::createWire()\n")); 177 178 MediaJack *outputJack, *inputJack; 179 MediaJack *jack = dynamic_cast<MediaJack *>(fromWhich); 180 181 if (jack == NULL) 182 return 0; 183 184 if (jack->isOutput()) 185 { 186 outputJack = jack; 187 inputJack = dynamic_cast<MediaJack *>(toWhich); 188 if (!inputJack || !inputJack->isInput()) 189 { 190 return 0; 191 } 192 } 193 else 194 { 195 inputJack = jack; 196 outputJack = dynamic_cast<MediaJack *>(toWhich); 197 if (!outputJack || !outputJack->isOutput()) 198 { 199 return 0; 200 } 201 } 202 if (!outputJack->isConnected() && !inputJack->isConnected()) 203 { 204 media_output output; 205 media_input input; 206 if ((outputJack->getOutput(&output) == B_OK) 207 && (inputJack->getInput(&input) == B_OK)) 208 { 209 status_t error; 210 Connection connection; 211 error = manager->connect(output, input, &connection); 212 if (error) 213 { 214 showErrorMessage(B_TRANSLATE("Could not connect"), error); 215 } 216 } 217 } 218 return 0; 219 } 220 221 DiagramWire *MediaRoutingView::createWire( 222 DiagramEndPoint *fromWhich) 223 { 224 D_METHOD(("MediaRoutingView::createWire(temp)\n")); 225 226 MediaJack *jack = dynamic_cast<MediaJack *>(fromWhich); 227 if (jack) 228 { 229 if (jack->isOutput()) // this is the start point 230 { 231 return new MediaWire(jack, true); 232 } 233 else 234 { 235 return new MediaWire(jack, false); 236 } 237 } 238 return 0; 239 } 240 241 242 void 243 MediaRoutingView::BackgroundMouseDown(BPoint point, uint32 buttons, 244 uint32 clicks) 245 { 246 D_MOUSE(("MediaRoutingView::BackgroundMouseDown()\n")); 247 248 if ((buttons == B_SECONDARY_MOUSE_BUTTON) 249 || (modifiers() & B_CONTROL_KEY)) { 250 EndRectTracking(); 251 showContextMenu(point); 252 } 253 } 254 255 256 void 257 MediaRoutingView::MessageDropped(BPoint point, BMessage *message) 258 { 259 D_METHOD(("MediaRoutingView::MessageDropped()\n")); 260 261 switch (message->what) { 262 case DormantNodeView::M_INSTANTIATE_NODE: 263 { 264 D_MESSAGE(("MediaRoutingView::MessageDropped(DormantNodeView::M_INSTANTIATE_NODE)\n")); 265 type_code type; 266 int32 count; 267 if (message->GetInfo("which", &type, &count) == B_OK) { 268 for (int32 n = 0; n < count; n++) { 269 dormant_node_info info; 270 const void *data; 271 ssize_t dataSize; 272 if (message->FindData("which", B_RAW_TYPE, &data, &dataSize) == B_OK) { 273 memcpy(reinterpret_cast<void *>(&info), data, dataSize); 274 NodeRef* droppedNode; 275 status_t error; 276 error = manager->instantiate(info, &droppedNode); 277 if (!error) { 278 m_lastDroppedNode = droppedNode->id(); 279 BPoint dropPoint, dropOffset; 280 dropPoint = message->DropPoint(&dropOffset); 281 m_lastDropPoint = Align(ConvertFromScreen(dropPoint - dropOffset)); 282 } else { 283 BString s = B_TRANSLATE( 284 "Could not instantiate '%infoname%'"); 285 s.ReplaceFirst("%infoname%", info.name); 286 showErrorMessage(s, error); 287 } 288 } 289 } 290 } 291 break; 292 } 293 294 case B_SIMPLE_DATA: 295 { 296 D_MESSAGE(("MediaRoutingView::MessageDropped(B_SIMPLE_DATA)\n")); 297 entry_ref fileRef; 298 if (message->FindRef("refs", &fileRef) == B_OK) 299 _checkDroppedFile(&fileRef, ConvertFromScreen(message->DropPoint())); 300 break; 301 } 302 303 case B_PASTE: 304 { 305 D_MESSAGE(("MediaRoutingView::MessageDropped(B_PASTE)\n")); 306 ssize_t size; 307 const rgb_color *color; // [e.moon 21nov99] fixed const error 308 if (message->FindData("RGBColor", B_RGB_COLOR_TYPE, 309 reinterpret_cast<const void **>(&color), &size) == B_OK) 310 _changeBackground(*color); 311 break; 312 } 313 314 default: 315 DiagramView::MessageDropped(point, message); 316 } 317 } 318 319 320 void 321 MediaRoutingView::SelectionChanged() 322 { 323 D_METHOD(("MediaRoutingView::selectionChanged()\n")); 324 _broadcastSelection(); 325 } 326 327 // ---------------------------------------------------------------- // 328 // *** BView impl. 329 // ---------------------------------------------------------------- // 330 331 void MediaRoutingView::AttachedToWindow() 332 { 333 D_METHOD(("MediaRoutingView::AttachedToWindow()\n")); 334 _inherited::AttachedToWindow(); 335 336 // attach to manager 337 ASSERT(manager); 338 add_observer(this, manager); 339 340 // add the context-menu shortcuts to the window 341 _addShortcuts(); 342 343 // populate with existing nodes & connections 344 _initContent(); 345 346 // [e.moon 29nov99] moved from AllAttached() 347 cleanUp(); 348 } 349 350 void MediaRoutingView::AllAttached() 351 { 352 D_METHOD(("MediaRoutingView::AllAttached()\n")); 353 _inherited::AllAttached(); 354 355 _adjustScrollBars(); 356 357 // grab keyboard events 358 MakeFocus(); 359 } 360 361 void MediaRoutingView::DetachedFromWindow() 362 { 363 D_METHOD(("MediaRoutingView::DetachedFromWindow()\n")); 364 _inherited::DetachedFromWindow(); 365 366 // detach from manager 367 if (manager) 368 { 369 Autolock lock(manager); 370 void *cookie = 0; 371 NodeRef *ref; 372 while (manager->getNextRef(&ref, &cookie) == B_OK) 373 { 374 remove_observer(this, ref); 375 } 376 remove_observer(this, manager); 377 const_cast<RouteAppNodeManager *&>(manager) = 0; 378 } 379 } 380 381 void MediaRoutingView::KeyDown( 382 const char *bytes, 383 int32 numBytes) 384 { 385 D_METHOD(("MediaRoutingView::KeyDown()\n")); 386 387 switch (bytes[0]) 388 { 389 case B_ENTER: 390 { 391 D_KEY(("MediaRoutingView::KeyDown(B_ENTER)\n")); 392 _openParameterWindowsForSelection(); 393 break; 394 } 395 case B_DELETE: 396 { 397 D_KEY(("MediaRoutingView::KeyDown(B_DELETE)\n")); 398 _deleteSelection(); 399 break; 400 } 401 case B_SPACE: 402 { 403 // [e.moon 1dec99] 404 BWindow* w = Window(); 405 ASSERT(w); 406 BMessenger(w).SendMessage(RouteWindow::M_TOGGLE_GROUP_ROLLING); 407 break; 408 } 409 default: 410 { 411 DiagramView::KeyDown(bytes, numBytes); 412 break; 413 } 414 } 415 } 416 417 void MediaRoutingView::Pulse() 418 { 419 // do the animation 420 } 421 422 // ---------------------------------------------------------------- // 423 // BHandler impl 424 // ---------------------------------------------------------------- // 425 426 void MediaRoutingView::MessageReceived( 427 BMessage* message) 428 { 429 D_METHOD(("MediaRoutingView::MessageReceived()\n")); 430 431 switch (message->what) 432 { 433 case B_MEDIA_NODE_CREATED: 434 { 435 D_MESSAGE(("MediaRoutingView::MessageReceived(B_MEDIA_NODE_CREATED)\n")); 436 type_code type; 437 int32 count; 438 if (message->GetInfo("media_node_id", &type, &count) == B_OK) 439 { 440 for(int32 n = 0; n < count; n++) 441 { 442 int32 id; 443 if (message->FindInt32("media_node_id", n, &id) == B_OK) 444 { 445 // [e.moon 8dec99] allow for existing panel 446 MediaNodePanel* panel; 447 if(_findPanelFor(id, &panel) < B_OK) 448 _addPanelFor(id, BPoint(5.0, 5.0)); 449 } 450 } 451 } 452 break; 453 } 454 case B_MEDIA_NODE_DELETED: 455 { 456 D_MESSAGE(("MediaRoutingView::MessageReceived(B_MEDIA_NODE_DELETED)\n")); 457 type_code type; 458 int32 count; 459 if (message->GetInfo("media_node_id", &type, &count) == B_OK) 460 { 461 for (int32 n = 0; n < count; n++) 462 { 463 int32 id; 464 if (message->FindInt32("media_node_id", n, &id) == B_OK) 465 { 466 _removePanelFor(id); 467 } 468 } 469 } 470 break; 471 } 472 case B_MEDIA_CONNECTION_MADE: 473 { 474 D_MESSAGE(("MediaRoutingView::MessageReceived(B_MEDIA_CONNECTION_MADE)\n")); 475 type_code type; 476 int32 count; 477 if (message->GetInfo("output", &type, &count) == B_OK) 478 { 479 for (int32 n = 0; n < count; n++) 480 { 481 media_output output; 482 const void *data; 483 ssize_t dataSize; 484 if (message->FindData("output", B_RAW_TYPE, n, &data, &dataSize) == B_OK) 485 { 486 output = *reinterpret_cast<const media_output *>(data); 487 Connection connection; 488 if (manager->findConnection(output.node.node, output.source, &connection) == B_OK) 489 { 490 _addWireFor(connection); 491 } 492 } 493 } 494 } 495 break; 496 } 497 case B_MEDIA_CONNECTION_BROKEN: 498 { 499 D_MESSAGE(("MediaRoutingView::MessageReceived(B_MEDIA_CONNECTION_BROKEN)\n")); 500 type_code type; 501 int32 count; 502 if (message->GetInfo("__connection_id", &type, &count) == B_OK) 503 { 504 for (int32 n = 0; n < count; n++) 505 { 506 int32 id; 507 if (message->FindInt32("__connection_id", n, &id) == B_OK) 508 { 509 _removeWireFor(id); 510 } 511 } 512 } 513 break; 514 } 515 case B_MEDIA_FORMAT_CHANGED: 516 { 517 D_MESSAGE(("MediaRoutingView::MessageReceived(B_MEDIA_FORMAT_CHANGED)\n")); 518 519 media_node_id nodeID; 520 if(message->FindInt32("__source_node_id", &nodeID) < B_OK) 521 break; 522 523 uint32 connectionID; 524 if(message->FindInt32("__connection_id", (int32*)&connectionID) < B_OK) 525 break; 526 527 media_source* source; 528 ssize_t dataSize; 529 if(message->FindData("be:source", B_RAW_TYPE, (const void**)&source, &dataSize) < B_OK) 530 break; 531 532 MediaWire* wire; 533 if(_findWireFor(connectionID, &wire) == B_OK) { 534 // copy new connection data 535 manager->findConnection(nodeID, *source, &wire->connection); 536 } 537 break; 538 } 539 case M_CLEANUP_REQUESTED: 540 { 541 D_MESSAGE(("MediaRoutingView::MessageReceived(M_M_CLEANUP_REQUESTED)\n")); 542 cleanUp(); 543 break; 544 } 545 case M_SELECT_ALL: 546 { 547 D_MESSAGE(("MediaRoutingView::MessageReceived(M_SELECT_ALL)\n")); 548 SelectAll(DiagramItem::M_BOX); 549 break; 550 } 551 case M_DELETE_SELECTION: 552 { 553 D_MESSAGE(("MediaRoutingView::MessageReceived(M_DELETE_SELECTION)\n")); 554 _deleteSelection(); 555 break; 556 } 557 case M_NODE_CHANGE_CYCLING: 558 { 559 D_MESSAGE(("MediaRoutingView::MessageReceived(M_NODE_CYCLING_CHANGED)\n")); 560 bool cycle; 561 if (message->FindBool("cycle", &cycle) == B_OK) 562 { 563 _changeCyclingForSelection(cycle); 564 } 565 break; 566 } 567 case M_NODE_CHANGE_RUN_MODE: 568 { 569 D_MESSAGE(("MediaRoutingView::MessageReceived(M_NODE_RUNMODE_CHANGED)\n")); 570 int32 mode; 571 if (message->FindInt32("run_mode", &mode) == B_OK) 572 { 573 _changeRunModeForSelection(static_cast<uint32>(mode)); 574 } 575 break; 576 } 577 case M_LAYOUT_CHANGED: 578 { 579 D_MESSAGE(("MediaRoutingView::MessageReceived(M_LAYOUT_CHANGED)\n")); 580 layout_t layout; 581 if (message->FindInt32("layout", (int32*)&layout) == B_OK) 582 { 583 if (layout != m_layout) 584 { 585 layoutChanged(layout); 586 updateDataRect(); 587 Invalidate(); 588 } 589 } 590 break; 591 } 592 case M_NODE_START_TIME_SOURCE: 593 { 594 D_MESSAGE(("MediaRoutingView::MessageReceived(M_NODE_START_TIME_SOURCE)\n")); 595 int32 id; 596 if(message->FindInt32("nodeID", &id) < B_OK) 597 break; 598 NodeRef* ref; 599 if(manager->getNodeRef(id, &ref) < B_OK) 600 break; 601 602 bigtime_t when = system_time(); 603 status_t err = manager->roster->StartTimeSource(ref->node(), when); 604 if(err < B_OK) { 605 PRINT(( 606 "! StartTimeSource(%" B_PRId32 "): '%s'\n", 607 ref->id(), strerror(err))); 608 } 609 break; 610 } 611 case M_NODE_STOP_TIME_SOURCE: 612 { 613 D_MESSAGE(("MediaRoutingView::MessageReceived(M_NODE_STOP_TIME_SOURCE)\n")); 614 int32 id; 615 if(message->FindInt32("nodeID", &id) < B_OK) 616 break; 617 NodeRef* ref; 618 if(manager->getNodeRef(id, &ref) < B_OK) 619 break; 620 621 bigtime_t when = system_time(); 622 status_t err = manager->roster->StopTimeSource(ref->node(), when); 623 if(err < B_OK) { 624 PRINT(( 625 "! StopTimeSource(%" B_PRId32 "): '%s'\n", 626 ref->id(), strerror(err))); 627 } 628 break; 629 } 630 case M_NODE_TWEAK_PARAMETERS: { 631 D_MESSAGE((" -> M_NODE_TWEAK_PARAMETERS\n")); 632 _openParameterWindowsForSelection(); 633 break; 634 } 635 case M_NODE_START_CONTROL_PANEL: { 636 D_MESSAGE((" -> M_NODE_START_CONTROL_PANEL\n")); 637 _startControlPanelsForSelection(); 638 break; 639 } 640 case M_GROUP_SET_LOCKED: 641 { 642 D_MESSAGE(("MediaRoutingView::MessageReceived(M_GROUP_SET_LOCKED)\n")); 643 int32 groupID; 644 if(message->FindInt32("groupID", &groupID) < B_OK) 645 break; 646 bool locked; 647 if(message->FindBool("locked", &locked) < B_OK) 648 break; 649 NodeGroup* group; 650 if(manager->findGroup(groupID, &group) < B_OK) 651 break; 652 uint32 f = locked ? 653 group->groupFlags() | NodeGroup::GROUP_LOCKED : 654 group->groupFlags() & ~NodeGroup::GROUP_LOCKED; 655 group->setGroupFlags(f); 656 break; 657 } 658 case M_BROADCAST_SELECTION: { 659 D_MESSAGE((" -> M_BROADCAST_SELECTION\n")); 660 _broadcastSelection(); 661 break; 662 } 663 case InfoWindowManager::M_INFO_WINDOW_REQUESTED: 664 { 665 D_MESSAGE(("MediaRoutingView::MessageReceived(InfoView::M_INFO_WINDOW_REQUESTED)\n")); 666 type_code type; 667 int32 count; 668 if (message->GetInfo("input", &type, &count) == B_OK) 669 { 670 for (int32 i = 0; i < count; i++) 671 { 672 media_input input; 673 const void *data; 674 ssize_t dataSize; 675 if (message->FindData("input", B_RAW_TYPE, i, &data, &dataSize) == B_OK) 676 { 677 input = *reinterpret_cast<const media_input *>(data); 678 InfoWindowManager *manager = InfoWindowManager::Instance(); 679 if (manager && manager->Lock()) { 680 manager->openWindowFor(input); 681 manager->Unlock(); 682 } 683 } 684 } 685 } 686 else if (message->GetInfo("output", &type, &count) == B_OK) 687 { 688 for (int32 i = 0; i < count; i++) 689 { 690 media_output output; 691 const void *data; 692 ssize_t dataSize; 693 if (message->FindData("output", B_RAW_TYPE, i, &data, &dataSize) == B_OK) 694 { 695 output = *reinterpret_cast<const media_output *>(data); 696 InfoWindowManager *manager = InfoWindowManager::Instance(); 697 if (manager && manager->Lock()) { 698 manager->openWindowFor(output); 699 manager->Unlock(); 700 } 701 } 702 } 703 } 704 else 705 { 706 _openInfoWindowsForSelection(); 707 } 708 break; 709 } 710 case NodeManager::M_RELEASED: 711 { 712 D_MESSAGE(("MediaRoutingView::MessageReceived(NodeManager::M_RELEASED)\n")); 713 remove_observer(this, manager); 714 const_cast<RouteAppNodeManager*&>(manager) = 0; 715 // +++++ disable view! 716 break; 717 } 718 case NodeRef::M_RELEASED: 719 { 720 D_MESSAGE(("MediaRoutingView::MessageReceived(NodeRef::M_RELEASED)\n")); 721 // only relevant on shutdown; do nothing 722 break; 723 } 724 default: 725 { 726 DiagramView::MessageReceived(message); 727 } 728 } 729 } 730 731 // ---------------------------------------------------------------- // 732 // *** operations (public) 733 // ---------------------------------------------------------------- // 734 735 BPoint MediaRoutingView::findFreePositionFor( 736 const MediaNodePanel* panel) const 737 { 738 D_METHOD(("MediaRoutingView::_findFreeSpotFor()\n")); 739 740 BPoint p(M_CLEANUP_H_MARGIN, M_CLEANUP_V_MARGIN); 741 if (panel) 742 { 743 switch (m_layout) 744 { 745 case M_ICON_VIEW: 746 { 747 // find the target column by node_kind 748 p.x += M_CLEANUP_H_GAP + MediaNodePanel::M_DEFAULT_WIDTH; 749 if (panel->ref->kind() & B_BUFFER_PRODUCER) 750 { 751 p.x -= M_CLEANUP_H_GAP + MediaNodePanel::M_DEFAULT_WIDTH; 752 } 753 if (panel->ref->kind() & B_BUFFER_CONSUMER) 754 { 755 p.x += M_CLEANUP_H_GAP + MediaNodePanel::M_DEFAULT_WIDTH; 756 } 757 // find the bottom item in the column 758 float bottom = 0.0; 759 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) 760 { 761 BRect r = ItemAt(i, DiagramItem::M_BOX)->Frame(); 762 if ((r.left >= p.x) 763 && (r.left <= p.x + MediaNodePanel::M_DEFAULT_WIDTH)) 764 { 765 bottom = (r.bottom > bottom) ? r.bottom : bottom; 766 } 767 } 768 if (bottom >= p.y) 769 { 770 p.y = bottom + M_CLEANUP_V_GAP; 771 } 772 break; 773 } 774 case M_MINI_ICON_VIEW: 775 { 776 // find the target row by node_kind 777 p.y += M_CLEANUP_V_GAP + MediaNodePanel::M_DEFAULT_HEIGHT; 778 if (panel->ref->kind() & B_BUFFER_PRODUCER) 779 { 780 p.y -= M_CLEANUP_V_GAP + MediaNodePanel::M_DEFAULT_HEIGHT; 781 } 782 if (panel->ref->kind() & B_BUFFER_CONSUMER) 783 { 784 p.y += M_CLEANUP_V_GAP + MediaNodePanel::M_DEFAULT_HEIGHT; 785 } 786 // find the right-most item in the row 787 float right = 0.0; 788 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) 789 { 790 BRect r = ItemAt(i, DiagramItem::M_BOX)->Frame(); 791 if ((r.top >= p.y) 792 && (r.top <= p.y + MediaNodePanel::M_DEFAULT_HEIGHT)) 793 { 794 right = (r.right > right) ? r.right : right; 795 } 796 } 797 if (right >= p.x) 798 { 799 p.x = right + M_CLEANUP_H_GAP; 800 } 801 break; 802 } 803 } 804 } 805 return p; 806 } 807 808 // ---------------------------------------------------------------- // 809 // *** operations (protected) 810 // ---------------------------------------------------------------- // 811 812 void MediaRoutingView::layoutChanged( 813 layout_t layout) 814 { 815 D_METHOD(("MediaRoutingView::layoutChanged()\n")); 816 817 switch (layout) 818 { 819 case M_ICON_VIEW: 820 { 821 float temp; 822 823 // swap the cleanup defaults 824 temp = M_CLEANUP_H_GAP; 825 M_CLEANUP_H_GAP = M_CLEANUP_V_GAP; 826 M_CLEANUP_V_GAP = temp; 827 temp = M_CLEANUP_H_MARGIN; 828 M_CLEANUP_H_MARGIN = M_CLEANUP_V_MARGIN; 829 M_CLEANUP_V_MARGIN = temp; 830 831 // swap the default dimensions for MediaJacks 832 temp = MediaJack::M_DEFAULT_WIDTH; 833 MediaJack::M_DEFAULT_WIDTH = MediaJack::M_DEFAULT_HEIGHT; 834 MediaJack::M_DEFAULT_HEIGHT = temp; 835 836 // Add space for the 3-letter i/o-abbreviation 837 BFont font(be_plain_font); 838 font.SetSize(font.Size() - 2.0); 839 for (int i = 0; i < MediaJack::M_MAX_ABBR_LENGTH; i++) 840 { 841 MediaJack::M_DEFAULT_WIDTH += font.StringWidth("M"); 842 } 843 MediaJack::M_DEFAULT_WIDTH += 2.0; // add some padding 844 845 // Adjust the default size for MediaNodePanels 846 float labelWidth, bodyWidth; 847 float labelHeight, bodyHeight; 848 font_height fh; 849 be_plain_font->GetHeight(&fh); 850 labelWidth = 4 * MediaNodePanel::M_LABEL_H_MARGIN 851 + be_plain_font->StringWidth(" Be Audio Mixer "); 852 bodyWidth = 2 * MediaNodePanel::M_BODY_H_MARGIN + B_LARGE_ICON 853 + 2 * MediaJack::M_DEFAULT_WIDTH; 854 labelHeight = 2 * MediaNodePanel::M_LABEL_V_MARGIN 855 + fh.ascent + fh.descent + fh.leading + 1.0; 856 bodyHeight = 2 * MediaNodePanel::M_BODY_V_MARGIN + B_LARGE_ICON; 857 MediaNodePanel::M_DEFAULT_WIDTH = labelWidth > bodyWidth ? labelWidth : bodyWidth; 858 MediaNodePanel::M_DEFAULT_HEIGHT = labelHeight + bodyHeight; 859 Align(&MediaNodePanel::M_DEFAULT_WIDTH, &MediaNodePanel::M_DEFAULT_HEIGHT); 860 break; 861 } 862 case M_MINI_ICON_VIEW: 863 { 864 float temp; 865 866 // Swap the cleanup defaults 867 temp = M_CLEANUP_H_GAP; 868 M_CLEANUP_H_GAP = M_CLEANUP_V_GAP; 869 M_CLEANUP_V_GAP = temp; 870 temp = M_CLEANUP_H_MARGIN; 871 M_CLEANUP_H_MARGIN = M_CLEANUP_V_MARGIN; 872 M_CLEANUP_V_MARGIN = temp; 873 874 // Subtract space for the 3-letter i/o-abbreviation 875 BFont font(be_plain_font); 876 font.SetSize(font.Size() - 2.0); 877 for (int i = 0; i < MediaJack::M_MAX_ABBR_LENGTH; i++) 878 { 879 MediaJack::M_DEFAULT_WIDTH -= font.StringWidth("M"); 880 } 881 MediaJack::M_DEFAULT_WIDTH -= 2.0; // substract the padding 882 883 // Swap the default dimensions for MediaJacks 884 temp = MediaJack::M_DEFAULT_WIDTH; 885 MediaJack::M_DEFAULT_WIDTH = MediaJack::M_DEFAULT_HEIGHT; 886 MediaJack::M_DEFAULT_HEIGHT = temp; 887 888 // Adjust the default size for MediaNodePanels 889 float labelWidth, bodyWidth; 890 float labelHeight, bodyHeight; 891 font_height fh; 892 be_plain_font->GetHeight(&fh); 893 labelWidth = 4 * MediaNodePanel::M_LABEL_H_MARGIN 894 + be_plain_font->StringWidth(" Be Audio Mixer "); 895 bodyWidth = 2 * MediaNodePanel::M_BODY_H_MARGIN + B_MINI_ICON; 896 labelHeight = 3 * MediaNodePanel::M_LABEL_V_MARGIN 897 + fh.ascent + fh.descent + fh.leading 898 + 2 * MediaJack::M_DEFAULT_HEIGHT; 899 bodyHeight = 2 * MediaNodePanel::M_BODY_V_MARGIN + B_MINI_ICON; 900 MediaNodePanel::M_DEFAULT_WIDTH = labelWidth + bodyWidth; 901 MediaNodePanel::M_DEFAULT_HEIGHT = labelHeight > bodyHeight ? labelHeight : bodyHeight; 902 Align(&MediaNodePanel::M_DEFAULT_WIDTH, &MediaNodePanel::M_DEFAULT_HEIGHT); 903 break; 904 } 905 } 906 m_layout = layout; 907 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) 908 { 909 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(ItemAt(i, DiagramItem::M_BOX)); 910 if (panel) 911 { 912 panel->layoutChanged(layout); 913 } 914 } 915 916 _adjustScrollBars(); 917 } 918 919 void MediaRoutingView::cleanUp() 920 { 921 D_METHOD(("MediaRoutingView::cleanUp()\n")); 922 923 SortItems(DiagramItem::M_BOX, compareID); 924 925 // move all the panels offscreen 926 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) 927 { 928 ItemAt(i, DiagramItem::M_BOX)->moveTo(BPoint(-200.0, -200.0)); 929 } 930 931 // move all panels to their 'ideal' position 932 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) 933 { 934 MediaNodePanel *panel; 935 panel = dynamic_cast<MediaNodePanel *>(ItemAt(i, DiagramItem::M_BOX)); 936 BPoint p = findFreePositionFor(panel); 937 panel->moveTo(p); 938 } 939 940 SortItems(DiagramItem::M_BOX, compareSelectionTime); 941 Invalidate(); 942 updateDataRect(); 943 } 944 945 void MediaRoutingView::showContextMenu( 946 BPoint point) 947 { 948 D_METHOD(("MediaRoutingView::showContextMenu()\n")); 949 950 BPopUpMenu *menu = new BPopUpMenu("MediaRoutingView PopUp", false, false, B_ITEMS_IN_COLUMN); 951 menu->SetFont(be_plain_font); 952 953 // add layout options 954 BMenuItem *item; 955 BMessage *message = new BMessage(M_LAYOUT_CHANGED); 956 message->AddInt32("layout", M_ICON_VIEW); 957 menu->AddItem(item = new BMenuItem(B_TRANSLATE("Icon view"), message)); 958 if (m_layout == M_ICON_VIEW) 959 { 960 item->SetMarked(true); 961 } 962 message = new BMessage(M_LAYOUT_CHANGED); 963 message->AddInt32("layout", M_MINI_ICON_VIEW); 964 menu->AddItem(item = new BMenuItem(B_TRANSLATE("Mini icon view"), message)); 965 if (m_layout == M_MINI_ICON_VIEW) 966 { 967 item->SetMarked(true); 968 } 969 menu->AddSeparatorItem(); 970 971 // add 'CleanUp' command 972 menu->AddItem(new BMenuItem(B_TRANSLATE("Clean up"), 973 new BMessage(M_CLEANUP_REQUESTED), 'K')); 974 975 // add 'Select All' command 976 menu->AddItem(new BMenuItem(B_TRANSLATE("Select all"), 977 new BMessage(M_SELECT_ALL), 'A')); 978 979 menu->SetTargetForItems(this); 980 ConvertToScreen(&point); 981 point -= BPoint(1.0, 1.0); 982 menu->Go(point, true, true, true); 983 } 984 985 void MediaRoutingView::showErrorMessage( 986 BString text, 987 status_t error) 988 { 989 D_METHOD(("MediaRoutingView::showErrorMessage()\n")); 990 991 if (error) { 992 text << " (" << strerror(error) << ")"; 993 } 994 995 BMessage message(M_SHOW_ERROR_MESSAGE); 996 message.AddString("text", text.String()); 997 if (error) { 998 message.AddBool("error", true); 999 } 1000 BMessenger messenger(0, Window()); 1001 if (!messenger.IsValid() 1002 || (messenger.SendMessage(&message) != B_OK)) { 1003 BAlert *alert = new BAlert(B_TRANSLATE("Error"), text.String(), 1004 B_TRANSLATE("OK"), 0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 1005 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 1006 alert->Go(); 1007 } 1008 } 1009 1010 // -------------------------------------------------------- // 1011 // *** IStateArchivable 1012 // -------------------------------------------------------- // 1013 1014 status_t MediaRoutingView::importState( 1015 const BMessage* archive) { 1016 1017 status_t err; 1018 1019 _emptyInactiveNodeState(); 1020 1021 layout_t layout; 1022 err = archive->FindInt32("layout", (int32*)&layout); 1023 if(err == B_OK && layout != m_layout) { 1024 layoutChanged(layout); 1025 } 1026 1027 const char* path; 1028 err = archive->FindString("bgBitmap", &path); 1029 if(err == B_OK) { 1030 BEntry entry(path); 1031 entry_ref ref; 1032 err = entry.GetRef(&ref); 1033 if(err == B_OK) 1034 _changeBackground(&ref); 1035 } 1036 else { 1037 rgb_color color; 1038 color.alpha = 255; 1039 if( 1040 archive->FindInt8("bgRed", (int8*)&color.red) == B_OK && 1041 archive->FindInt8("bgGreen", (int8*)&color.green) == B_OK && 1042 archive->FindInt8("bgBlue", (int8*)&color.blue) == B_OK) 1043 _changeBackground(color); 1044 } 1045 1046 for(int32 n = 0; ; ++n) { 1047 1048 // find panel state info; stop when exhausted 1049 BMessage m; 1050 err = archive->FindMessage("panel", n, &m); 1051 if(err < B_OK) 1052 break; 1053 1054 const char* nodeName; 1055 err = archive->FindString("nodeName", n, &nodeName); 1056 if(err < B_OK) 1057 break; 1058 1059 uint32 nodeKind; 1060 err = archive->FindInt32("nodeKind", n, (int32*)&nodeKind); 1061 if(err < B_OK) 1062 break; 1063 1064 // look up matching panel +++++ SLOW +++++ 1065 uint32 panelIndex; 1066 uint32 items = CountItems(DiagramItem::M_BOX); 1067 for( 1068 panelIndex = 0; 1069 panelIndex < items; 1070 ++panelIndex) { 1071 1072 MediaNodePanel* panel = dynamic_cast<MediaNodePanel*>( 1073 ItemAt(panelIndex, DiagramItem::M_BOX)); 1074 1075 if(panel && 1076 !strcmp(panel->ref->name(), nodeName) && 1077 panel->ref->kind() == nodeKind) { 1078 1079 // found match; hand message to panel 1080 panel->importState(&m); 1081 break; 1082 } 1083 } 1084 if(panelIndex == items) { 1085 // no panel found 1086 // if a "system node" hang onto (and re-export) state info 1087 bool sysOwned; 1088 if(m.FindBool("sysOwned", &sysOwned) == B_OK && sysOwned) { 1089 m_inactiveNodeState.AddItem( 1090 new _inactive_node_state_entry( 1091 nodeName, nodeKind, m)); 1092 } 1093 } 1094 } 1095 1096 updateDataRect(); 1097 1098 return B_OK; 1099 } 1100 1101 // +++++ export state info for currently inactive system nodes +++++ 1102 status_t MediaRoutingView::exportState( 1103 BMessage* archive) const { 1104 1105 // store layout mode 1106 archive->AddInt32("layout", m_layout); 1107 1108 // store background settings 1109 if(m_backgroundBitmapEntry.InitCheck() == B_OK) { 1110 BPath path; 1111 m_backgroundBitmapEntry.GetPath(&path); 1112 archive->AddString("bgBitmap", path.Path()); 1113 } else { 1114 rgb_color c = backgroundColor(); 1115 archive->AddInt8("bgRed", c.red); 1116 archive->AddInt8("bgGreen", c.green); 1117 archive->AddInt8("bgBlue", c.blue); 1118 } 1119 1120 // store panel positions w/ node names & signatures 1121 for(uint32 n = 0; n < CountItems(DiagramItem::M_BOX); ++n) { 1122 MediaNodePanel* panel = dynamic_cast<MediaNodePanel*>( 1123 ItemAt(n, DiagramItem::M_BOX)); 1124 if(!panel) 1125 continue; 1126 1127 if(panel->ref->isInternal()) 1128 // skip internal nodes 1129 continue; 1130 1131 BMessage m; 1132 panel->exportState(&m); 1133 archive->AddString("nodeName", panel->ref->name()); 1134 archive->AddInt32("nodeKind", panel->ref->kind()); 1135 archive->AddMessage("panel", &m); 1136 } 1137 1138 // copy inactive node state info 1139 for(int32 n = 0; n < m_inactiveNodeState.CountItems(); ++n) { 1140 _inactive_node_state_entry* e = reinterpret_cast<_inactive_node_state_entry*>( 1141 m_inactiveNodeState.ItemAt(n)); 1142 1143 archive->AddString("nodeName", e->name.String()); 1144 archive->AddInt32("nodeKind", e->kind); 1145 archive->AddMessage("panel", &e->state); 1146 } 1147 1148 return B_OK; 1149 } 1150 1151 // [e.moon 8dec99] subset support 1152 1153 status_t MediaRoutingView::importStateFor( 1154 const NodeSetIOContext* context, 1155 const BMessage* archive) { 1156 1157 status_t err; 1158 1159 for(int32 archiveIndex = 0;; ++archiveIndex) { 1160 1161 // fetch archived key & panel data 1162 const char* key; 1163 err = archive->FindString("nodeKey", archiveIndex, &key); 1164 if(err < B_OK) 1165 break; 1166 1167 BMessage m; 1168 err = archive->FindMessage("panel", archiveIndex, &m); 1169 if(err < B_OK) { 1170 PRINT(( 1171 "!!! MediaRoutingView::importStateFor(): missing panel %" 1172 B_PRId32 "\n", archiveIndex)); 1173 continue; 1174 } 1175 1176 // find corresponding node 1177 media_node_id id; 1178 err = context->getNodeFor(key, &id); 1179 if(err < B_OK) { 1180 PRINT(( 1181 "!!! MediaRoutingView::importStateFor(): missing node '%s'\n", 1182 key)); 1183 continue; 1184 } 1185 1186 // look for panel, create it if necessary 1187 MediaNodePanel* panel; 1188 err = _findPanelFor(id, &panel); 1189 if(err < B_OK) { 1190 // create it 1191 err = _addPanelFor( 1192 id, 1193 BPoint(5.0, 5.0)); 1194 if(err < B_OK) { 1195 PRINT(( 1196 "!!! MediaRoutingView::importStateFor(): _addPanelFor():\n" 1197 " %s\n", strerror(err))); 1198 continue; 1199 } 1200 1201 err = _findPanelFor(id, &panel); 1202 if(err < B_OK) { 1203 PRINT(( 1204 "!!! MediaRoutingView::importStateFor(): _findPanelFor():\n" 1205 " %s\n", strerror(err))); 1206 continue; 1207 } 1208 } 1209 1210 // pass state data along 1211 panel->importState(&m); 1212 1213 // select the panel 1214 SelectItem(panel, false); 1215 } 1216 1217 return B_OK; 1218 } 1219 1220 status_t MediaRoutingView::exportStateFor( 1221 const NodeSetIOContext* context, 1222 BMessage* archive) const { 1223 1224 status_t err; 1225 1226 for(uint32 n = 0; n < context->countNodes(); ++n) { 1227 MediaNodePanel* panel; 1228 err = _findPanelFor( 1229 context->nodeAt(n), 1230 &panel); 1231 if(err < B_OK) { 1232 PRINT(( 1233 "!!! MediaRoutingView::exportStateFor():\n" 1234 " no panel for node %" B_PRId32 "\n", 1235 context->nodeAt(n))); 1236 return B_BAD_VALUE; 1237 } 1238 1239 const char* key = context->keyAt(n); 1240 1241 archive->AddString("nodeKey", key); 1242 BMessage m; 1243 panel->exportState(&m); 1244 archive->AddMessage("panel", &m); 1245 } 1246 1247 return B_OK; 1248 } 1249 1250 // -------------------------------------------------------- // 1251 // *** children management 1252 // -------------------------------------------------------- // 1253 1254 status_t MediaRoutingView::_addPanelFor( 1255 media_node_id id, 1256 BPoint atPoint) 1257 { 1258 D_METHOD(("MediaRoutingView::_addPanelFor()\n")); 1259 1260 manager->lock(); 1261 NodeRef *ref; 1262 status_t error = manager->getNodeRef(id, &ref); 1263 manager->unlock(); 1264 if (!error) 1265 { 1266 add_observer(this, ref); 1267 MediaNodePanel *panel = 0; 1268 if (id == m_lastDroppedNode) // this was instantiated thru drag & drop 1269 { 1270 AddItem(panel = new MediaNodePanel(m_lastDropPoint, ref)); 1271 SelectItem(panel, true); 1272 m_lastDroppedNode = 0; 1273 } 1274 else // this was an externally created node, must find a nice position first 1275 { 1276 panel = new MediaNodePanel(BPoint(0.0, 0.0), ref); 1277 AddItem(panel); 1278 BMessage state; 1279 if(_fetchInactiveNodeState(panel, &state) == B_OK) 1280 panel->importState(&state); 1281 else { 1282 BPoint p = findFreePositionFor(panel); 1283 panel->moveTo(p); 1284 } 1285 Invalidate(panel->Frame()); 1286 } 1287 } 1288 updateDataRect(); 1289 return error; 1290 } 1291 1292 status_t MediaRoutingView::_findPanelFor( 1293 media_node_id id, 1294 MediaNodePanel **outPanel) const 1295 { 1296 D_METHOD(("MediaRoutingView::_findPanelFor()\n")); 1297 1298 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) 1299 { 1300 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(ItemAt(i, DiagramItem::M_BOX)); 1301 if (panel) 1302 { 1303 if (panel->ref->id() == id) 1304 { 1305 *outPanel = panel; 1306 return B_OK; 1307 } 1308 } 1309 } 1310 return B_ERROR; 1311 } 1312 1313 status_t MediaRoutingView::_removePanelFor( 1314 media_node_id id) 1315 { 1316 D_METHOD(("MediaRoutingView::_removePanelFor()\n")); 1317 1318 MediaNodePanel *panel; 1319 if (_findPanelFor(id, &panel) == B_OK) 1320 { 1321 if (RemoveItem(panel)) 1322 { 1323 remove_observer(this, panel->ref); 1324 Invalidate(panel->Frame()); 1325 delete panel; 1326 return B_OK; 1327 } 1328 } 1329 return B_ERROR; 1330 } 1331 1332 status_t MediaRoutingView::_addWireFor( 1333 Connection& connection) 1334 { 1335 D_METHOD(("MediaRoutingView::_addWireFor()\n")); 1336 1337 MediaNodePanel *source, *destination; 1338 if ((_findPanelFor(connection.sourceNode(), &source) == B_OK) 1339 && (_findPanelFor(connection.destinationNode(), &destination) == B_OK)) 1340 { 1341 status_t error; 1342 1343 media_output output; 1344 error = connection.getOutput(&output); 1345 if (error) 1346 { 1347 return error; 1348 } 1349 MediaJack *outputJack = new MediaJack(output); 1350 source->AddItem(outputJack); 1351 1352 media_input input; 1353 error = connection.getInput(&input); 1354 if (error) 1355 { 1356 return error; 1357 } 1358 MediaJack *inputJack = new MediaJack(input); 1359 destination->AddItem(inputJack); 1360 1361 MediaWire *wire = new MediaWire(connection, outputJack, inputJack); 1362 AddItem(wire); 1363 source->updateIOJacks(); 1364 source->arrangeIOJacks(); 1365 destination->updateIOJacks(); 1366 destination->arrangeIOJacks(); 1367 updateDataRect(); 1368 1369 // [e.moon 21nov99] group creation/merging now performed by 1370 // RouteAppNodeManager 1371 1372 Invalidate(source->Frame()); 1373 Invalidate(destination->Frame()); 1374 Invalidate(wire->Frame()); 1375 return B_OK; 1376 } 1377 else 1378 { 1379 return B_ERROR; 1380 } 1381 } 1382 1383 status_t MediaRoutingView::_findWireFor( 1384 uint32 connectionID, 1385 MediaWire **outWire) const 1386 { 1387 D_METHOD(("MediaRoutingView::_findWireFor()\n")); 1388 1389 for (uint32 i = 0; i < CountItems(DiagramItem::M_WIRE); i++) 1390 { 1391 MediaWire *wire = dynamic_cast<MediaWire *>(ItemAt(i, DiagramItem::M_WIRE)); 1392 if (wire && wire->connection.id() == connectionID) 1393 { 1394 *outWire = wire; 1395 return B_OK; 1396 } 1397 } 1398 return B_ERROR; 1399 } 1400 1401 status_t MediaRoutingView::_removeWireFor( 1402 uint32 connectionID) 1403 { 1404 D_METHOD(("MediaRoutingView::_removeWireFor()\n")); 1405 1406 MediaWire *wire; 1407 if (_findWireFor(connectionID, &wire) == B_OK) 1408 { 1409 MediaNodePanel *source, *destination; 1410 _findPanelFor(wire->connection.sourceNode(), &source); 1411 _findPanelFor(wire->connection.destinationNode(), &destination); 1412 RemoveItem(wire); 1413 Invalidate(wire->Frame()); 1414 delete wire; 1415 if (source) 1416 { 1417 source->updateIOJacks(); 1418 source->arrangeIOJacks(); 1419 Invalidate(source->Frame()); 1420 } 1421 if (destination) 1422 { 1423 destination->updateIOJacks(); 1424 destination->arrangeIOJacks(); 1425 Invalidate(destination->Frame()); 1426 } 1427 1428 // [e.moon 21nov99] group split/remove now performed by 1429 // RouteAppNodeManager 1430 1431 updateDataRect(); 1432 return B_OK; 1433 } 1434 return B_ERROR; 1435 } 1436 1437 // -------------------------------------------------------- // 1438 // *** internal methods 1439 // -------------------------------------------------------- // 1440 1441 void MediaRoutingView::_addShortcuts() 1442 { 1443 Window()->AddShortcut('A', B_COMMAND_KEY, 1444 new BMessage(M_SELECT_ALL), this); 1445 Window()->AddShortcut('K', B_COMMAND_KEY, 1446 new BMessage(M_CLEANUP_REQUESTED), this); 1447 Window()->AddShortcut('T', B_COMMAND_KEY, 1448 new BMessage(M_DELETE_SELECTION), this); 1449 Window()->AddShortcut('P', B_COMMAND_KEY, 1450 new BMessage(M_NODE_TWEAK_PARAMETERS), this); 1451 Window()->AddShortcut('P', B_COMMAND_KEY | B_SHIFT_KEY, 1452 new BMessage(M_NODE_START_CONTROL_PANEL), this); 1453 Window()->AddShortcut('I', B_COMMAND_KEY, 1454 new BMessage(InfoWindowManager::M_INFO_WINDOW_REQUESTED), this); 1455 } 1456 1457 void MediaRoutingView::_initLayout() 1458 { 1459 D_METHOD(("MediaRoutingView::_initLayout()\n")); 1460 1461 BString measure; 1462 measure << " " << B_TRANSLATE("Be Audio Mixer") << " "; 1463 1464 switch (m_layout) 1465 { 1466 case M_ICON_VIEW: 1467 { 1468 // Adjust the jack width for displaying the abbreviated 1469 // input/output name 1470 BFont font(be_plain_font); 1471 font.SetSize(font.Size() - 2.0); 1472 for (int i = 0; i < MediaJack::M_MAX_ABBR_LENGTH; i++) 1473 { 1474 MediaJack::M_DEFAULT_WIDTH += font.StringWidth("M"); 1475 } 1476 MediaJack::M_DEFAULT_WIDTH += 2.0; // add some padding 1477 1478 // Adjust the default size for MediaNodePanels to fit the 1479 // size of be_plain_font 1480 float labelWidth, bodyWidth; 1481 float labelHeight, bodyHeight; 1482 font_height fh; 1483 be_plain_font->GetHeight(&fh); 1484 labelWidth = 4 * MediaNodePanel::M_LABEL_H_MARGIN 1485 + be_plain_font->StringWidth(measure.String()); 1486 bodyWidth = 2 * MediaNodePanel::M_BODY_H_MARGIN + B_LARGE_ICON 1487 + 2 * MediaJack::M_DEFAULT_WIDTH; 1488 labelHeight = 2 * MediaNodePanel::M_LABEL_V_MARGIN 1489 + fh.ascent + fh.descent + fh.leading + 1.0; 1490 bodyHeight = 2 * MediaNodePanel::M_BODY_V_MARGIN + B_LARGE_ICON; 1491 MediaNodePanel::M_DEFAULT_WIDTH = labelWidth > bodyWidth ? labelWidth : bodyWidth; 1492 MediaNodePanel::M_DEFAULT_HEIGHT = labelHeight + bodyHeight; 1493 Align(&MediaNodePanel::M_DEFAULT_WIDTH, &MediaNodePanel::M_DEFAULT_HEIGHT); 1494 1495 // Adjust the cleanup settings 1496 M_CLEANUP_H_GAP += MediaNodePanel::M_DEFAULT_WIDTH; 1497 break; 1498 } 1499 case M_MINI_ICON_VIEW: 1500 { 1501 // Adjust the default size for MediaNodePanels to fit the 1502 // size of be_plain_font 1503 float labelWidth, bodyWidth; 1504 float labelHeight, bodyHeight; 1505 font_height fh; 1506 be_plain_font->GetHeight(&fh); 1507 labelWidth = 4 * MediaNodePanel::M_LABEL_H_MARGIN 1508 + be_plain_font->StringWidth(measure.String()); 1509 bodyWidth = 2 * MediaNodePanel::M_BODY_H_MARGIN + B_MINI_ICON; 1510 labelHeight = 3 * MediaNodePanel::M_LABEL_V_MARGIN 1511 + fh.ascent + fh.descent + fh.leading 1512 + 2 * MediaJack::M_DEFAULT_HEIGHT; 1513 bodyHeight = 2 * MediaNodePanel::M_BODY_V_MARGIN + B_MINI_ICON; 1514 MediaNodePanel::M_DEFAULT_WIDTH = labelWidth + bodyWidth; 1515 MediaNodePanel::M_DEFAULT_HEIGHT = labelHeight > bodyHeight ? labelHeight : bodyHeight; 1516 Align(&MediaNodePanel::M_DEFAULT_WIDTH, &MediaNodePanel::M_DEFAULT_HEIGHT); 1517 1518 // Adjust the cleanup settings 1519 M_CLEANUP_V_GAP += MediaNodePanel::M_DEFAULT_HEIGHT; 1520 break; 1521 } 1522 } 1523 } 1524 1525 void MediaRoutingView::_initContent() 1526 { 1527 D_METHOD(("MediaRoutingView::_initContent()\n")); 1528 1529 Autolock lock(manager); 1530 1531 void *cookie = 0; 1532 NodeRef *ref; 1533 while (manager->getNextRef(&ref, &cookie) == B_OK) 1534 { 1535 // add self as observer 1536 add_observer(this, ref); 1537 // create & place node view (+++++ defer until observer status confirmed!) 1538 _addPanelFor(ref->id(), BPoint(M_CLEANUP_H_MARGIN, M_CLEANUP_V_MARGIN)); 1539 } 1540 cookie = 0; 1541 Connection connection; 1542 while (manager->getNextConnection(&connection, &cookie) == B_OK) 1543 { 1544 _addWireFor(connection); 1545 } 1546 1547 // create default groups 1548 NodeGroup* group; 1549 NodeRef* videoIn = manager->videoInputNode(); 1550 if (videoIn) 1551 { 1552 group = manager->createGroup(B_TRANSLATE("Video input")); 1553 group->setRunMode(BMediaNode::B_RECORDING); 1554 group->addNode(videoIn); 1555 } 1556 NodeRef* audioIn = manager->audioInputNode(); 1557 if (audioIn) 1558 { 1559 group = manager->createGroup(B_TRANSLATE("Audio input")); 1560 group->setRunMode(BMediaNode::B_RECORDING); 1561 group->addNode(audioIn); 1562 } 1563 NodeRef* videoOut = manager->videoOutputNode(); 1564 if (videoOut) 1565 { 1566 group = manager->createGroup(B_TRANSLATE("Video output")); 1567 group->addNode(videoOut); 1568 } 1569 } 1570 1571 void MediaRoutingView::_changeCyclingForSelection( 1572 bool cycle) 1573 { 1574 D_METHOD(("MediaRoutingView::_changeCyclingForSelection()\n")); 1575 1576 if (SelectedType() == DiagramItem::M_BOX) 1577 { 1578 manager->lock(); 1579 for (uint32 i = 0; i < CountSelectedItems(); i++) 1580 { 1581 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(SelectedItemAt(i)); 1582 if (panel && (panel->ref->isCycling() != cycle)) 1583 { 1584 panel->ref->setCycling(cycle); 1585 } 1586 } 1587 manager->unlock(); 1588 } 1589 } 1590 1591 void MediaRoutingView::_changeRunModeForSelection( 1592 uint32 mode) 1593 { 1594 D_METHOD(("MediaRoutingView::_changeRunModeForSelection()\n")); 1595 1596 if (SelectedType() == DiagramItem::M_BOX) 1597 { 1598 manager->lock(); 1599 for (uint32 i = 0; i < CountSelectedItems(); i++) 1600 { 1601 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(SelectedItemAt(i)); 1602 if (panel && (panel->ref->runMode() != mode)) 1603 { 1604 panel->ref->setRunMode(mode); 1605 } 1606 } 1607 manager->unlock(); 1608 } 1609 } 1610 1611 void MediaRoutingView::_openInfoWindowsForSelection() { 1612 D_METHOD(("MediaRoutingView::_openInfoWindowsForSelection()\n")); 1613 1614 InfoWindowManager *manager = InfoWindowManager::Instance(); 1615 if (!manager) { 1616 return; 1617 } 1618 1619 if (SelectedType() == DiagramItem::M_BOX) { 1620 for (uint32 i = 0; i < CountSelectedItems(); i++) { 1621 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(SelectedItemAt(i)); 1622 if (panel && manager->Lock()) { 1623 manager->openWindowFor(panel->ref); 1624 manager->Unlock(); 1625 } 1626 } 1627 } 1628 else if (SelectedType() == DiagramItem::M_WIRE) { 1629 for (uint32 i = 0; i < CountSelectedItems(); i++) { 1630 MediaWire *wire = dynamic_cast<MediaWire *>(SelectedItemAt(i)); 1631 if (wire && manager->Lock()) { 1632 manager->openWindowFor(wire->connection); 1633 manager->Unlock(); 1634 } 1635 } 1636 } 1637 } 1638 1639 void MediaRoutingView::_openParameterWindowsForSelection() { 1640 D_METHOD(("MediaRoutingView::_openParameterWindowsForSelection()\n")); 1641 1642 if (SelectedType() != DiagramItem::M_BOX) { 1643 // can only open parameter window for nodes 1644 return; 1645 } 1646 1647 for (uint32 i = 0; i < CountSelectedItems(); i++) { 1648 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(SelectedItemAt(i)); 1649 if (panel && (panel->ref->kind() & B_CONTROLLABLE)) { 1650 ParameterWindowManager *paramMgr= ParameterWindowManager::Instance(); 1651 if (paramMgr && paramMgr->Lock()) { 1652 paramMgr->openWindowFor(panel->ref); 1653 paramMgr->Unlock(); 1654 } 1655 } 1656 } 1657 } 1658 1659 void MediaRoutingView::_startControlPanelsForSelection() { 1660 D_METHOD(("MediaRoutingView::_startControlPanelsForSelection()\n")); 1661 1662 if (SelectedType() != DiagramItem::M_BOX) { 1663 // can only start control panel for nodes 1664 return; 1665 } 1666 1667 for (uint32 i = 0; i < CountSelectedItems(); i++) { 1668 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(SelectedItemAt(i)); 1669 if (panel && (panel->ref->kind() & B_CONTROLLABLE)) { 1670 ParameterWindowManager *paramMgr= ParameterWindowManager::Instance(); 1671 if (paramMgr && paramMgr->Lock()) { 1672 paramMgr->startControlPanelFor(panel->ref); 1673 paramMgr->Unlock(); 1674 } 1675 } 1676 } 1677 } 1678 1679 void MediaRoutingView::_deleteSelection() 1680 { 1681 D_METHOD(("MediaRoutingView::_deleteSelection()\n")); 1682 if (SelectedType() == DiagramItem::M_BOX) 1683 { 1684 for (uint32 i = 0; i < CountSelectedItems(); i++) 1685 { 1686 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(SelectedItemAt(i)); 1687 if (panel && panel->ref->isInternal()) 1688 { 1689 status_t error = panel->ref->releaseNode(); 1690 if (error) 1691 { 1692 BString s = B_TRANSLATE("Could not release '%refname%'"); 1693 s.ReplaceFirst("%rename%", panel->ref->name()); 1694 showErrorMessage(s, error); 1695 } 1696 } 1697 } 1698 } 1699 else if (SelectedType() == DiagramItem::M_WIRE) 1700 { 1701 for (uint32 i = 0; i < CountSelectedItems(); i++) 1702 { 1703 MediaWire *wire = dynamic_cast<MediaWire *>(SelectedItemAt(i)); 1704 if (wire && !(wire->connection.flags() & Connection::LOCKED)) 1705 { 1706 status_t error = manager->disconnect(wire->connection); 1707 if (error) 1708 { 1709 showErrorMessage( 1710 B_TRANSLATE("Could not disconnect"), error); 1711 } 1712 } 1713 } 1714 } 1715 // make sure none of the deleted items is still displaying its mouse cursor ! 1716 be_app->SetCursor(B_HAND_CURSOR); 1717 } 1718 1719 void MediaRoutingView::_checkDroppedFile( 1720 entry_ref *ref, 1721 BPoint dropPoint) 1722 { 1723 D_METHOD(("MediaRoutingView::_checkDroppedFile()\n")); 1724 1725 // [cell 26apr00] traverse links 1726 BEntry entry(ref, true); 1727 entry.GetRef(ref); 1728 1729 BNode node(ref); 1730 if (node.InitCheck() == B_OK) 1731 { 1732 BNodeInfo nodeInfo(&node); 1733 if (nodeInfo.InitCheck() == B_OK) 1734 { 1735 char mimeString[B_MIME_TYPE_LENGTH]; 1736 if (nodeInfo.GetType(mimeString) == B_OK) 1737 { 1738 BMimeType mimeType(mimeString); 1739 BMimeType superType; 1740 1741 // [e.moon 22dec99] handle dropped node-set files 1742 if(mimeType == RouteApp::s_nodeSetType) { 1743 BMessage m(B_REFS_RECEIVED); 1744 m.AddRef("refs", ref); 1745 be_app_messenger.SendMessage(&m); 1746 } 1747 else if (mimeType.GetSupertype(&superType) == B_OK) 1748 { 1749 if (superType == "image") 1750 { 1751 _changeBackground(ref); 1752 } 1753 else if ((superType == "audio") || (superType == "video")) 1754 { 1755 NodeRef* droppedNode; 1756 status_t error; 1757 error = manager->instantiate(*ref, B_BUFFER_PRODUCER, &droppedNode); 1758 if (!error) 1759 { 1760 media_output encVideoOutput; 1761 if (droppedNode->findFreeOutput(&encVideoOutput, B_MEDIA_ENCODED_VIDEO) == B_OK) 1762 { 1763 droppedNode->setFlags(droppedNode->flags() | NodeRef::NO_POSITION_REPORTING); 1764 } 1765 m_lastDroppedNode = droppedNode->id(); 1766 m_lastDropPoint = Align(dropPoint); 1767 } 1768 else 1769 { 1770 char fileName[B_FILE_NAME_LENGTH]; 1771 BEntry entry(ref); 1772 entry.GetName(fileName); 1773 BString s = B_TRANSLATE( 1774 "Could not load '%filename%'"); 1775 s.ReplaceFirst("%filename%", fileName); 1776 showErrorMessage(s, error); 1777 } 1778 } 1779 } 1780 } 1781 } 1782 } 1783 } 1784 1785 void MediaRoutingView::_changeBackground( 1786 entry_ref *ref) 1787 { 1788 D_METHOD(("MediaRoutingView::_changeBackground()\n")); 1789 1790 status_t error; 1791 BBitmap *background = 0; 1792 BFile file(ref, B_READ_ONLY); 1793 error = file.InitCheck(); 1794 if (!error) 1795 { 1796 BTranslatorRoster *roster = BTranslatorRoster::Default(); 1797 BBitmapStream stream; 1798 error = roster->Translate(&file, NULL, NULL, &stream, B_TRANSLATOR_BITMAP); 1799 if (!error) 1800 { 1801 stream.DetachBitmap(&background); 1802 setBackgroundBitmap(background); 1803 Invalidate(); 1804 1805 // [e.moon 1dec99] persistence, yay 1806 m_backgroundBitmapEntry.SetTo(ref); 1807 } 1808 } 1809 delete background; 1810 } 1811 1812 void MediaRoutingView::_changeBackground( 1813 rgb_color color) 1814 { 1815 D_METHOD(("MediaRoutingView::_changeBackground()\n")); 1816 setBackgroundColor(color); 1817 Invalidate(); 1818 1819 // [e.moon 1dec99] persistence, yay 1820 m_backgroundBitmapEntry.Unset(); 1821 } 1822 1823 void 1824 MediaRoutingView::_adjustScrollBars() 1825 { 1826 D_METHOD(("MediaRoutingView::_adjustScrollBars()\n")); 1827 1828 BScrollBar *scrollBar; 1829 1830 // adjust horizontal scroll bar 1831 scrollBar = ScrollBar(B_HORIZONTAL); 1832 if (scrollBar) { 1833 float bigStep = floor(MediaNodePanel::M_DEFAULT_WIDTH + M_CLEANUP_H_GAP); 1834 scrollBar->SetSteps(floor(bigStep / 10.0), bigStep); 1835 } 1836 1837 // adjust vertical scroll bar 1838 scrollBar = ScrollBar(B_VERTICAL); 1839 if (scrollBar) { 1840 float bigStep = floor(MediaNodePanel::M_DEFAULT_HEIGHT + M_CLEANUP_V_GAP); 1841 scrollBar->SetSteps(floor(bigStep / 10.0), bigStep); 1842 } 1843 } 1844 1845 void 1846 MediaRoutingView::_broadcastSelection() const 1847 { 1848 int32 selectedGroup = 0; 1849 1850 if (SelectedType() == DiagramItem::M_BOX) { 1851 // iterate thru the list of selected node panels and make the 1852 // first group we find the selected group 1853 for (uint32 i = 0; i < CountSelectedItems(); i++) { 1854 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(SelectedItemAt(i)); 1855 if (panel && panel->ref->group()) { 1856 selectedGroup = panel->ref->group()->id(); 1857 BMessenger messenger(Window()); 1858 BMessage groupMsg(M_GROUP_SELECTED); 1859 groupMsg.AddInt32("groupID", selectedGroup); 1860 messenger.SendMessage(&groupMsg); 1861 return; 1862 } 1863 } 1864 } 1865 1866 // currently no group is selected 1867 BMessenger messenger(Window()); 1868 BMessage groupMsg(M_GROUP_SELECTED); 1869 groupMsg.AddInt32("groupID", selectedGroup); 1870 messenger.SendMessage(&groupMsg); 1871 } 1872 1873 status_t 1874 MediaRoutingView::_fetchInactiveNodeState(MediaNodePanel *forPanel, BMessage *outMessage) 1875 { 1876 // copy inactive node state info 1877 int32 c = m_inactiveNodeState.CountItems(); 1878 for(int32 n = 0; n < c; n++) { 1879 _inactive_node_state_entry* e = reinterpret_cast<_inactive_node_state_entry*>( 1880 m_inactiveNodeState.ItemAt(n)); 1881 ASSERT(e); 1882 if(e->name != forPanel->ref->name()) 1883 continue; 1884 1885 if(e->kind != forPanel->ref->kind()) 1886 continue; 1887 1888 // found match; extract message & remove entry 1889 *outMessage = e->state; 1890 m_inactiveNodeState.RemoveItem(n); 1891 return B_OK; 1892 } 1893 1894 return B_BAD_VALUE; 1895 } 1896 1897 void 1898 MediaRoutingView::_emptyInactiveNodeState() 1899 { 1900 int32 c = m_inactiveNodeState.CountItems(); 1901 for(int32 n = 0; n < c; n++) { 1902 _inactive_node_state_entry* e = reinterpret_cast<_inactive_node_state_entry*>( 1903 m_inactiveNodeState.ItemAt(n)); 1904 ASSERT(e); 1905 delete e; 1906 } 1907 m_inactiveNodeState.MakeEmpty(); 1908 } 1909 1910 1911 // END -- MediaRoutingView.cpp -- 1912