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