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