repository_infos: Enable automatic updates on the main Haiku repostiory.
[haiku.git] / src / apps / cortex / MediaRoutingView / MediaNodePanel.cpp
blob92d6864cf054ad72eebdfebdd2cfc28e056ab361
1 /*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
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.
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.
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.
32 // MediaNodePanel.cpp
33 // c.lenz 10oct99
35 #include "MediaNodePanel.h"
36 // InfoWindow
37 #include "InfoWindowManager.h"
38 // MediaRoutingView
39 #include "MediaRoutingView.h"
40 #include "MediaWire.h"
41 #include "RouteAppNodeManager.h"
42 // NodeManager
43 #include "NodeRef.h"
44 #include "NodeGroup.h"
45 // ParameterWindow
46 #include "ParameterWindow.h"
47 // Support
48 #include "cortex_ui.h"
49 #include "MediaIcon.h"
50 #include "MediaString.h"
51 // RouteApp
52 #include "RouteWindow.h"
53 // TipManager
54 #include "TipManager.h"
56 // App Kit
57 #include <Application.h>
58 #include <Roster.h>
59 // Interface Kit
60 #include <MenuItem.h>
61 #include <PopUpMenu.h>
62 // Media Kit
63 #include <MediaDefs.h>
64 #include <MediaRoster.h>
66 using namespace std;
68 __USE_CORTEX_NAMESPACE
70 #include <Debug.h>
71 #define D_METHOD(x) //PRINT (x)
72 #define D_MESSAGE(x) //PRINT (x)
73 #define D_DRAW(x) //PRINT (x)
75 // -------------------------------------------------------- //
76 // constants
77 // -------------------------------------------------------- //
79 float MediaNodePanel::M_DEFAULT_WIDTH = 90.0;
80 float MediaNodePanel::M_DEFAULT_HEIGHT = 60.0;
81 float MediaNodePanel::M_LABEL_H_MARGIN = 3.0;
82 float MediaNodePanel::M_LABEL_V_MARGIN = 3.0;
83 float MediaNodePanel::M_BODY_H_MARGIN = 5.0;
84 float MediaNodePanel::M_BODY_V_MARGIN = 5.0;
86 // [e.moon 7dec99]
87 const BPoint MediaNodePanel::s_invalidPosition(-200.0, -200.0);
89 // -------------------------------------------------------- //
90 // *** ctor/dtor
91 // -------------------------------------------------------- //
93 MediaNodePanel::MediaNodePanel(
94 BPoint position,
95 NodeRef *nodeRef)
96 : DiagramBox(BRect(position, position + BPoint(M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT))),
97 BHandler(nodeRef->name()),
98 ref(nodeRef),
99 m_bitmap(0),
100 m_icon(0),
101 m_alternatePosition(s_invalidPosition)
103 D_METHOD(("MediaNodePanel::MediaNodePanel()\n"));
104 ASSERT(ref);
107 MediaNodePanel::~MediaNodePanel()
109 D_METHOD(("MediaNodePanel::~MediaNodePanel()\n"));
110 if (m_icon)
112 delete m_icon;
114 if (m_bitmap)
116 delete m_bitmap;
120 // -------------------------------------------------------- //
121 // *** derived from DiagramBox
122 // -------------------------------------------------------- //
124 void MediaNodePanel::attachedToDiagram()
126 D_METHOD(("MediaNodePanel::attachedToDiagram()\n"));
128 resizeTo(M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT);
129 _updateIcon(dynamic_cast<MediaRoutingView *>(view())->getLayout());
130 _prepareLabel();
131 populateInit();
132 arrangeIOJacks();
134 view()->Looper()->AddHandler(this);
137 void MediaNodePanel::detachedFromDiagram()
139 D_METHOD(("MediaNodePanel::detachedFromDiagram()\n"));
141 BRect labelRect = m_labelRect.OffsetByCopy(Frame().LeftTop());
142 if (m_mouseOverLabel && m_labelTruncated)
144 TipManager *tips = TipManager::Instance();
145 tips->hideTip(view()->ConvertToScreen(labelRect));
148 view()->Looper()->RemoveHandler(this);
151 void MediaNodePanel::DrawBox()
153 D_DRAW(("MediaNodePanel::DrawBox()\n"));
154 if (m_bitmap)
156 view()->DrawBitmap(m_bitmap, Frame().LeftTop());
160 void MediaNodePanel::MouseDown(
161 BPoint point,
162 uint32 buttons,
163 uint32 clicks)
165 D_METHOD(("MediaNodePanel::MouseDown()\n"));
167 _inherited::MouseDown(point, buttons, clicks);
169 // +++ REALLY BAD WORKAROUND
170 MediaJack *jack = dynamic_cast<MediaJack *>(_LastItemUnder());
171 if (jack && jack->Frame().Contains(point))
173 return;
176 switch (buttons) {
177 case B_PRIMARY_MOUSE_BUTTON:
179 if (clicks == 2) {
180 if (ref->kind() & B_CONTROLLABLE) {
181 BMessage message(MediaRoutingView::M_NODE_TWEAK_PARAMETERS);
182 DiagramView* v = view();
183 BMessenger(v).SendMessage(&message);
186 break;
188 case B_SECONDARY_MOUSE_BUTTON:
190 if (clicks == 1) {
191 showContextMenu(point);
193 break;
198 void MediaNodePanel::MouseOver(
199 BPoint point,
200 uint32 transit)
202 D_METHOD(("MediaNodePanel::MouseOver()\n"));
203 _inherited::MouseOver(point, transit);
205 switch (transit)
207 case B_ENTERED_VIEW:
209 break;
211 case B_INSIDE_VIEW:
213 BRect labelRect = m_labelRect.OffsetByCopy(Frame().LeftTop());
214 if (labelRect.Contains(point))
216 if (!m_mouseOverLabel && m_labelTruncated)
218 TipManager *tips = TipManager::Instance();
219 tips->showTip(m_fullLabel.String(), view()->ConvertToScreen(labelRect));
220 m_mouseOverLabel = true;
223 else
225 m_mouseOverLabel = false;
227 break;
229 case B_EXITED_VIEW:
231 m_mouseOverLabel = false;
232 break;
237 void MediaNodePanel::MessageDropped(
238 BPoint point,
239 BMessage *message)
241 D_METHOD(("MediaNodePanel::MessageDropped()\n"));
243 // +++ REALLY BAD WORKAROUND
244 MediaJack *jack = dynamic_cast<MediaJack *>(ItemUnder(point));
245 if (jack)
247 jack->MessageDropped(point, message);
248 return;
250 else
252 be_app->SetCursor(B_HAND_CURSOR);
256 void MediaNodePanel::selected()
258 D_METHOD(("MediaNodePanel::selected()\n"));
259 _updateBitmap();
262 void MediaNodePanel::deselected()
264 D_METHOD(("MediaNodePanel::deselected()\n"));
265 _updateBitmap();
268 // ---------------------------------------------------------------- //
269 // *** updating
270 // ---------------------------------------------------------------- //
272 void MediaNodePanel::layoutChanged(
273 int32 layout)
275 D_METHOD(("MediaNodePanel::layoutChanged()\n"));
277 BPoint p = Frame().LeftTop();
278 if (m_alternatePosition == s_invalidPosition)
280 m_alternatePosition = dynamic_cast<MediaRoutingView *>
281 (view())->findFreePositionFor(this);
283 moveTo(m_alternatePosition);
284 m_alternatePosition = p;
286 resizeTo(M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT);
287 for (uint32 i = 0; i < CountItems(); i++)
289 MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i));
290 jack->layoutChanged(layout);
292 _updateIcon(layout);
293 _prepareLabel();
294 arrangeIOJacks();
295 _updateBitmap();
298 void MediaNodePanel::populateInit()
300 D_METHOD(("MediaNodePanel::populateInit()\n"));
301 if (ref->kind() & B_BUFFER_CONSUMER)
303 vector<media_input> freeInputs;
304 ref->getFreeInputs(freeInputs);
305 for (uint32 i = 0; i < freeInputs.size(); i++)
307 AddItem(new MediaJack(freeInputs[i]));
310 if (ref->kind() & B_BUFFER_PRODUCER)
312 vector<media_output> freeOutputs;
313 ref->getFreeOutputs(freeOutputs);
314 for (uint32 i = 0; i < freeOutputs.size(); i++)
316 AddItem(new MediaJack(freeOutputs[i]));
321 void MediaNodePanel::updateIOJacks()
323 D_METHOD(("MediaNodePanel::updateIOJacks()\n"));
325 // remove all free inputs/outputs, they may be outdated
326 for (uint32 i = 0; i < CountItems(); i++)
328 MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i));
329 if (jack && !jack->isConnected())
331 RemoveItem(jack);
332 delete jack;
333 i--; // account for reindexing in the BList
337 // add free inputs
338 if (ref->kind() & B_BUFFER_CONSUMER)
340 vector<media_input> freeInputs;
341 ref->getFreeInputs(freeInputs);
342 for (uint32 i = 0; i < freeInputs.size(); i++)
344 MediaJack *jack;
345 AddItem(jack = new MediaJack(freeInputs[i]));
349 // add free outputs
350 if (ref->kind() & B_BUFFER_PRODUCER)
352 vector<media_output> freeOutputs;
353 ref->getFreeOutputs(freeOutputs);
354 for (uint32 i = 0; i < freeOutputs.size(); i++)
356 MediaJack *jack;
357 AddItem(jack = new MediaJack(freeOutputs[i]));
361 // the supported media types might have changed -> this could
362 // require changing the icon
363 _updateIcon(dynamic_cast<MediaRoutingView *>(view())->getLayout());
366 void MediaNodePanel::arrangeIOJacks()
368 D_METHOD(("MediaNodePanel::arrangeIOJacks()\n"));
369 SortItems(DiagramItem::M_ENDPOINT, &compareTypeAndID);
371 switch (dynamic_cast<MediaRoutingView *>(view())->getLayout())
373 case MediaRoutingView::M_ICON_VIEW:
375 BRegion updateRegion;
376 float align = 1.0;
377 view()->GetItemAlignment(0, &align);
379 // adjust this panel's size
380 int32 numInputs = 0, numOutputs = 0;
381 for (uint32 i = 0; i < CountItems(); i++)
383 MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i));
384 if (jack)
386 if (jack->isInput())
388 numInputs++;
390 if (jack->isOutput())
392 numOutputs++;
396 float minHeight = MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP;
397 minHeight *= numInputs > numOutputs ? numInputs : numOutputs;
398 minHeight += m_labelRect.Height();
399 minHeight += 2 * MediaJack::M_DEFAULT_GAP;
400 minHeight = ((int)minHeight / (int)align) * align + align;
401 if ((Frame().Height() < minHeight)
402 || ((Frame().Height() > minHeight)
403 && (minHeight >= MediaNodePanel::M_DEFAULT_HEIGHT)))
405 updateRegion.Include(Frame());
406 resizeTo(Frame().Width(), minHeight);
407 updateRegion.Include(Frame());
408 _prepareLabel();
411 // adjust the placement of the jacks
412 BRect r = m_bodyRect;
413 r.bottom -= M_BODY_V_MARGIN;
414 float inputOffset = 0.0, outputOffset = 0.0;
415 float center = Frame().top + r.top + (r.Height() / 2.0);
416 center += MediaJack::M_DEFAULT_GAP - (MediaJack::M_DEFAULT_HEIGHT / 2.0);
417 center = ((int)center / (int)align) * align;
418 if (numInputs)
420 if (numInputs % 2) // odd number of inputs
422 inputOffset = center - (numInputs / 2) * (MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP);
424 else // even number of inputs
426 inputOffset = center - ((numInputs + 1) / 2) * (MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP);
429 if (numOutputs)
431 if (numOutputs % 2) // odd number of outputs
433 outputOffset = center - (numOutputs / 2) * (MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP);
435 else // even number of outputs
437 outputOffset = center - ((numOutputs + 1) / 2) * (MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP);
440 for (uint32 i = 0; i < CountItems(); i++)
442 MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i));
443 if (jack)
445 if (jack->isInput())
447 jack->setPosition(inputOffset, Frame().left, Frame().right, &updateRegion);
448 inputOffset += jack->Frame().Height() + MediaJack::M_DEFAULT_GAP;
450 if (jack->isOutput())
452 jack->setPosition(outputOffset, Frame().left, Frame().right, &updateRegion);
453 outputOffset += jack->Frame().Height() + MediaJack::M_DEFAULT_GAP;
457 for (int32 i = 0; i < updateRegion.CountRects(); i++)
459 view()->Invalidate(updateRegion.RectAt(i));
461 break;
463 case MediaRoutingView::M_MINI_ICON_VIEW:
465 BRegion updateRegion;
466 float align = 1.0;
467 view()->GetItemAlignment(&align, 0);
469 // adjust this panel's size
470 int32 numInputs = 0, numOutputs = 0;
471 for (uint32 i = 0; i < CountItems(); i++)
473 MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i));
474 if (jack)
476 if (jack->isInput())
478 numInputs++;
480 if (jack->isOutput())
482 numOutputs++;
486 float minWidth = MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP;
487 minWidth *= numInputs > numOutputs ? numInputs : numOutputs;
488 minWidth += m_bodyRect.Width();
489 minWidth += 2 * MediaJack::M_DEFAULT_GAP;
490 minWidth = ((int)minWidth / (int)align) * align + align;
491 if ((Frame().Width() < minWidth)
492 || ((Frame().Width() > minWidth)
493 && (minWidth >= MediaNodePanel::M_DEFAULT_WIDTH)))
495 updateRegion.Include(Frame());
496 resizeTo(minWidth, Frame().Height());
497 updateRegion.Include(Frame());
498 _prepareLabel();
500 // adjust the placement of the jacks
501 float inputOffset = 0.0, outputOffset = 0.0;
502 float center = Frame().left + m_labelRect.left + (m_labelRect.Width() / 2.0);
503 center += MediaJack::M_DEFAULT_GAP - (MediaJack::M_DEFAULT_WIDTH / 2.0);
504 center = ((int)center / (int)align) * align;
505 if (numInputs)
507 if (numInputs % 2) // odd number of inputs
509 inputOffset = center - (numInputs / 2) * (MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP);
511 else // even number of inputs
513 inputOffset = center - ((numInputs + 1) / 2) * (MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP);
516 if (numOutputs)
518 if (numOutputs % 2) // odd number of outputs
520 outputOffset = center - (numOutputs / 2) * (MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP);
522 else // even number of outputs
524 outputOffset = center - ((numOutputs + 1) / 2) * (MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP);
527 for (uint32 i = 0; i < CountItems(); i++)
529 MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i));
530 if (jack)
532 if (jack->isInput())
534 jack->setPosition(inputOffset, Frame().top, Frame().bottom, &updateRegion);
535 inputOffset += jack->Frame().Width() + MediaJack::M_DEFAULT_GAP;
537 if (jack->isOutput())
539 jack->setPosition(outputOffset, Frame().top, Frame().bottom, &updateRegion);
540 outputOffset += jack->Frame().Width() + MediaJack::M_DEFAULT_GAP;
544 for (int32 i = 0; i < updateRegion.CountRects(); i++)
546 view()->Invalidate(updateRegion.RectAt(i));
548 break;
551 _updateBitmap();
554 void MediaNodePanel::showContextMenu(
555 BPoint point)
557 D_METHOD(("MediaNodePanel::showContextMenu()\n"));
559 BPopUpMenu *menu = new BPopUpMenu("MediaNodePanel PopUp", false, false, B_ITEMS_IN_COLUMN);
560 menu->SetFont(be_plain_font);
562 BMenuItem *item;
563 BMessage *message;
565 // add the "Tweak Parameters" item
566 message = new BMessage(MediaRoutingView::M_NODE_TWEAK_PARAMETERS);
567 menu->AddItem(item = new BMenuItem("Tweak parameters", message, 'P'));
568 if (!(ref->kind() & B_CONTROLLABLE))
570 item->SetEnabled(false);
573 message = new BMessage(InfoWindowManager::M_INFO_WINDOW_REQUESTED);
574 message->AddInt32("nodeID", ref->id());
575 menu->AddItem(new BMenuItem("Get info", message, 'I'));
576 menu->AddSeparatorItem();
578 menu->AddItem(item = new BMenuItem("Release", new BMessage(MediaRoutingView::M_DELETE_SELECTION), 'T'));
579 if (!ref->isInternal())
581 item->SetEnabled(false);
583 menu->AddSeparatorItem();
585 // add the "Cycle" item
586 message = new BMessage(MediaRoutingView::M_NODE_CHANGE_CYCLING);
587 message->AddBool("cycle", !ref->isCycling());
588 menu->AddItem(item = new BMenuItem("Cycle", message));
589 item->SetMarked(ref->isCycling());
590 if (ref->flags() & NodeRef::NO_SEEK)
592 item->SetEnabled(false);
595 // add the "Run Mode" sub menu
596 BMenu *subMenu = new BMenu("Run mode");
597 subMenu->SetFont(be_plain_font);
598 for (uint32 runMode = 1; runMode <= BMediaNode::B_RECORDING; runMode++)
600 BString itemName = MediaString::getStringFor(static_cast<BMediaNode::run_mode>
601 (runMode));
602 message = new BMessage(MediaRoutingView::M_NODE_CHANGE_RUN_MODE);
603 message->AddInt32("run_mode", runMode);
604 subMenu->AddItem(item = new BMenuItem(itemName.String(), message));
605 if (ref->runMode() == runMode)
607 item->SetMarked(true);
609 else if ((ref->runMode() == 0)
610 && (ref->group()) && (ref->group()->runMode() == BMediaNode::run_mode(runMode)))
612 item->SetMarked(true);
615 subMenu->AddSeparatorItem();
616 message = new BMessage(MediaRoutingView::M_NODE_CHANGE_RUN_MODE);
617 message->AddInt32("run_mode", 0);
618 subMenu->AddItem(item = new BMenuItem("(same as group)", message));
619 if (ref->group() == 0)
621 item->SetEnabled(false);
623 else if ((ref->runMode() < 1) && (ref->group()->runMode() > 0))
625 item->SetMarked(true);
627 menu->AddItem(subMenu);
628 subMenu->SetTargetForItems(view());
630 // [c.lenz 24dec99] hide rarely used commands in a 'Advanced' submenu
631 subMenu = new BMenu("Advanced");
632 subMenu->SetFont(be_plain_font);
633 // [e.moon 5dec99] ad-hoc timesource support
634 if(ref->kind() & B_TIME_SOURCE) {
635 message = new BMessage(MediaRoutingView::M_NODE_START_TIME_SOURCE);
636 message->AddInt32("nodeID", ref->id());
637 subMenu->AddItem(new BMenuItem(
638 "Start time source",
639 message));
640 message = new BMessage(MediaRoutingView::M_NODE_START_TIME_SOURCE);
641 message->AddInt32("nodeID", ref->id());
642 subMenu->AddItem(new BMenuItem(
643 "Stop time source",
644 message));
646 // [c.lenz 24dec99] support for BControllable::StartControlPanel()
647 if(ref->kind() & B_CONTROLLABLE) {
648 if (subMenu->CountItems() > 0)
649 subMenu->AddSeparatorItem();
650 message = new BMessage(MediaRoutingView::M_NODE_START_CONTROL_PANEL);
651 subMenu->AddItem(new BMenuItem("Start Control Panel", message,
652 'P', B_COMMAND_KEY | B_SHIFT_KEY));
654 // [em 1feb00] group tweaks
655 if(ref->group())
657 message = new BMessage(MediaRoutingView::M_GROUP_SET_LOCKED);
658 message->AddInt32("groupID", ref->group()->id());
659 bool isLocked = (ref->group()->groupFlags() & NodeGroup::GROUP_LOCKED);
660 message->AddBool("locked", !isLocked);
661 if (subMenu->CountItems() > 0)
662 subMenu->AddSeparatorItem();
663 subMenu->AddItem(
664 new BMenuItem(
665 isLocked ? "Unlock group" : "Lock group", message));
668 if (subMenu->CountItems() > 0)
670 menu->AddItem(subMenu);
671 subMenu->SetTargetForItems(view());
674 menu->SetTargetForItems(view());
675 view()->ConvertToScreen(&point);
676 point -= BPoint(1.0, 1.0);
677 menu->Go(point, true, true, true);
680 // ---------------------------------------------------------------- //
681 // BHandler impl
682 // ---------------------------------------------------------------- //
684 void MediaNodePanel::MessageReceived(
685 BMessage *message)
687 D_METHOD(("MediaNodePanel::MessageReceived()\n"));
688 switch (message->what)
690 case NodeRef::M_INPUTS_CHANGED:
692 D_MESSAGE(("MediaNodePanel::MessageReceived(NodeRef::M_INPUTS_CHANGED)\n"));
693 _updateIcon(dynamic_cast<MediaRoutingView *>(view())->getLayout());
694 break;
696 case NodeRef::M_OUTPUTS_CHANGED:
698 D_MESSAGE(("MediaNodePanel::MessageReceived(NodeRef::M_OUTPUTS_CHANGED)\n"));
699 _updateIcon(dynamic_cast<MediaRoutingView *>(view())->getLayout());
700 break;
702 default:
704 BHandler::MessageReceived(message);
705 break;
710 // -------------------------------------------------------- //
711 // *** IStateArchivable
712 // -------------------------------------------------------- //
714 status_t MediaNodePanel::importState(
715 const BMessage* archive) {
717 BPoint iconPos(s_invalidPosition);
718 BPoint miniIconPos(s_invalidPosition);
720 MediaRoutingView* v = dynamic_cast<MediaRoutingView*>(view());
721 ASSERT(v);
722 MediaRoutingView::layout_t layoutMode = v->getLayout();
723 archive->FindPoint("iconPos", &iconPos);
724 archive->FindPoint("miniIconPos", &miniIconPos);
726 switch(layoutMode) {
727 case MediaRoutingView::M_ICON_VIEW:
728 if(iconPos != s_invalidPosition)
729 moveTo(iconPos);
730 m_alternatePosition = miniIconPos;
731 break;
733 case MediaRoutingView::M_MINI_ICON_VIEW:
734 if(miniIconPos != s_invalidPosition)
735 moveTo(miniIconPos);
736 m_alternatePosition = iconPos;
737 break;
740 return B_OK;
743 status_t MediaNodePanel::exportState(
744 BMessage* archive) const {
746 BPoint iconPos, miniIconPos;
748 MediaRoutingView* v = dynamic_cast<MediaRoutingView*>(view());
749 ASSERT(v);
750 MediaRoutingView::layout_t layoutMode = v->getLayout();
751 switch(layoutMode) {
752 case MediaRoutingView::M_ICON_VIEW:
753 iconPos = Frame().LeftTop();
754 miniIconPos = m_alternatePosition;
755 break;
757 case MediaRoutingView::M_MINI_ICON_VIEW:
758 miniIconPos = Frame().LeftTop();
759 iconPos = m_alternatePosition;
760 break;
763 if(iconPos != s_invalidPosition)
764 archive->AddPoint("iconPos", iconPos);
765 if(miniIconPos != s_invalidPosition)
766 archive->AddPoint("miniIconPos", miniIconPos);
768 // determine if I'm a 'system' node
769 port_info portInfo;
770 app_info appInfo;
772 if ((get_port_info(ref->node().port, &portInfo) == B_OK)
773 && (be_roster->GetRunningAppInfo(portInfo.team, &appInfo) == B_OK)) {
774 BEntry appEntry(&appInfo.ref);
775 char appName[B_FILE_NAME_LENGTH];
777 appEntry.InitCheck() == B_OK &&
778 appEntry.GetName(appName) == B_OK &&
779 (!strcmp(appName, "media_addon_server") ||
780 !strcmp(appName, "audio_server"))) {
782 archive->AddBool("sysOwned", true);
786 return B_OK;
789 // ---------------------------------------------------------------- //
790 // *** internal operations
791 // ---------------------------------------------------------------- //
793 void MediaNodePanel::_prepareLabel()
795 // find out if its a file node first
796 if (ref->kind() & B_FILE_INTERFACE)
798 entry_ref nodeFile;
799 status_t error = BMediaRoster::Roster()->GetRefFor(ref->node(), &nodeFile);
800 if (error)
802 m_fullLabel = ref->name();
803 m_fullLabel += " (no file)";
805 else
807 BEntry entry(&nodeFile);
808 char fileName[B_FILE_NAME_LENGTH];
809 entry.GetName(fileName);
810 m_fullLabel = fileName;
813 else
815 m_fullLabel = ref->name();
818 int32 layout = dynamic_cast<MediaRoutingView *>(view())->getLayout();
820 // Construct labelRect
821 font_height fh;
822 be_plain_font->GetHeight(&fh);
823 switch (layout)
825 case MediaRoutingView::M_ICON_VIEW:
827 m_labelRect = Frame();
828 m_labelRect.OffsetTo(0.0, 0.0);
829 m_labelRect.bottom = 2 * M_LABEL_V_MARGIN + (fh.ascent + fh.descent + fh.leading) + 1.0;
830 break;
832 case MediaRoutingView::M_MINI_ICON_VIEW:
834 m_labelRect = Frame();
835 m_labelRect.OffsetTo(0.0, 0.0);
836 m_labelRect.left = M_BODY_H_MARGIN + B_MINI_ICON;
837 m_labelRect.top += MediaJack::M_DEFAULT_HEIGHT;
838 m_labelRect.bottom -= MediaJack::M_DEFAULT_HEIGHT;
839 break;
843 // truncate the label to fit in the panel
844 float maxWidth = m_labelRect.Width() - (2.0 * M_LABEL_H_MARGIN) - 2.0;
845 if (be_plain_font->StringWidth(m_fullLabel.String()) > maxWidth)
847 char *truncatedLabel[1];
848 truncatedLabel[0] = new char[B_MEDIA_NAME_LENGTH];
849 const char *originalLabel[1];
850 originalLabel[0] = new char[B_MEDIA_NAME_LENGTH];
851 m_fullLabel.CopyInto(const_cast<char *>(originalLabel[0]), 0, B_MEDIA_NAME_LENGTH);
852 be_plain_font->GetTruncatedStrings(originalLabel, 1, B_TRUNCATE_END, maxWidth, (char **) truncatedLabel);
853 m_label = truncatedLabel[0];
854 m_labelTruncated = true;
855 delete [] originalLabel[0];
856 delete [] truncatedLabel[0];
858 else
860 m_label = m_fullLabel;
861 m_labelTruncated = false;
864 // Construct labelOffset
865 float fw = be_plain_font->StringWidth(m_label.String());
866 m_labelOffset.x = m_labelRect.left + m_labelRect.Width() / 2.0 - fw / 2.0;
867 m_labelOffset.y = m_labelRect.bottom - M_LABEL_V_MARGIN - fh.descent - (fh.leading / 2.0) - 1.0;
869 // Construct bodyRect
870 switch (layout)
872 case MediaRoutingView::M_ICON_VIEW:
874 m_bodyRect = Frame();
875 m_bodyRect.OffsetTo(0.0, 0.0);
876 m_bodyRect.top = m_labelRect.bottom;
877 break;
879 case MediaRoutingView::M_MINI_ICON_VIEW:
881 m_bodyRect = Frame();
882 m_bodyRect.OffsetTo(0.0, 0.0);
883 m_bodyRect.right = m_labelRect.left;
884 break;
889 void MediaNodePanel::_updateBitmap()
891 if (m_bitmap)
893 delete m_bitmap;
895 BBitmap *tempBitmap = new BBitmap(Frame().OffsetToCopy(0.0, 0.0), B_CMAP8, true);
896 tempBitmap->Lock();
898 BView *tempView = new BView(tempBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
899 tempBitmap->AddChild(tempView);
900 tempView->SetOrigin(0.0, 0.0);
902 int32 layout = dynamic_cast<MediaRoutingView *>(view())->getLayout();
903 _drawInto(tempView, tempView->Bounds(), layout);
905 tempView->Sync();
906 tempBitmap->RemoveChild(tempView);
907 delete tempView;
909 tempBitmap->Unlock();
910 m_bitmap = new BBitmap(tempBitmap);
911 delete tempBitmap;
914 void MediaNodePanel::_drawInto(
915 BView *target,
916 BRect targetRect,
917 int32 layout)
919 switch (layout)
921 case MediaRoutingView::M_ICON_VIEW:
923 BRect r;
924 BPoint p;
926 // Draw borders
927 r = targetRect;
928 target->BeginLineArray(16);
929 target->AddLine(r.LeftTop(), r.RightTop(), M_DARK_GRAY_COLOR);
930 target->AddLine(r.RightTop(), r.RightBottom(), M_DARK_GRAY_COLOR);
931 target->AddLine(r.RightBottom(), r.LeftBottom(), M_DARK_GRAY_COLOR);
932 target->AddLine(r.LeftBottom(), r.LeftTop(), M_DARK_GRAY_COLOR);
933 r.InsetBy(1.0, 1.0);
934 target->AddLine(r.LeftTop(), r.RightTop(), M_LIGHT_GRAY_COLOR);
935 target->AddLine(r.RightTop(), r.RightBottom(), M_MED_GRAY_COLOR);
936 target->AddLine(r.RightBottom(), r.LeftBottom(), M_MED_GRAY_COLOR);
937 target->AddLine(r.LeftBottom(), r.LeftTop(), M_LIGHT_GRAY_COLOR);
938 target->EndLineArray();
940 // Fill background
941 r.InsetBy(1.0, 1.0);
942 target->SetLowColor(M_GRAY_COLOR);
943 target->FillRect(r, B_SOLID_LOW);
945 // Draw icon
946 if (m_icon)
948 p.x = m_bodyRect.left + m_bodyRect.Width() / 2.0 - B_LARGE_ICON / 2.0;
949 p.y = m_labelRect.bottom + m_bodyRect.Height() / 2.0 - B_LARGE_ICON / 2.0;
950 if (isSelected())
952 target->SetDrawingMode(B_OP_INVERT);
953 target->DrawBitmapAsync(m_icon, p);
954 target->SetDrawingMode(B_OP_ALPHA);
955 target->SetHighColor(0, 0, 0, 180);
956 target->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
957 target->DrawBitmapAsync(m_icon, p);
958 target->SetDrawingMode(B_OP_OVER);
960 else
962 target->SetDrawingMode(B_OP_OVER);
963 target->DrawBitmapAsync(m_icon, p);
967 // Draw label
968 if (isSelected())
970 r = m_labelRect;
971 r.InsetBy(M_LABEL_H_MARGIN, M_LABEL_V_MARGIN);
972 target->BeginLineArray(4);
973 target->AddLine(r.LeftTop(), r.RightTop(), M_LIGHT_BLUE_COLOR);
974 target->AddLine(r.RightTop(), r.RightBottom(), M_LIGHT_BLUE_COLOR);
975 target->AddLine(r.RightBottom(), r.LeftBottom(), M_LIGHT_BLUE_COLOR);
976 target->AddLine(r.LeftBottom(), r.LeftTop(), M_LIGHT_BLUE_COLOR);
977 target->EndLineArray();
978 r.InsetBy(1.0, 1.0);
979 target->SetHighColor(M_DARK_BLUE_COLOR);
980 target->FillRect(r, B_SOLID_HIGH);
982 target->SetDrawingMode(B_OP_OVER);
983 target->SetHighColor(isSelected() ? M_WHITE_COLOR : M_BLACK_COLOR);
984 target->DrawString(m_label.String(), m_labelOffset);
985 break;
987 case MediaRoutingView::M_MINI_ICON_VIEW:
989 BRect r;
990 BPoint p;
992 // Draw borders
993 r = targetRect;
994 target->BeginLineArray(16);
995 target->AddLine(r.LeftTop(), r.RightTop(), M_DARK_GRAY_COLOR);
996 target->AddLine(r.RightTop(), r.RightBottom(), M_DARK_GRAY_COLOR);
997 target->AddLine(r.RightBottom(), r.LeftBottom(), M_DARK_GRAY_COLOR);
998 target->AddLine(r.LeftBottom(), r.LeftTop(), M_DARK_GRAY_COLOR);
999 r.InsetBy(1.0, 1.0);
1000 target->AddLine(r.LeftTop(), r.RightTop(), M_LIGHT_GRAY_COLOR);
1001 target->AddLine(r.RightTop(), r.RightBottom(), M_MED_GRAY_COLOR);
1002 target->AddLine(r.RightBottom(), r.LeftBottom(), M_MED_GRAY_COLOR);
1003 target->AddLine(r.LeftBottom(), r.LeftTop(), M_LIGHT_GRAY_COLOR);
1004 target->EndLineArray();
1006 // Fill background
1007 r.InsetBy(1.0, 1.0);
1008 target->SetLowColor(M_GRAY_COLOR);
1009 target->FillRect(r, B_SOLID_LOW);
1011 // Draw icon
1012 if (m_icon)
1014 p.x = m_bodyRect.left + M_BODY_H_MARGIN;
1015 p.y = m_bodyRect.top + (m_bodyRect.Height() / 2.0) - (B_MINI_ICON / 2.0);
1016 if (isSelected())
1018 target->SetDrawingMode(B_OP_INVERT);
1019 target->DrawBitmapAsync(m_icon, p);
1020 target->SetDrawingMode(B_OP_ALPHA);
1021 target->SetHighColor(0, 0, 0, 180);
1022 target->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
1023 target->DrawBitmapAsync(m_icon, p);
1024 target->SetDrawingMode(B_OP_OVER);
1026 else
1028 target->SetDrawingMode(B_OP_OVER);
1029 target->DrawBitmapAsync(m_icon, p);
1033 // Draw label
1034 if (isSelected())
1036 r = m_labelRect;
1037 r.InsetBy(M_LABEL_H_MARGIN, M_LABEL_V_MARGIN);
1038 target->BeginLineArray(4);
1039 target->AddLine(r.LeftTop(), r.RightTop(), M_LIGHT_BLUE_COLOR);
1040 target->AddLine(r.RightTop(), r.RightBottom(), M_LIGHT_BLUE_COLOR);
1041 target->AddLine(r.RightBottom(), r.LeftBottom(), M_LIGHT_BLUE_COLOR);
1042 target->AddLine(r.LeftBottom(), r.LeftTop(), M_LIGHT_BLUE_COLOR);
1043 target->EndLineArray();
1044 r.InsetBy(1.0, 1.0);
1045 target->SetHighColor(M_DARK_BLUE_COLOR);
1046 target->FillRect(r, B_SOLID_HIGH);
1048 target->SetDrawingMode(B_OP_OVER);
1049 target->SetHighColor(isSelected() ? M_WHITE_COLOR : M_BLACK_COLOR);
1050 target->DrawString(m_label.String(), m_labelOffset);
1051 break;
1056 void MediaNodePanel::_updateIcon(
1057 int32 layout)
1059 D_METHOD(("MediaNodePanel::_updateIcon()\n"));
1061 if (m_icon)
1063 delete m_icon;
1064 m_icon = 0;
1066 RouteAppNodeManager *manager;
1067 manager = dynamic_cast<MediaRoutingView *>(view())->manager;
1068 switch (layout)
1070 case MediaRoutingView::M_ICON_VIEW:
1072 const MediaIcon *icon = manager->mediaIconFor(ref->id(), B_LARGE_ICON);
1073 m_icon = new BBitmap(dynamic_cast<const BBitmap *>(icon));
1074 break;
1076 case MediaRoutingView::M_MINI_ICON_VIEW:
1078 const MediaIcon *icon = manager->mediaIconFor(ref->id(), B_MINI_ICON);
1079 m_icon = new BBitmap(dynamic_cast<const BBitmap *>(icon));
1080 break;
1085 // -------------------------------------------------------- //
1086 // *** sorting methods (friend)
1087 // -------------------------------------------------------- //
1089 int __CORTEX_NAMESPACE__ compareID(
1090 const void *lValue,
1091 const void *rValue)
1093 int retValue = 0;
1094 const MediaNodePanel *lPanel = *(reinterpret_cast<MediaNodePanel * const*>(reinterpret_cast<void * const*>(lValue)));
1095 const MediaNodePanel *rPanel = *(reinterpret_cast<MediaNodePanel * const*>(reinterpret_cast<void * const*>(rValue)));
1096 if (lPanel && rPanel)
1098 if (lPanel->ref->id() < rPanel->ref->id())
1100 retValue = -1;
1102 else if (lPanel->ref->id() > rPanel->ref->id())
1104 retValue = 1;
1107 return retValue;
1110 // END -- MediaNodePanel.cpp --