1 // MediaNodePanel.cpp 2 // c.lenz 10oct99 3 4 #include "MediaNodePanel.h" 5 // InfoWindow 6 #include "InfoWindowManager.h" 7 // MediaRoutingView 8 #include "MediaRoutingView.h" 9 #include "MediaWire.h" 10 #include "RouteAppNodeManager.h" 11 // NodeManager 12 #include "NodeRef.h" 13 #include "NodeGroup.h" 14 // ParameterWindow 15 #include "ParameterWindow.h" 16 // Support 17 #include "cortex_ui.h" 18 #include "MediaIcon.h" 19 #include "MediaString.h" 20 // RouteApp 21 #include "RouteWindow.h" 22 // TipManager 23 #include "TipManager.h" 24 25 // App Kit 26 #include <Application.h> 27 #include <Roster.h> 28 // Interface Kit 29 #include <MenuItem.h> 30 #include <PopUpMenu.h> 31 // Media Kit 32 #include <MediaDefs.h> 33 #include <MediaRoster.h> 34 35 using namespace std; 36 37 __USE_CORTEX_NAMESPACE 38 39 #include <Debug.h> 40 #define D_METHOD(x) //PRINT (x) 41 #define D_MESSAGE(x) //PRINT (x) 42 #define D_DRAW(x) //PRINT (x) 43 44 // -------------------------------------------------------- // 45 // constants 46 // -------------------------------------------------------- // 47 48 float MediaNodePanel::M_DEFAULT_WIDTH = 90.0; 49 float MediaNodePanel::M_DEFAULT_HEIGHT = 60.0; 50 float MediaNodePanel::M_LABEL_H_MARGIN = 3.0; 51 float MediaNodePanel::M_LABEL_V_MARGIN = 3.0; 52 float MediaNodePanel::M_BODY_H_MARGIN = 5.0; 53 float MediaNodePanel::M_BODY_V_MARGIN = 5.0; 54 55 // [e.moon 7dec99] 56 const BPoint MediaNodePanel::s_invalidPosition(-200.0, -200.0); 57 58 // -------------------------------------------------------- // 59 // *** ctor/dtor 60 // -------------------------------------------------------- // 61 62 MediaNodePanel::MediaNodePanel( 63 BPoint position, 64 NodeRef *nodeRef) 65 : DiagramBox(BRect(position, position + BPoint(M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT))), 66 BHandler(nodeRef->name()), 67 ref(nodeRef), 68 m_bitmap(0), 69 m_icon(0), 70 m_alternatePosition(s_invalidPosition) 71 { 72 D_METHOD(("MediaNodePanel::MediaNodePanel()\n")); 73 ASSERT(ref); 74 } 75 76 MediaNodePanel::~MediaNodePanel() 77 { 78 D_METHOD(("MediaNodePanel::~MediaNodePanel()\n")); 79 if (m_icon) 80 { 81 delete m_icon; 82 } 83 if (m_bitmap) 84 { 85 delete m_bitmap; 86 } 87 } 88 89 // -------------------------------------------------------- // 90 // *** derived from DiagramBox 91 // -------------------------------------------------------- // 92 93 void MediaNodePanel::attachedToDiagram() 94 { 95 D_METHOD(("MediaNodePanel::attachedToDiagram()\n")); 96 97 resizeTo(M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT); 98 _updateIcon(dynamic_cast<MediaRoutingView *>(view())->getLayout()); 99 _prepareLabel(); 100 populateInit(); 101 arrangeIOJacks(); 102 103 view()->Looper()->AddHandler(this); 104 } 105 106 void MediaNodePanel::detachedFromDiagram() 107 { 108 D_METHOD(("MediaNodePanel::detachedFromDiagram()\n")); 109 110 BRect labelRect = m_labelRect.OffsetByCopy(Frame().LeftTop()); 111 if (m_mouseOverLabel && m_labelTruncated) 112 { 113 TipManager *tips = TipManager::Instance(); 114 tips->hideTip(view()->ConvertToScreen(labelRect)); 115 } 116 117 view()->Looper()->RemoveHandler(this); 118 } 119 120 void MediaNodePanel::DrawBox() 121 { 122 D_DRAW(("MediaNodePanel::DrawBox()\n")); 123 if (m_bitmap) 124 { 125 view()->DrawBitmap(m_bitmap, Frame().LeftTop()); 126 } 127 } 128 129 void MediaNodePanel::MouseDown( 130 BPoint point, 131 uint32 buttons, 132 uint32 clicks) 133 { 134 D_METHOD(("MediaNodePanel::MouseDown()\n")); 135 136 _inherited::MouseDown(point, buttons, clicks); 137 138 // +++ REALLY BAD WORKAROUND 139 MediaJack *jack = dynamic_cast<MediaJack *>(_LastItemUnder()); 140 if (jack && jack->Frame().Contains(point)) 141 { 142 return; 143 } 144 145 switch (buttons) { 146 case B_PRIMARY_MOUSE_BUTTON: 147 { 148 if (clicks == 2) { 149 if (ref->kind() & B_CONTROLLABLE) { 150 BMessage message(MediaRoutingView::M_NODE_TWEAK_PARAMETERS); 151 DiagramView* v = view(); 152 BMessenger(v).SendMessage(&message); 153 } 154 } 155 break; 156 } 157 case B_SECONDARY_MOUSE_BUTTON: 158 { 159 if (clicks == 1) { 160 showContextMenu(point); 161 } 162 break; 163 } 164 } 165 } 166 167 void MediaNodePanel::MouseOver( 168 BPoint point, 169 uint32 transit) 170 { 171 D_METHOD(("MediaNodePanel::MouseOver()\n")); 172 _inherited::MouseOver(point, transit); 173 174 switch (transit) 175 { 176 case B_ENTERED_VIEW: 177 { 178 break; 179 } 180 case B_INSIDE_VIEW: 181 { 182 BRect labelRect = m_labelRect.OffsetByCopy(Frame().LeftTop()); 183 if (labelRect.Contains(point)) 184 { 185 if (!m_mouseOverLabel && m_labelTruncated) 186 { 187 TipManager *tips = TipManager::Instance(); 188 tips->showTip(m_fullLabel.String(), view()->ConvertToScreen(labelRect)); 189 m_mouseOverLabel = true; 190 } 191 } 192 else 193 { 194 m_mouseOverLabel = false; 195 } 196 break; 197 } 198 case B_EXITED_VIEW: 199 { 200 m_mouseOverLabel = false; 201 break; 202 } 203 } 204 } 205 206 void MediaNodePanel::MessageDropped( 207 BPoint point, 208 BMessage *message) 209 { 210 D_METHOD(("MediaNodePanel::MessageDropped()\n")); 211 212 // +++ REALLY BAD WORKAROUND 213 MediaJack *jack = dynamic_cast<MediaJack *>(ItemUnder(point)); 214 if (jack) 215 { 216 jack->MessageDropped(point, message); 217 return; 218 } 219 else 220 { 221 be_app->SetCursor(B_HAND_CURSOR); 222 } 223 } 224 225 void MediaNodePanel::selected() 226 { 227 D_METHOD(("MediaNodePanel::selected()\n")); 228 _updateBitmap(); 229 } 230 231 void MediaNodePanel::deselected() 232 { 233 D_METHOD(("MediaNodePanel::deselected()\n")); 234 _updateBitmap(); 235 } 236 237 // ---------------------------------------------------------------- // 238 // *** updating 239 // ---------------------------------------------------------------- // 240 241 void MediaNodePanel::layoutChanged( 242 int32 layout) 243 { 244 D_METHOD(("MediaNodePanel::layoutChanged()\n")); 245 246 BPoint p = Frame().LeftTop(); 247 if (m_alternatePosition == s_invalidPosition) 248 { 249 m_alternatePosition = dynamic_cast<MediaRoutingView *> 250 (view())->findFreePositionFor(this); 251 } 252 moveTo(m_alternatePosition); 253 m_alternatePosition = p; 254 255 resizeTo(M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT); 256 for (uint32 i = 0; i < CountItems(); i++) 257 { 258 MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i)); 259 jack->layoutChanged(layout); 260 } 261 _updateIcon(layout); 262 _prepareLabel(); 263 arrangeIOJacks(); 264 _updateBitmap(); 265 } 266 267 void MediaNodePanel::populateInit() 268 { 269 D_METHOD(("MediaNodePanel::populateInit()\n")); 270 if (ref->kind() & B_BUFFER_CONSUMER) 271 { 272 vector<media_input> freeInputs; 273 ref->getFreeInputs(freeInputs); 274 for (uint32 i = 0; i < freeInputs.size(); i++) 275 { 276 AddItem(new MediaJack(freeInputs[i])); 277 } 278 } 279 if (ref->kind() & B_BUFFER_PRODUCER) 280 { 281 vector<media_output> freeOutputs; 282 ref->getFreeOutputs(freeOutputs); 283 for (uint32 i = 0; i < freeOutputs.size(); i++) 284 { 285 AddItem(new MediaJack(freeOutputs[i])); 286 } 287 } 288 } 289 290 void MediaNodePanel::updateIOJacks() 291 { 292 D_METHOD(("MediaNodePanel::updateIOJacks()\n")); 293 294 // remove all free inputs/outputs, they may be outdated 295 for (uint32 i = 0; i < CountItems(); i++) 296 { 297 MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i)); 298 if (jack && !jack->isConnected()) 299 { 300 RemoveItem(jack); 301 delete jack; 302 i--; // account for reindexing in the BList 303 } 304 } 305 306 // add free inputs 307 if (ref->kind() & B_BUFFER_CONSUMER) 308 { 309 vector<media_input> freeInputs; 310 ref->getFreeInputs(freeInputs); 311 for (uint32 i = 0; i < freeInputs.size(); i++) 312 { 313 MediaJack *jack; 314 AddItem(jack = new MediaJack(freeInputs[i])); 315 } 316 } 317 318 // add free outputs 319 if (ref->kind() & B_BUFFER_PRODUCER) 320 { 321 vector<media_output> freeOutputs; 322 ref->getFreeOutputs(freeOutputs); 323 for (uint32 i = 0; i < freeOutputs.size(); i++) 324 { 325 MediaJack *jack; 326 AddItem(jack = new MediaJack(freeOutputs[i])); 327 } 328 } 329 330 // the supported media types might have changed -> this could 331 // require changing the icon 332 _updateIcon(dynamic_cast<MediaRoutingView *>(view())->getLayout()); 333 } 334 335 void MediaNodePanel::arrangeIOJacks() 336 { 337 D_METHOD(("MediaNodePanel::arrangeIOJacks()\n")); 338 SortItems(DiagramItem::M_ENDPOINT, &compareTypeAndID); 339 340 switch (dynamic_cast<MediaRoutingView *>(view())->getLayout()) 341 { 342 case MediaRoutingView::M_ICON_VIEW: 343 { 344 BRegion updateRegion; 345 float align = 1.0; 346 view()->GetItemAlignment(0, &align); 347 348 // adjust this panel's size 349 int32 numInputs = 0, numOutputs = 0; 350 for (uint32 i = 0; i < CountItems(); i++) 351 { 352 MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i)); 353 if (jack) 354 { 355 if (jack->isInput()) 356 { 357 numInputs++; 358 } 359 if (jack->isOutput()) 360 { 361 numOutputs++; 362 } 363 } 364 } 365 float minHeight = MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP; 366 minHeight *= numInputs > numOutputs ? numInputs : numOutputs; 367 minHeight += m_labelRect.Height(); 368 minHeight += 2 * MediaJack::M_DEFAULT_GAP; 369 minHeight = ((int)minHeight / (int)align) * align + align; 370 if ((Frame().Height() < minHeight) 371 || ((Frame().Height() > minHeight) 372 && (minHeight >= MediaNodePanel::M_DEFAULT_HEIGHT))) 373 { 374 updateRegion.Include(Frame()); 375 resizeTo(Frame().Width(), minHeight); 376 updateRegion.Include(Frame()); 377 _prepareLabel(); 378 } 379 380 // adjust the placement of the jacks 381 BRect r = m_bodyRect; 382 r.bottom -= M_BODY_V_MARGIN; 383 float inputOffset = 0.0, outputOffset = 0.0; 384 float center = Frame().top + r.top + (r.Height() / 2.0); 385 center += MediaJack::M_DEFAULT_GAP - (MediaJack::M_DEFAULT_HEIGHT / 2.0); 386 center = ((int)center / (int)align) * align; 387 if (numInputs) 388 { 389 if (numInputs % 2) // odd number of inputs 390 { 391 inputOffset = center - (numInputs / 2) * (MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP); 392 } 393 else // even number of inputs 394 { 395 inputOffset = center - ((numInputs + 1) / 2) * (MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP); 396 } 397 } 398 if (numOutputs) 399 { 400 if (numOutputs % 2) // odd number of outputs 401 { 402 outputOffset = center - (numOutputs / 2) * (MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP); 403 } 404 else // even number of outputs 405 { 406 outputOffset = center - ((numOutputs + 1) / 2) * (MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP); 407 } 408 } 409 for (uint32 i = 0; i < CountItems(); i++) 410 { 411 MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i)); 412 if (jack) 413 { 414 if (jack->isInput()) 415 { 416 jack->setPosition(inputOffset, Frame().left, Frame().right, &updateRegion); 417 inputOffset += jack->Frame().Height() + MediaJack::M_DEFAULT_GAP; 418 } 419 if (jack->isOutput()) 420 { 421 jack->setPosition(outputOffset, Frame().left, Frame().right, &updateRegion); 422 outputOffset += jack->Frame().Height() + MediaJack::M_DEFAULT_GAP; 423 } 424 } 425 } 426 for (int32 i = 0; i < updateRegion.CountRects(); i++) 427 { 428 view()->Invalidate(updateRegion.RectAt(i)); 429 } 430 break; 431 } 432 case MediaRoutingView::M_MINI_ICON_VIEW: 433 { 434 BRegion updateRegion; 435 float align = 1.0; 436 view()->GetItemAlignment(&align, 0); 437 438 // adjust this panel's size 439 int32 numInputs = 0, numOutputs = 0; 440 for (uint32 i = 0; i < CountItems(); i++) 441 { 442 MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i)); 443 if (jack) 444 { 445 if (jack->isInput()) 446 { 447 numInputs++; 448 } 449 if (jack->isOutput()) 450 { 451 numOutputs++; 452 } 453 } 454 } 455 float minWidth = MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP; 456 minWidth *= numInputs > numOutputs ? numInputs : numOutputs; 457 minWidth += m_bodyRect.Width(); 458 minWidth += 2 * MediaJack::M_DEFAULT_GAP; 459 minWidth = ((int)minWidth / (int)align) * align + align; 460 if ((Frame().Width() < minWidth) 461 || ((Frame().Width() > minWidth) 462 && (minWidth >= MediaNodePanel::M_DEFAULT_WIDTH))) 463 { 464 updateRegion.Include(Frame()); 465 resizeTo(minWidth, Frame().Height()); 466 updateRegion.Include(Frame()); 467 _prepareLabel(); 468 } 469 // adjust the placement of the jacks 470 float inputOffset = 0.0, outputOffset = 0.0; 471 float center = Frame().left + m_labelRect.left + (m_labelRect.Width() / 2.0); 472 center += MediaJack::M_DEFAULT_GAP - (MediaJack::M_DEFAULT_WIDTH / 2.0); 473 center = ((int)center / (int)align) * align; 474 if (numInputs) 475 { 476 if (numInputs % 2) // odd number of inputs 477 { 478 inputOffset = center - (numInputs / 2) * (MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP); 479 } 480 else // even number of inputs 481 { 482 inputOffset = center - ((numInputs + 1) / 2) * (MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP); 483 } 484 } 485 if (numOutputs) 486 { 487 if (numOutputs % 2) // odd number of outputs 488 { 489 outputOffset = center - (numOutputs / 2) * (MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP); 490 } 491 else // even number of outputs 492 { 493 outputOffset = center - ((numOutputs + 1) / 2) * (MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP); 494 } 495 } 496 for (uint32 i = 0; i < CountItems(); i++) 497 { 498 MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i)); 499 if (jack) 500 { 501 if (jack->isInput()) 502 { 503 jack->setPosition(inputOffset, Frame().top, Frame().bottom, &updateRegion); 504 inputOffset += jack->Frame().Width() + MediaJack::M_DEFAULT_GAP; 505 } 506 if (jack->isOutput()) 507 { 508 jack->setPosition(outputOffset, Frame().top, Frame().bottom, &updateRegion); 509 outputOffset += jack->Frame().Width() + MediaJack::M_DEFAULT_GAP; 510 } 511 } 512 } 513 for (int32 i = 0; i < updateRegion.CountRects(); i++) 514 { 515 view()->Invalidate(updateRegion.RectAt(i)); 516 } 517 break; 518 } 519 } 520 _updateBitmap(); 521 } 522 523 void MediaNodePanel::showContextMenu( 524 BPoint point) 525 { 526 D_METHOD(("MediaNodePanel::showContextMenu()\n")); 527 528 BPopUpMenu *menu = new BPopUpMenu("MediaNodePanel PopUp", false, false, B_ITEMS_IN_COLUMN); 529 menu->SetFont(be_plain_font); 530 531 BMenuItem *item; 532 BMessage *message; 533 534 // add the "Tweak Parameters" item 535 message = new BMessage(MediaRoutingView::M_NODE_TWEAK_PARAMETERS); 536 menu->AddItem(item = new BMenuItem("Tweak Parameters", message, 'P')); 537 if (!(ref->kind() & B_CONTROLLABLE)) 538 { 539 item->SetEnabled(false); 540 } 541 542 message = new BMessage(InfoWindowManager::M_INFO_WINDOW_REQUESTED); 543 message->AddInt32("nodeID", ref->id()); 544 menu->AddItem(new BMenuItem("Get Info", message, 'I')); 545 menu->AddSeparatorItem(); 546 547 menu->AddItem(item = new BMenuItem("Release", new BMessage(MediaRoutingView::M_DELETE_SELECTION), 'T')); 548 if (!ref->isInternal()) 549 { 550 item->SetEnabled(false); 551 } 552 menu->AddSeparatorItem(); 553 554 // add the "Cycle" item 555 message = new BMessage(MediaRoutingView::M_NODE_CHANGE_CYCLING); 556 message->AddBool("cycle", !ref->isCycling()); 557 menu->AddItem(item = new BMenuItem("Cycle", message)); 558 item->SetMarked(ref->isCycling()); 559 if (ref->flags() & NodeRef::NO_SEEK) 560 { 561 item->SetEnabled(false); 562 } 563 564 // add the "Run Mode" sub menu 565 BMenu *subMenu = new BMenu("Run Mode"); 566 subMenu->SetFont(be_plain_font); 567 for (uint32 runMode = 1; runMode <= BMediaNode::B_RECORDING; runMode++) 568 { 569 BString itemName = MediaString::getStringFor(static_cast<BMediaNode::run_mode> 570 (runMode)); 571 message = new BMessage(MediaRoutingView::M_NODE_CHANGE_RUN_MODE); 572 message->AddInt32("run_mode", runMode); 573 subMenu->AddItem(item = new BMenuItem(itemName.String(), message)); 574 if (ref->runMode() == runMode) 575 { 576 item->SetMarked(true); 577 } 578 else if ((ref->runMode() == 0) 579 && (ref->group()) && (ref->group()->runMode() == BMediaNode::run_mode(runMode))) 580 { 581 item->SetMarked(true); 582 } 583 } 584 subMenu->AddSeparatorItem(); 585 message = new BMessage(MediaRoutingView::M_NODE_CHANGE_RUN_MODE); 586 message->AddInt32("run_mode", 0); 587 subMenu->AddItem(item = new BMenuItem("(same as group)", message)); 588 if (ref->group() == 0) 589 { 590 item->SetEnabled(false); 591 } 592 else if ((ref->runMode() < 1) && (ref->group()->runMode() > 0)) 593 { 594 item->SetMarked(true); 595 } 596 menu->AddItem(subMenu); 597 subMenu->SetTargetForItems(view()); 598 599 // [c.lenz 24dec99] hide rarely used commands in a 'Advanced' submenu 600 subMenu = new BMenu("Advanced"); 601 subMenu->SetFont(be_plain_font); 602 // [e.moon 5dec99] ad-hoc timesource support 603 if(ref->kind() & B_TIME_SOURCE) { 604 message = new BMessage(MediaRoutingView::M_NODE_START_TIME_SOURCE); 605 message->AddInt32("nodeID", ref->id()); 606 subMenu->AddItem(new BMenuItem( 607 "Start Time Source", 608 message)); 609 message = new BMessage(MediaRoutingView::M_NODE_START_TIME_SOURCE); 610 message->AddInt32("nodeID", ref->id()); 611 subMenu->AddItem(new BMenuItem( 612 "Stop Time Source", 613 message)); 614 } 615 // [c.lenz 24dec99] support for BControllable::StartControlPanel() 616 if(ref->kind() & B_CONTROLLABLE) { 617 if (subMenu->CountItems() > 0) 618 subMenu->AddSeparatorItem(); 619 message = new BMessage(MediaRoutingView::M_NODE_START_CONTROL_PANEL); 620 subMenu->AddItem(new BMenuItem("Start Control Panel", message, 621 'P', B_COMMAND_KEY | B_SHIFT_KEY)); 622 } 623 // [em 1feb00] group tweaks 624 if(ref->group()) 625 { 626 message = new BMessage(MediaRoutingView::M_GROUP_SET_LOCKED); 627 message->AddInt32("groupID", ref->group()->id()); 628 bool isLocked = (ref->group()->groupFlags() & NodeGroup::GROUP_LOCKED); 629 message->AddBool("locked", !isLocked); 630 if (subMenu->CountItems() > 0) 631 subMenu->AddSeparatorItem(); 632 subMenu->AddItem( 633 new BMenuItem( 634 isLocked ? "Unlock Group" : "Lock Group", message)); 635 } 636 637 if (subMenu->CountItems() > 0) 638 { 639 menu->AddItem(subMenu); 640 subMenu->SetTargetForItems(view()); 641 } 642 643 menu->SetTargetForItems(view()); 644 view()->ConvertToScreen(&point); 645 point -= BPoint(1.0, 1.0); 646 menu->Go(point, true, true, true); 647 } 648 649 // ---------------------------------------------------------------- // 650 // BHandler impl 651 // ---------------------------------------------------------------- // 652 653 void MediaNodePanel::MessageReceived( 654 BMessage *message) 655 { 656 D_METHOD(("MediaNodePanel::MessageReceived()\n")); 657 switch (message->what) 658 { 659 case NodeRef::M_INPUTS_CHANGED: 660 { 661 D_MESSAGE(("MediaNodePanel::MessageReceived(NodeRef::M_INPUTS_CHANGED)\n")); 662 _updateIcon(dynamic_cast<MediaRoutingView *>(view())->getLayout()); 663 break; 664 } 665 case NodeRef::M_OUTPUTS_CHANGED: 666 { 667 D_MESSAGE(("MediaNodePanel::MessageReceived(NodeRef::M_OUTPUTS_CHANGED)\n")); 668 _updateIcon(dynamic_cast<MediaRoutingView *>(view())->getLayout()); 669 break; 670 } 671 default: 672 { 673 BHandler::MessageReceived(message); 674 break; 675 } 676 } 677 } 678 679 // -------------------------------------------------------- // 680 // *** IStateArchivable 681 // -------------------------------------------------------- // 682 683 status_t MediaNodePanel::importState( 684 const BMessage* archive) { 685 686 BPoint iconPos(s_invalidPosition); 687 BPoint miniIconPos(s_invalidPosition); 688 689 MediaRoutingView* v = dynamic_cast<MediaRoutingView*>(view()); 690 ASSERT(v); 691 MediaRoutingView::layout_t layoutMode = v->getLayout(); 692 archive->FindPoint("iconPos", &iconPos); 693 archive->FindPoint("miniIconPos", &miniIconPos); 694 695 switch(layoutMode) { 696 case MediaRoutingView::M_ICON_VIEW: 697 if(iconPos != s_invalidPosition) 698 moveTo(iconPos); 699 m_alternatePosition = miniIconPos; 700 break; 701 702 case MediaRoutingView::M_MINI_ICON_VIEW: 703 if(miniIconPos != s_invalidPosition) 704 moveTo(miniIconPos); 705 m_alternatePosition = iconPos; 706 break; 707 } 708 709 return B_OK; 710 } 711 712 status_t MediaNodePanel::exportState( 713 BMessage* archive) const { 714 715 BPoint iconPos, miniIconPos; 716 717 MediaRoutingView* v = dynamic_cast<MediaRoutingView*>(view()); 718 ASSERT(v); 719 MediaRoutingView::layout_t layoutMode = v->getLayout(); 720 switch(layoutMode) { 721 case MediaRoutingView::M_ICON_VIEW: 722 iconPos = Frame().LeftTop(); 723 miniIconPos = m_alternatePosition; 724 break; 725 726 case MediaRoutingView::M_MINI_ICON_VIEW: 727 miniIconPos = Frame().LeftTop(); 728 iconPos = m_alternatePosition; 729 break; 730 } 731 732 if(iconPos != s_invalidPosition) 733 archive->AddPoint("iconPos", iconPos); 734 if(miniIconPos != s_invalidPosition) 735 archive->AddPoint("miniIconPos", miniIconPos); 736 737 // determine if I'm a 'system' node 738 port_info portInfo; 739 app_info appInfo; 740 741 if ((get_port_info(ref->node().port, &portInfo) == B_OK) 742 && (be_roster->GetRunningAppInfo(portInfo.team, &appInfo) == B_OK)) { 743 BEntry appEntry(&appInfo.ref); 744 char appName[B_FILE_NAME_LENGTH]; 745 if( 746 appEntry.InitCheck() == B_OK && 747 appEntry.GetName(appName) == B_OK && 748 (!strcmp(appName, "media_addon_server") || 749 !strcmp(appName, "audio_server"))) { 750 751 archive->AddBool("sysOwned", true); 752 } 753 } 754 755 return B_OK; 756 } 757 758 // ---------------------------------------------------------------- // 759 // *** internal operations 760 // ---------------------------------------------------------------- // 761 762 void MediaNodePanel::_prepareLabel() 763 { 764 // find out if its a file node first 765 if (ref->kind() & B_FILE_INTERFACE) 766 { 767 entry_ref nodeFile; 768 status_t error = BMediaRoster::Roster()->GetRefFor(ref->node(), &nodeFile); 769 if (error) 770 { 771 m_fullLabel = ref->name(); 772 m_fullLabel += " (no file)"; 773 } 774 else 775 { 776 BEntry entry(&nodeFile); 777 char fileName[B_FILE_NAME_LENGTH]; 778 entry.GetName(fileName); 779 m_fullLabel = fileName; 780 } 781 } 782 else 783 { 784 m_fullLabel = ref->name(); 785 } 786 787 int32 layout = dynamic_cast<MediaRoutingView *>(view())->getLayout(); 788 789 // Construct labelRect 790 font_height fh; 791 be_plain_font->GetHeight(&fh); 792 switch (layout) 793 { 794 case MediaRoutingView::M_ICON_VIEW: 795 { 796 m_labelRect = Frame(); 797 m_labelRect.OffsetTo(0.0, 0.0); 798 m_labelRect.bottom = 2 * M_LABEL_V_MARGIN + (fh.ascent + fh.descent + fh.leading) + 1.0; 799 break; 800 } 801 case MediaRoutingView::M_MINI_ICON_VIEW: 802 { 803 m_labelRect = Frame(); 804 m_labelRect.OffsetTo(0.0, 0.0); 805 m_labelRect.left = M_BODY_H_MARGIN + B_MINI_ICON; 806 m_labelRect.top += MediaJack::M_DEFAULT_HEIGHT; 807 m_labelRect.bottom -= MediaJack::M_DEFAULT_HEIGHT; 808 break; 809 } 810 } 811 812 // truncate the label to fit in the panel 813 float maxWidth = m_labelRect.Width() - (2.0 * M_LABEL_H_MARGIN) - 2.0; 814 if (be_plain_font->StringWidth(m_fullLabel.String()) > maxWidth) 815 { 816 char *truncatedLabel[1]; 817 truncatedLabel[0] = new char[B_MEDIA_NAME_LENGTH]; 818 const char *originalLabel[1]; 819 originalLabel[0] = new char[B_MEDIA_NAME_LENGTH]; 820 m_fullLabel.CopyInto(const_cast<char *>(originalLabel[0]), 0, B_MEDIA_NAME_LENGTH); 821 be_plain_font->GetTruncatedStrings(originalLabel, 1, B_TRUNCATE_END, maxWidth, (char **) truncatedLabel); 822 m_label = truncatedLabel[0]; 823 m_labelTruncated = true; 824 delete [] originalLabel[0]; 825 delete [] truncatedLabel[0]; 826 } 827 else 828 { 829 m_label = m_fullLabel; 830 m_labelTruncated = false; 831 } 832 833 // Construct labelOffset 834 float fw = be_plain_font->StringWidth(m_label.String()); 835 m_labelOffset.x = m_labelRect.left + m_labelRect.Width() / 2.0 - fw / 2.0; 836 m_labelOffset.y = m_labelRect.bottom - M_LABEL_V_MARGIN - fh.descent - (fh.leading / 2.0) - 1.0; 837 838 // Construct bodyRect 839 switch (layout) 840 { 841 case MediaRoutingView::M_ICON_VIEW: 842 { 843 m_bodyRect = Frame(); 844 m_bodyRect.OffsetTo(0.0, 0.0); 845 m_bodyRect.top = m_labelRect.bottom; 846 break; 847 } 848 case MediaRoutingView::M_MINI_ICON_VIEW: 849 { 850 m_bodyRect = Frame(); 851 m_bodyRect.OffsetTo(0.0, 0.0); 852 m_bodyRect.right = m_labelRect.left; 853 break; 854 } 855 } 856 } 857 858 void MediaNodePanel::_updateBitmap() 859 { 860 if (m_bitmap) 861 { 862 delete m_bitmap; 863 } 864 BBitmap *tempBitmap = new BBitmap(Frame().OffsetToCopy(0.0, 0.0), B_CMAP8, true); 865 tempBitmap->Lock(); 866 { 867 BView *tempView = new BView(tempBitmap->Bounds(), "", B_FOLLOW_NONE, 0); 868 tempBitmap->AddChild(tempView); 869 tempView->SetOrigin(0.0, 0.0); 870 871 int32 layout = dynamic_cast<MediaRoutingView *>(view())->getLayout(); 872 _drawInto(tempView, tempView->Bounds(), layout); 873 874 tempView->Sync(); 875 tempBitmap->RemoveChild(tempView); 876 delete tempView; 877 } 878 tempBitmap->Unlock(); 879 m_bitmap = new BBitmap(tempBitmap); 880 delete tempBitmap; 881 } 882 883 void MediaNodePanel::_drawInto( 884 BView *target, 885 BRect targetRect, 886 int32 layout) 887 { 888 switch (layout) 889 { 890 case MediaRoutingView::M_ICON_VIEW: 891 { 892 BRect r; 893 BPoint p; 894 895 // Draw borders 896 r = targetRect; 897 target->BeginLineArray(16); 898 target->AddLine(r.LeftTop(), r.RightTop(), M_DARK_GRAY_COLOR); 899 target->AddLine(r.RightTop(), r.RightBottom(), M_DARK_GRAY_COLOR); 900 target->AddLine(r.RightBottom(), r.LeftBottom(), M_DARK_GRAY_COLOR); 901 target->AddLine(r.LeftBottom(), r.LeftTop(), M_DARK_GRAY_COLOR); 902 r.InsetBy(1.0, 1.0); 903 target->AddLine(r.LeftTop(), r.RightTop(), M_LIGHT_GRAY_COLOR); 904 target->AddLine(r.RightTop(), r.RightBottom(), M_MED_GRAY_COLOR); 905 target->AddLine(r.RightBottom(), r.LeftBottom(), M_MED_GRAY_COLOR); 906 target->AddLine(r.LeftBottom(), r.LeftTop(), M_LIGHT_GRAY_COLOR); 907 target->EndLineArray(); 908 909 // Fill background 910 r.InsetBy(1.0, 1.0); 911 target->SetLowColor(M_GRAY_COLOR); 912 target->FillRect(r, B_SOLID_LOW); 913 914 // Draw icon 915 if (m_icon) 916 { 917 p.x = m_bodyRect.left + m_bodyRect.Width() / 2.0 - B_LARGE_ICON / 2.0; 918 p.y = m_labelRect.bottom + m_bodyRect.Height() / 2.0 - B_LARGE_ICON / 2.0; 919 if (isSelected()) 920 { 921 target->SetDrawingMode(B_OP_INVERT); 922 target->DrawBitmapAsync(m_icon, p); 923 target->SetDrawingMode(B_OP_ALPHA); 924 target->SetHighColor(0, 0, 0, 180); 925 target->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE); 926 target->DrawBitmapAsync(m_icon, p); 927 target->SetDrawingMode(B_OP_OVER); 928 } 929 else 930 { 931 target->SetDrawingMode(B_OP_OVER); 932 target->DrawBitmapAsync(m_icon, p); 933 } 934 } 935 936 // Draw label 937 if (isSelected()) 938 { 939 r = m_labelRect; 940 r.InsetBy(M_LABEL_H_MARGIN, M_LABEL_V_MARGIN); 941 target->BeginLineArray(4); 942 target->AddLine(r.LeftTop(), r.RightTop(), M_LIGHT_BLUE_COLOR); 943 target->AddLine(r.RightTop(), r.RightBottom(), M_LIGHT_BLUE_COLOR); 944 target->AddLine(r.RightBottom(), r.LeftBottom(), M_LIGHT_BLUE_COLOR); 945 target->AddLine(r.LeftBottom(), r.LeftTop(), M_LIGHT_BLUE_COLOR); 946 target->EndLineArray(); 947 r.InsetBy(1.0, 1.0); 948 target->SetHighColor(M_DARK_BLUE_COLOR); 949 target->FillRect(r, B_SOLID_HIGH); 950 } 951 target->SetDrawingMode(B_OP_OVER); 952 target->SetHighColor(isSelected() ? M_WHITE_COLOR : M_BLACK_COLOR); 953 target->DrawString(m_label.String(), m_labelOffset); 954 break; 955 } 956 case MediaRoutingView::M_MINI_ICON_VIEW: 957 { 958 BRect r; 959 BPoint p; 960 961 // Draw borders 962 r = targetRect; 963 target->BeginLineArray(16); 964 target->AddLine(r.LeftTop(), r.RightTop(), M_DARK_GRAY_COLOR); 965 target->AddLine(r.RightTop(), r.RightBottom(), M_DARK_GRAY_COLOR); 966 target->AddLine(r.RightBottom(), r.LeftBottom(), M_DARK_GRAY_COLOR); 967 target->AddLine(r.LeftBottom(), r.LeftTop(), M_DARK_GRAY_COLOR); 968 r.InsetBy(1.0, 1.0); 969 target->AddLine(r.LeftTop(), r.RightTop(), M_LIGHT_GRAY_COLOR); 970 target->AddLine(r.RightTop(), r.RightBottom(), M_MED_GRAY_COLOR); 971 target->AddLine(r.RightBottom(), r.LeftBottom(), M_MED_GRAY_COLOR); 972 target->AddLine(r.LeftBottom(), r.LeftTop(), M_LIGHT_GRAY_COLOR); 973 target->EndLineArray(); 974 975 // Fill background 976 r.InsetBy(1.0, 1.0); 977 target->SetLowColor(M_GRAY_COLOR); 978 target->FillRect(r, B_SOLID_LOW); 979 980 // Draw icon 981 if (m_icon) 982 { 983 p.x = m_bodyRect.left + M_BODY_H_MARGIN; 984 p.y = m_bodyRect.top + (m_bodyRect.Height() / 2.0) - (B_MINI_ICON / 2.0); 985 if (isSelected()) 986 { 987 target->SetDrawingMode(B_OP_INVERT); 988 target->DrawBitmapAsync(m_icon, p); 989 target->SetDrawingMode(B_OP_ALPHA); 990 target->SetHighColor(0, 0, 0, 180); 991 target->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE); 992 target->DrawBitmapAsync(m_icon, p); 993 target->SetDrawingMode(B_OP_OVER); 994 } 995 else 996 { 997 target->SetDrawingMode(B_OP_OVER); 998 target->DrawBitmapAsync(m_icon, p); 999 } 1000 } 1001 1002 // Draw label 1003 if (isSelected()) 1004 { 1005 r = m_labelRect; 1006 r.InsetBy(M_LABEL_H_MARGIN, M_LABEL_V_MARGIN); 1007 target->BeginLineArray(4); 1008 target->AddLine(r.LeftTop(), r.RightTop(), M_LIGHT_BLUE_COLOR); 1009 target->AddLine(r.RightTop(), r.RightBottom(), M_LIGHT_BLUE_COLOR); 1010 target->AddLine(r.RightBottom(), r.LeftBottom(), M_LIGHT_BLUE_COLOR); 1011 target->AddLine(r.LeftBottom(), r.LeftTop(), M_LIGHT_BLUE_COLOR); 1012 target->EndLineArray(); 1013 r.InsetBy(1.0, 1.0); 1014 target->SetHighColor(M_DARK_BLUE_COLOR); 1015 target->FillRect(r, B_SOLID_HIGH); 1016 } 1017 target->SetDrawingMode(B_OP_OVER); 1018 target->SetHighColor(isSelected() ? M_WHITE_COLOR : M_BLACK_COLOR); 1019 target->DrawString(m_label.String(), m_labelOffset); 1020 break; 1021 } 1022 } 1023 } 1024 1025 void MediaNodePanel::_updateIcon( 1026 int32 layout) 1027 { 1028 D_METHOD(("MediaNodePanel::_updateIcon()\n")); 1029 1030 if (m_icon) 1031 { 1032 delete m_icon; 1033 m_icon = 0; 1034 } 1035 RouteAppNodeManager *manager; 1036 manager = dynamic_cast<MediaRoutingView *>(view())->manager; 1037 switch (layout) 1038 { 1039 case MediaRoutingView::M_ICON_VIEW: 1040 { 1041 const MediaIcon *icon = manager->mediaIconFor(ref->id(), B_LARGE_ICON); 1042 m_icon = new BBitmap(dynamic_cast<const BBitmap *>(icon)); 1043 break; 1044 } 1045 case MediaRoutingView::M_MINI_ICON_VIEW: 1046 { 1047 const MediaIcon *icon = manager->mediaIconFor(ref->id(), B_MINI_ICON); 1048 m_icon = new BBitmap(dynamic_cast<const BBitmap *>(icon)); 1049 break; 1050 } 1051 } 1052 } 1053 1054 // -------------------------------------------------------- // 1055 // *** sorting methods (friend) 1056 // -------------------------------------------------------- // 1057 1058 int __CORTEX_NAMESPACE__ compareID( 1059 const void *lValue, 1060 const void *rValue) 1061 { 1062 int retValue = 0; 1063 const MediaNodePanel *lPanel = *(reinterpret_cast<MediaNodePanel * const*>(reinterpret_cast<void * const*>(lValue))); 1064 const MediaNodePanel *rPanel = *(reinterpret_cast<MediaNodePanel * const*>(reinterpret_cast<void * const*>(rValue))); 1065 if (lPanel && rPanel) 1066 { 1067 if (lPanel->ref->id() < rPanel->ref->id()) 1068 { 1069 retValue = -1; 1070 } 1071 else if (lPanel->ref->id() > rPanel->ref->id()) 1072 { 1073 retValue = 1; 1074 } 1075 } 1076 return retValue; 1077 } 1078 1079 // END -- MediaNodePanel.cpp -- 1080