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