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