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