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