/*
* Copyright (c) 1999-2000, Eric Moon.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions, and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// MediaNodePanel.cpp
// c.lenz 10oct99
#include "MediaNodePanel.h"
// InfoWindow
#include "InfoWindowManager.h"
// MediaRoutingView
#include "MediaRoutingView.h"
#include "MediaWire.h"
#include "RouteAppNodeManager.h"
// NodeManager
#include "NodeRef.h"
#include "NodeGroup.h"
// ParameterWindow
#include "ParameterWindow.h"
// Support
#include "cortex_ui.h"
#include "MediaIcon.h"
#include "MediaString.h"
// RouteApp
#include "RouteWindow.h"
// TipManager
#include "TipManager.h"
// App Kit
#include <Application.h>
#include <Roster.h>
// Interface Kit
#include <MenuItem.h>
#include <PopUpMenu.h>
// Media Kit
#include <MediaDefs.h>
#include <MediaRoster.h>
using namespace std;
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT (x)
#define D_MESSAGE(x) //PRINT (x)
#define D_DRAW(x) //PRINT (x)
// -------------------------------------------------------- //
// constants
// -------------------------------------------------------- //
float MediaNodePanel::M_DEFAULT_WIDTH = 90.0;
float MediaNodePanel::M_DEFAULT_HEIGHT = 60.0;
float MediaNodePanel::M_LABEL_H_MARGIN = 3.0;
float MediaNodePanel::M_LABEL_V_MARGIN = 3.0;
float MediaNodePanel::M_BODY_H_MARGIN = 5.0;
float MediaNodePanel::M_BODY_V_MARGIN = 5.0;
// [e.moon 7dec99]
const BPoint MediaNodePanel::s_invalidPosition(-200.0, -200.0);
// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //
MediaNodePanel::MediaNodePanel(
BPoint position,
NodeRef *nodeRef)
: DiagramBox(BRect(position, position + BPoint(M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT))),
BHandler(nodeRef->name()),
ref(nodeRef),
m_bitmap(0),
m_icon(0),
m_alternatePosition(s_invalidPosition)
{
D_METHOD(("MediaNodePanel::MediaNodePanel()\n"));
ASSERT(ref);
}
MediaNodePanel::~MediaNodePanel()
{
D_METHOD(("MediaNodePanel::~MediaNodePanel()\n"));
if (m_icon)
{
delete m_icon;
}
if (m_bitmap)
{
delete m_bitmap;
}
}
// -------------------------------------------------------- //
// *** derived from DiagramBox
// -------------------------------------------------------- //
void MediaNodePanel::attachedToDiagram()
{
D_METHOD(("MediaNodePanel::attachedToDiagram()\n"));
resizeTo(M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT);
_updateIcon(dynamic_cast<MediaRoutingView *>(view())->getLayout());
_prepareLabel();
populateInit();
arrangeIOJacks();
view()->Looper()->AddHandler(this);
}
void MediaNodePanel::detachedFromDiagram()
{
D_METHOD(("MediaNodePanel::detachedFromDiagram()\n"));
BRect labelRect = m_labelRect.OffsetByCopy(Frame().LeftTop());
if (m_mouseOverLabel && m_labelTruncated)
{
TipManager *tips = TipManager::Instance();
tips->hideTip(view()->ConvertToScreen(labelRect));
}
view()->Looper()->RemoveHandler(this);
}
void MediaNodePanel::DrawBox()
{
D_DRAW(("MediaNodePanel::DrawBox()\n"));
if (m_bitmap)
{
view()->DrawBitmap(m_bitmap, Frame().LeftTop());
}
}
void MediaNodePanel::MouseDown(
BPoint point,
uint32 buttons,
uint32 clicks)
{
D_METHOD(("MediaNodePanel::MouseDown()\n"));
_inherited::MouseDown(point, buttons, clicks);
// +++ REALLY BAD WORKAROUND
MediaJack *jack = dynamic_cast<MediaJack *>(_LastItemUnder());
if (jack && jack->Frame().Contains(point))
{
return;
}
switch (buttons) {
case B_PRIMARY_MOUSE_BUTTON:
{
if (clicks == 2) {
if (ref->kind() & B_CONTROLLABLE) {
BMessage message(MediaRoutingView::M_NODE_TWEAK_PARAMETERS);
DiagramView* v = view();
BMessenger(v).SendMessage(&message);
}
}
break;
}
case B_SECONDARY_MOUSE_BUTTON:
{
if (clicks == 1) {
showContextMenu(point);
}
break;
}
}
}
void MediaNodePanel::MouseOver(
BPoint point,
uint32 transit)
{
D_METHOD(("MediaNodePanel::MouseOver()\n"));
_inherited::MouseOver(point, transit);
switch (transit)
{
case B_ENTERED_VIEW:
{
break;
}
case B_INSIDE_VIEW:
{
BRect labelRect = m_labelRect.OffsetByCopy(Frame().LeftTop());
if (labelRect.Contains(point))
{
if (!m_mouseOverLabel && m_labelTruncated)
{
TipManager *tips = TipManager::Instance();
tips->showTip(m_fullLabel.String(), view()->ConvertToScreen(labelRect));
m_mouseOverLabel = true;
}
}
else
{
m_mouseOverLabel = false;
}
break;
}
case B_EXITED_VIEW:
{
m_mouseOverLabel = false;
break;
}
}
}
void MediaNodePanel::MessageDropped(
BPoint point,
BMessage *message)
{
D_METHOD(("MediaNodePanel::MessageDropped()\n"));
// +++ REALLY BAD WORKAROUND
MediaJack *jack = dynamic_cast<MediaJack *>(ItemUnder(point));
if (jack)
{
jack->MessageDropped(point, message);
return;
}
else
{
be_app->SetCursor(B_HAND_CURSOR);
}
}
void MediaNodePanel::selected()
{
D_METHOD(("MediaNodePanel::selected()\n"));
_updateBitmap();
}
void MediaNodePanel::deselected()
{
D_METHOD(("MediaNodePanel::deselected()\n"));
_updateBitmap();
}
// ---------------------------------------------------------------- //
// *** updating
// ---------------------------------------------------------------- //
void MediaNodePanel::layoutChanged(
int32 layout)
{
D_METHOD(("MediaNodePanel::layoutChanged()\n"));
BPoint p = Frame().LeftTop();
if (m_alternatePosition == s_invalidPosition)
{
m_alternatePosition = dynamic_cast<MediaRoutingView *>
(view())->findFreePositionFor(this);
}
moveTo(m_alternatePosition);
m_alternatePosition = p;
resizeTo(M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT);
for (uint32 i = 0; i < CountItems(); i++)
{
MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i));
jack->layoutChanged(layout);
}
_updateIcon(layout);
_prepareLabel();
arrangeIOJacks();
_updateBitmap();
}
void MediaNodePanel::populateInit()
{
D_METHOD(("MediaNodePanel::populateInit()\n"));
if (ref->kind() & B_BUFFER_CONSUMER)
{
vector<media_input> freeInputs;
ref->getFreeInputs(freeInputs);
for (uint32 i = 0; i < freeInputs.size(); i++)
{
AddItem(new MediaJack(freeInputs[i]));
}
}
if (ref->kind() & B_BUFFER_PRODUCER)
{
vector<media_output> freeOutputs;
ref->getFreeOutputs(freeOutputs);
for (uint32 i = 0; i < freeOutputs.size(); i++)
{
AddItem(new MediaJack(freeOutputs[i]));
}
}
}
void MediaNodePanel::updateIOJacks()
{
D_METHOD(("MediaNodePanel::updateIOJacks()\n"));
// remove all free inputs/outputs, they may be outdated
for (uint32 i = 0; i < CountItems(); i++)
{
MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i));
if (jack && !jack->isConnected())
{
RemoveItem(jack);
delete jack;
i--; // account for reindexing in the BList
}
}
// add free inputs
if (ref->kind() & B_BUFFER_CONSUMER)
{
vector<media_input> freeInputs;
ref->getFreeInputs(freeInputs);
for (uint32 i = 0; i < freeInputs.size(); i++)
{
MediaJack *jack;
AddItem(jack = new MediaJack(freeInputs[i]));
}
}
// add free outputs
if (ref->kind() & B_BUFFER_PRODUCER)
{
vector<media_output> freeOutputs;
ref->getFreeOutputs(freeOutputs);
for (uint32 i = 0; i < freeOutputs.size(); i++)
{
MediaJack *jack;
AddItem(jack = new MediaJack(freeOutputs[i]));
}
}
// the supported media types might have changed -> this could
// require changing the icon
_updateIcon(dynamic_cast<MediaRoutingView *>(view())->getLayout());
}
void MediaNodePanel::arrangeIOJacks()
{
D_METHOD(("MediaNodePanel::arrangeIOJacks()\n"));
SortItems(DiagramItem::M_ENDPOINT, &compareTypeAndID);
switch (dynamic_cast<MediaRoutingView *>(view())->getLayout())
{
case MediaRoutingView::M_ICON_VIEW:
{
BRegion updateRegion;
float align = 1.0;
view()->GetItemAlignment(0, &align);
// adjust this panel's size
int32 numInputs = 0, numOutputs = 0;
for (uint32 i = 0; i < CountItems(); i++)
{
MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i));
if (jack)
{
if (jack->isInput())
{
numInputs++;
}
if (jack->isOutput())
{
numOutputs++;
}
}
}
float minHeight = MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP;
minHeight *= numInputs > numOutputs ? numInputs : numOutputs;
minHeight += m_labelRect.Height();
minHeight += 2 * MediaJack::M_DEFAULT_GAP;
minHeight = ((int)minHeight / (int)align) * align + align;
if ((Frame().Height() < minHeight)
|| ((Frame().Height() > minHeight)
&& (minHeight >= MediaNodePanel::M_DEFAULT_HEIGHT)))
{
updateRegion.Include(Frame());
resizeTo(Frame().Width(), minHeight);
updateRegion.Include(Frame());
_prepareLabel();
}
// adjust the placement of the jacks
BRect r = m_bodyRect;
r.bottom -= M_BODY_V_MARGIN;
float inputOffset = 0.0, outputOffset = 0.0;
float center = Frame().top + r.top + (r.Height() / 2.0);
center += MediaJack::M_DEFAULT_GAP - (MediaJack::M_DEFAULT_HEIGHT / 2.0);
center = ((int)center / (int)align) * align;
if (numInputs)
{
if (numInputs % 2) // odd number of inputs
{
inputOffset = center - (numInputs / 2) * (MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP);
}
else // even number of inputs
{
inputOffset = center - ((numInputs + 1) / 2) * (MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP);
}
}
if (numOutputs)
{
if (numOutputs % 2) // odd number of outputs
{
outputOffset = center - (numOutputs / 2) * (MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP);
}
else // even number of outputs
{
outputOffset = center - ((numOutputs + 1) / 2) * (MediaJack::M_DEFAULT_HEIGHT + MediaJack::M_DEFAULT_GAP);
}
}
for (uint32 i = 0; i < CountItems(); i++)
{
MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i));
if (jack)
{
if (jack->isInput())
{
jack->setPosition(inputOffset, Frame().left, Frame().right, &updateRegion);
inputOffset += jack->Frame().Height() + MediaJack::M_DEFAULT_GAP;
}
if (jack->isOutput())
{
jack->setPosition(outputOffset, Frame().left, Frame().right, &updateRegion);
outputOffset += jack->Frame().Height() + MediaJack::M_DEFAULT_GAP;
}
}
}
for (int32 i = 0; i < updateRegion.CountRects(); i++)
{
view()->Invalidate(updateRegion.RectAt(i));
}
break;
}
case MediaRoutingView::M_MINI_ICON_VIEW:
{
BRegion updateRegion;
float align = 1.0;
view()->GetItemAlignment(&align, 0);
// adjust this panel's size
int32 numInputs = 0, numOutputs = 0;
for (uint32 i = 0; i < CountItems(); i++)
{
MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i));
if (jack)
{
if (jack->isInput())
{
numInputs++;
}
if (jack->isOutput())
{
numOutputs++;
}
}
}
float minWidth = MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP;
minWidth *= numInputs > numOutputs ? numInputs : numOutputs;
minWidth += m_bodyRect.Width();
minWidth += 2 * MediaJack::M_DEFAULT_GAP;
minWidth = ((int)minWidth / (int)align) * align + align;
if ((Frame().Width() < minWidth)
|| ((Frame().Width() > minWidth)
&& (minWidth >= MediaNodePanel::M_DEFAULT_WIDTH)))
{
updateRegion.Include(Frame());
resizeTo(minWidth, Frame().Height());
updateRegion.Include(Frame());
_prepareLabel();
}
// adjust the placement of the jacks
float inputOffset = 0.0, outputOffset = 0.0;
float center = Frame().left + m_labelRect.left + (m_labelRect.Width() / 2.0);
center += MediaJack::M_DEFAULT_GAP - (MediaJack::M_DEFAULT_WIDTH / 2.0);
center = ((int)center / (int)align) * align;
if (numInputs)
{
if (numInputs % 2) // odd number of inputs
{
inputOffset = center - (numInputs / 2) * (MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP);
}
else // even number of inputs
{
inputOffset = center - ((numInputs + 1) / 2) * (MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP);
}
}
if (numOutputs)
{
if (numOutputs % 2) // odd number of outputs
{
outputOffset = center - (numOutputs / 2) * (MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP);
}
else // even number of outputs
{
outputOffset = center - ((numOutputs + 1) / 2) * (MediaJack::M_DEFAULT_WIDTH + MediaJack::M_DEFAULT_GAP);
}
}
for (uint32 i = 0; i < CountItems(); i++)
{
MediaJack *jack = dynamic_cast<MediaJack *>(ItemAt(i));
if (jack)
{
if (jack->isInput())
{
jack->setPosition(inputOffset, Frame().top, Frame().bottom, &updateRegion);
inputOffset += jack->Frame().Width() + MediaJack::M_DEFAULT_GAP;
}
if (jack->isOutput())
{
jack->setPosition(outputOffset, Frame().top, Frame().bottom, &updateRegion);
outputOffset += jack->Frame().Width() + MediaJack::M_DEFAULT_GAP;
}
}
}
for (int32 i = 0; i < updateRegion.CountRects(); i++)
{
view()->Invalidate(updateRegion.RectAt(i));
}
break;
}
}
_updateBitmap();
}
void MediaNodePanel::showContextMenu(
BPoint point)
{
D_METHOD(("MediaNodePanel::showContextMenu()\n"));
BPopUpMenu *menu = new BPopUpMenu("MediaNodePanel PopUp", false, false, B_ITEMS_IN_COLUMN);
menu->SetFont(be_plain_font);
BMenuItem *item;
BMessage *message;
// add the "Tweak Parameters" item
message = new BMessage(MediaRoutingView::M_NODE_TWEAK_PARAMETERS);
menu->AddItem(item = new BMenuItem("Tweak parameters", message, 'P'));
if (!(ref->kind() & B_CONTROLLABLE))
{
item->SetEnabled(false);
}
message = new BMessage(InfoWindowManager::M_INFO_WINDOW_REQUESTED);
message->AddInt32("nodeID", ref->id());
menu->AddItem(new BMenuItem("Get info", message, 'I'));
menu->AddSeparatorItem();
menu->AddItem(item = new BMenuItem("Release", new BMessage(MediaRoutingView::M_DELETE_SELECTION), 'T'));
if (!ref->isInternal())
{
item->SetEnabled(false);
}
menu->AddSeparatorItem();
// add the "Cycle" item
message = new BMessage(MediaRoutingView::M_NODE_CHANGE_CYCLING);
message->AddBool("cycle", !ref->isCycling());
menu->AddItem(item = new BMenuItem("Cycle", message));
item->SetMarked(ref->isCycling());
if (ref->flags() & NodeRef::NO_SEEK)
{
item->SetEnabled(false);
}
// add the "Run Mode" sub menu
BMenu *subMenu = new BMenu("Run mode");
subMenu->SetFont(be_plain_font);
for (uint32 runMode = 1; runMode <= BMediaNode::B_RECORDING; runMode++)
{
BString itemName = MediaString::getStringFor(static_cast<BMediaNode::run_mode>
(runMode));
message = new BMessage(MediaRoutingView::M_NODE_CHANGE_RUN_MODE);
message->AddInt32("run_mode", runMode);
subMenu->AddItem(item = new BMenuItem(itemName.String(), message));
if (ref->runMode() == runMode)
{
item->SetMarked(true);
}
else if ((ref->runMode() == 0)
&& (ref->group()) && (ref->group()->runMode() == BMediaNode::run_mode(runMode)))
{
item->SetMarked(true);
}
}
subMenu->AddSeparatorItem();
message = new BMessage(MediaRoutingView::M_NODE_CHANGE_RUN_MODE);
message->AddInt32("run_mode", 0);
subMenu->AddItem(item = new BMenuItem("(same as group)", message));
if (ref->group() == 0)
{
item->SetEnabled(false);
}
else if ((ref->runMode() < 1) && (ref->group()->runMode() > 0))
{
item->SetMarked(true);
}
menu->AddItem(subMenu);
subMenu->SetTargetForItems(view());
// [c.lenz 24dec99] hide rarely used commands in a 'Advanced' submenu
subMenu = new BMenu("Advanced");
subMenu->SetFont(be_plain_font);
// [e.moon 5dec99] ad-hoc timesource support
if(ref->kind() & B_TIME_SOURCE) {
message = new BMessage(MediaRoutingView::M_NODE_START_TIME_SOURCE);
message->AddInt32("nodeID", ref->id());
subMenu->AddItem(new BMenuItem(
"Start time source",
message));
message = new BMessage(MediaRoutingView::M_NODE_START_TIME_SOURCE);
message->AddInt32("nodeID", ref->id());
subMenu->AddItem(new BMenuItem(
"Stop time source",
message));
}
// [c.lenz 24dec99] support for BControllable::StartControlPanel()
if(ref->kind() & B_CONTROLLABLE) {
if (subMenu->CountItems() > 0)
subMenu->AddSeparatorItem();
message = new BMessage(MediaRoutingView::M_NODE_START_CONTROL_PANEL);
subMenu->AddItem(new BMenuItem("Start Control Panel", message,
'P', B_COMMAND_KEY | B_SHIFT_KEY));
}
// [em 1feb00] group tweaks
if(ref->group())
{
message = new BMessage(MediaRoutingView::M_GROUP_SET_LOCKED);
message->AddInt32("groupID", ref->group()->id());
bool isLocked = (ref->group()->groupFlags() & NodeGroup::GROUP_LOCKED);
message->AddBool("locked", !isLocked);
if (subMenu->CountItems() > 0)
subMenu->AddSeparatorItem();
subMenu->AddItem(
new BMenuItem(
isLocked ? "Unlock group" : "Lock group", message));
}
if (subMenu->CountItems() > 0)
{
menu->AddItem(subMenu);
subMenu->SetTargetForItems(view());
}
menu->SetTargetForItems(view());
view()->ConvertToScreen(&point);
point -= BPoint(1.0, 1.0);
menu->Go(point, true, true, true);
}
// ---------------------------------------------------------------- //
// BHandler impl
// ---------------------------------------------------------------- //
void MediaNodePanel::MessageReceived(
BMessage *message)
{
D_METHOD(("MediaNodePanel::MessageReceived()\n"));
switch (message->what)
{
case NodeRef::M_INPUTS_CHANGED:
{
D_MESSAGE(("MediaNodePanel::MessageReceived(NodeRef::M_INPUTS_CHANGED)\n"));
_updateIcon(dynamic_cast<MediaRoutingView *>(view())->getLayout());
break;
}
case NodeRef::M_OUTPUTS_CHANGED:
{
D_MESSAGE(("MediaNodePanel::MessageReceived(NodeRef::M_OUTPUTS_CHANGED)\n"));
_updateIcon(dynamic_cast<MediaRoutingView *>(view())->getLayout());
break;
}
default:
{
BHandler::MessageReceived(message);
break;
}
}
}
// -------------------------------------------------------- //
// *** IStateArchivable
// -------------------------------------------------------- //
status_t MediaNodePanel::importState(
const BMessage* archive) {
BPoint iconPos(s_invalidPosition);
BPoint miniIconPos(s_invalidPosition);
MediaRoutingView* v = dynamic_cast<MediaRoutingView*>(view());
ASSERT(v);
MediaRoutingView::layout_t layoutMode = v->getLayout();
archive->FindPoint("iconPos", &iconPos);
archive->FindPoint("miniIconPos", &miniIconPos);
switch(layoutMode) {
case MediaRoutingView::M_ICON_VIEW:
if(iconPos != s_invalidPosition)
moveTo(iconPos);
m_alternatePosition = miniIconPos;
break;
case MediaRoutingView::M_MINI_ICON_VIEW:
if(miniIconPos != s_invalidPosition)
moveTo(miniIconPos);
m_alternatePosition = iconPos;
break;
}
return B_OK;
}
status_t MediaNodePanel::exportState(
BMessage* archive) const {
BPoint iconPos, miniIconPos;
MediaRoutingView* v = dynamic_cast<MediaRoutingView*>(view());
ASSERT(v);
MediaRoutingView::layout_t layoutMode = v->getLayout();
switch(layoutMode) {
case MediaRoutingView::M_ICON_VIEW:
iconPos = Frame().LeftTop();
miniIconPos = m_alternatePosition;
break;
case MediaRoutingView::M_MINI_ICON_VIEW:
miniIconPos = Frame().LeftTop();
iconPos = m_alternatePosition;
break;
}
if(iconPos != s_invalidPosition)
archive->AddPoint("iconPos", iconPos);
if(miniIconPos != s_invalidPosition)
archive->AddPoint("miniIconPos", miniIconPos);
// determine if I'm a 'system' node
port_info portInfo;
app_info appInfo;
if ((get_port_info(ref->node().port, &portInfo) == B_OK)
&& (be_roster->GetRunningAppInfo(portInfo.team, &appInfo) == B_OK)) {
BEntry appEntry(&appInfo.ref);
char appName[B_FILE_NAME_LENGTH];
if(
appEntry.InitCheck() == B_OK &&
appEntry.GetName(appName) == B_OK &&
(!strcmp(appName, "media_addon_server") ||
!strcmp(appName, "audio_server"))) {
archive->AddBool("sysOwned", true);
}
}
return B_OK;
}
// ---------------------------------------------------------------- //
// *** internal operations
// ---------------------------------------------------------------- //
void MediaNodePanel::_prepareLabel()
{
// find out if its a file node first
if (ref->kind() & B_FILE_INTERFACE)
{
entry_ref nodeFile;
status_t error = BMediaRoster::Roster()->GetRefFor(ref->node(), &nodeFile);
if (error)
{
m_fullLabel = ref->name();
m_fullLabel += " (no file)";
}
else
{
BEntry entry(&nodeFile);
char fileName[B_FILE_NAME_LENGTH];
entry.GetName(fileName);
m_fullLabel = fileName;
}
}
else
{
m_fullLabel = ref->name();
}
int32 layout = dynamic_cast<MediaRoutingView *>(view())->getLayout();
// Construct labelRect
font_height fh;
be_plain_font->GetHeight(&fh);
switch (layout)
{
case MediaRoutingView::M_ICON_VIEW:
{
m_labelRect = Frame();
m_labelRect.OffsetTo(0.0, 0.0);
m_labelRect.bottom = 2 * M_LABEL_V_MARGIN + (fh.ascent + fh.descent + fh.leading) + 1.0;
break;
}
case MediaRoutingView::M_MINI_ICON_VIEW:
{
m_labelRect = Frame();
m_labelRect.OffsetTo(0.0, 0.0);
m_labelRect.left = M_BODY_H_MARGIN + B_MINI_ICON;
m_labelRect.top += MediaJack::M_DEFAULT_HEIGHT;
m_labelRect.bottom -= MediaJack::M_DEFAULT_HEIGHT;
break;
}
}
// truncate the label to fit in the panel
float maxWidth = m_labelRect.Width() - (2.0 * M_LABEL_H_MARGIN) - 2.0;
if (be_plain_font->StringWidth(m_fullLabel.String()) > maxWidth)
{
char *truncatedLabel[1];
truncatedLabel[0] = new char[B_MEDIA_NAME_LENGTH];
const char *originalLabel[1];
originalLabel[0] = new char[B_MEDIA_NAME_LENGTH];
m_fullLabel.CopyInto(const_cast<char *>(originalLabel[0]), 0, B_MEDIA_NAME_LENGTH);
be_plain_font->GetTruncatedStrings(originalLabel, 1, B_TRUNCATE_END, maxWidth, (char **) truncatedLabel);
m_label = truncatedLabel[0];
m_labelTruncated = true;
delete [] originalLabel[0];
delete [] truncatedLabel[0];
}
else
{
m_label = m_fullLabel;
m_labelTruncated = false;
}
// Construct labelOffset
float fw = be_plain_font->StringWidth(m_label.String());
m_labelOffset.x = m_labelRect.left + m_labelRect.Width() / 2.0 - fw / 2.0;
m_labelOffset.y = m_labelRect.bottom - M_LABEL_V_MARGIN - fh.descent - (fh.leading / 2.0) - 1.0;
// Construct bodyRect
switch (layout)
{
case MediaRoutingView::M_ICON_VIEW:
{
m_bodyRect = Frame();
m_bodyRect.OffsetTo(0.0, 0.0);
m_bodyRect.top = m_labelRect.bottom;
break;
}
case MediaRoutingView::M_MINI_ICON_VIEW:
{
m_bodyRect = Frame();
m_bodyRect.OffsetTo(0.0, 0.0);
m_bodyRect.right = m_labelRect.left;
break;
}
}
}
void MediaNodePanel::_updateBitmap()
{
if (m_bitmap)
{
delete m_bitmap;
}
BBitmap *tempBitmap = new BBitmap(Frame().OffsetToCopy(0.0, 0.0), B_CMAP8, true);
tempBitmap->Lock();
{
BView *tempView = new BView(tempBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
tempBitmap->AddChild(tempView);
tempView->SetOrigin(0.0, 0.0);
int32 layout = dynamic_cast<MediaRoutingView *>(view())->getLayout();
_drawInto(tempView, tempView->Bounds(), layout);
tempView->Sync();
tempBitmap->RemoveChild(tempView);
delete tempView;
}
tempBitmap->Unlock();
m_bitmap = new BBitmap(tempBitmap);
delete tempBitmap;
}
void MediaNodePanel::_drawInto(
BView *target,
BRect targetRect,
int32 layout)
{
switch (layout)
{
case MediaRoutingView::M_ICON_VIEW:
{
BRect r;
BPoint p;
// Draw borders
r = targetRect;
target->BeginLineArray(16);
target->AddLine(r.LeftTop(), r.RightTop(), M_DARK_GRAY_COLOR);
target->AddLine(r.RightTop(), r.RightBottom(), M_DARK_GRAY_COLOR);
target->AddLine(r.RightBottom(), r.LeftBottom(), M_DARK_GRAY_COLOR);
target->AddLine(r.LeftBottom(), r.LeftTop(), M_DARK_GRAY_COLOR);
r.InsetBy(1.0, 1.0);
target->AddLine(r.LeftTop(), r.RightTop(), M_LIGHT_GRAY_COLOR);
target->AddLine(r.RightTop(), r.RightBottom(), M_MED_GRAY_COLOR);
target->AddLine(r.RightBottom(), r.LeftBottom(), M_MED_GRAY_COLOR);
target->AddLine(r.LeftBottom(), r.LeftTop(), M_LIGHT_GRAY_COLOR);
target->EndLineArray();
// Fill background
r.InsetBy(1.0, 1.0);
target->SetLowColor(M_GRAY_COLOR);
target->FillRect(r, B_SOLID_LOW);
// Draw icon
if (m_icon)
{
p.x = m_bodyRect.left + m_bodyRect.Width() / 2.0 - B_LARGE_ICON / 2.0;
p.y = m_labelRect.bottom + m_bodyRect.Height() / 2.0 - B_LARGE_ICON / 2.0;
if (isSelected())
{
target->SetDrawingMode(B_OP_INVERT);
target->DrawBitmapAsync(m_icon, p);
target->SetDrawingMode(B_OP_ALPHA);
target->SetHighColor(0, 0, 0, 180);
target->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
target->DrawBitmapAsync(m_icon, p);
target->SetDrawingMode(B_OP_OVER);
}
else
{
target->SetDrawingMode(B_OP_OVER);
target->DrawBitmapAsync(m_icon, p);
}
}
// Draw label
if (isSelected())
{
r = m_labelRect;
r.InsetBy(M_LABEL_H_MARGIN, M_LABEL_V_MARGIN);
target->BeginLineArray(4);
target->AddLine(r.LeftTop(), r.RightTop(), M_LIGHT_BLUE_COLOR);
target->AddLine(r.RightTop(), r.RightBottom(), M_LIGHT_BLUE_COLOR);
target->AddLine(r.RightBottom(), r.LeftBottom(), M_LIGHT_BLUE_COLOR);
target->AddLine(r.LeftBottom(), r.LeftTop(), M_LIGHT_BLUE_COLOR);
target->EndLineArray();
r.InsetBy(1.0, 1.0);
target->SetHighColor(M_DARK_BLUE_COLOR);
target->FillRect(r, B_SOLID_HIGH);
}
target->SetDrawingMode(B_OP_OVER);
target->SetHighColor(isSelected() ? M_WHITE_COLOR : M_BLACK_COLOR);
target->DrawString(m_label.String(), m_labelOffset);
break;
}
case MediaRoutingView::M_MINI_ICON_VIEW:
{
BRect r;
BPoint p;
// Draw borders
r = targetRect;
target->BeginLineArray(16);
target->AddLine(r.LeftTop(), r.RightTop(), M_DARK_GRAY_COLOR);
target->AddLine(r.RightTop(), r.RightBottom(), M_DARK_GRAY_COLOR);
target->AddLine(r.RightBottom(), r.LeftBottom(), M_DARK_GRAY_COLOR);
target->AddLine(r.LeftBottom(), r.LeftTop(), M_DARK_GRAY_COLOR);
r.InsetBy(1.0, 1.0);
target->AddLine(r.LeftTop(), r.RightTop(), M_LIGHT_GRAY_COLOR);
target->AddLine(r.RightTop(), r.RightBottom(), M_MED_GRAY_COLOR);
target->AddLine(r.RightBottom(), r.LeftBottom(), M_MED_GRAY_COLOR);
target->AddLine(r.LeftBottom(), r.LeftTop(), M_LIGHT_GRAY_COLOR);
target->EndLineArray();
// Fill background
r.InsetBy(1.0, 1.0);
target->SetLowColor(M_GRAY_COLOR);
target->FillRect(r, B_SOLID_LOW);
// Draw icon
if (m_icon)
{
p.x = m_bodyRect.left + M_BODY_H_MARGIN;
p.y = m_bodyRect.top + (m_bodyRect.Height() / 2.0) - (B_MINI_ICON / 2.0);
if (isSelected())
{
target->SetDrawingMode(B_OP_INVERT);
target->DrawBitmapAsync(m_icon, p);
target->SetDrawingMode(B_OP_ALPHA);
target->SetHighColor(0, 0, 0, 180);
target->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
target->DrawBitmapAsync(m_icon, p);
target->SetDrawingMode(B_OP_OVER);
}
else
{
target->SetDrawingMode(B_OP_OVER);
target->DrawBitmapAsync(m_icon, p);
}
}
// Draw label
if (isSelected())
{
r = m_labelRect;
r.InsetBy(M_LABEL_H_MARGIN, M_LABEL_V_MARGIN);
target->BeginLineArray(4);
target->AddLine(r.LeftTop(), r.RightTop(), M_LIGHT_BLUE_COLOR);
target->AddLine(r.RightTop(), r.RightBottom(), M_LIGHT_BLUE_COLOR);
target->AddLine(r.RightBottom(), r.LeftBottom(), M_LIGHT_BLUE_COLOR);
target->AddLine(r.LeftBottom(), r.LeftTop(), M_LIGHT_BLUE_COLOR);
target->EndLineArray();
r.InsetBy(1.0, 1.0);
target->SetHighColor(M_DARK_BLUE_COLOR);
target->FillRect(r, B_SOLID_HIGH);
}
target->SetDrawingMode(B_OP_OVER);
target->SetHighColor(isSelected() ? M_WHITE_COLOR : M_BLACK_COLOR);
target->DrawString(m_label.String(), m_labelOffset);
break;
}
}
}
void MediaNodePanel::_updateIcon(
int32 layout)
{
D_METHOD(("MediaNodePanel::_updateIcon()\n"));
if (m_icon)
{
delete m_icon;
m_icon = 0;
}
RouteAppNodeManager *manager;
manager = dynamic_cast<MediaRoutingView *>(view())->manager;
switch (layout)
{
case MediaRoutingView::M_ICON_VIEW:
{
const MediaIcon *icon = manager->mediaIconFor(ref->id(), B_LARGE_ICON);
m_icon = new BBitmap(dynamic_cast<const BBitmap *>(icon));
break;
}
case MediaRoutingView::M_MINI_ICON_VIEW:
{
const MediaIcon *icon = manager->mediaIconFor(ref->id(), B_MINI_ICON);
m_icon = new BBitmap(dynamic_cast<const BBitmap *>(icon));
break;
}
}
}
// -------------------------------------------------------- //
// *** sorting methods (friend)
// -------------------------------------------------------- //
int __CORTEX_NAMESPACE__ compareID(
const void *lValue,
const void *rValue)
{
int retValue = 0;
const MediaNodePanel *lPanel = *(reinterpret_cast<MediaNodePanel * const*>(reinterpret_cast<void * const*>(lValue)));
const MediaNodePanel *rPanel = *(reinterpret_cast<MediaNodePanel * const*>(reinterpret_cast<void * const*>(rValue)));
if (lPanel && rPanel)
{
if (lPanel->ref->id() < rPanel->ref->id())
{
retValue = -1;
}
else if (lPanel->ref->id() > rPanel->ref->id())
{
retValue = 1;
}
}
return retValue;
}
// END -- MediaNodePanel.cpp --
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: m_labelTruncated, m_mouseOverLabel.
↑ V773 Visibility scope of the 'menu' pointer was exited without releasing the memory. A memory leak is possible.