/* * 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. */ // TransportView.cpp #include "TransportView.h" #include "RouteApp.h" #include "RouteWindow.h" #include "RouteAppNodeManager.h" #include "NodeGroup.h" #include "NumericValControl.h" #include "TextControlFloater.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef B_CATALOG #define B_CATALOG (&sCatalog) #include #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "TransportView" using namespace std; __USE_CORTEX_NAMESPACE static BCatalog sCatalog("x-vnd.Cortex.TransportView"); // -------------------------------------------------------- // // _GroupInfoView // -------------------------------------------------------- // __BEGIN_CORTEX_NAMESPACE class _GroupInfoView : public BView { typedef BView _inherited; public: // ctor/dtor _GroupInfoView( BRect frame, TransportView* parent, const char* name, uint32 resizeMode =B_FOLLOW_LEFT|B_FOLLOW_TOP, uint32 flags =B_WILL_DRAW|B_FRAME_EVENTS) : BView(frame, name, resizeMode, flags), m_parent(parent), m_plainFont(be_plain_font), m_boldFont(be_bold_font) { _initViews(); _initColors(); _updateLayout(); } public: // BView virtual void FrameResized( float width, float height) { _inherited::FrameResized(width, height); _updateLayout(); Invalidate(); } virtual void GetPreferredSize( float* width, float* height) { font_height fh; m_plainFont.GetHeight(&fh); *width = 0.0; *height = (fh.ascent+fh.descent+fh.leading) * 2; *height += 4.0; //+++++ } virtual void Draw( BRect updateRect) { NodeGroup* g = m_parent->m_group; BRect b = Bounds(); // border rgb_color hi = tint_color(ViewColor(), B_LIGHTEN_2_TINT); rgb_color lo = tint_color(ViewColor(), B_DARKEN_2_TINT); SetHighColor(lo); StrokeLine( b.LeftTop(), b.RightTop()); StrokeLine( b.LeftTop(), b.LeftBottom()); SetHighColor(hi); StrokeLine( b.LeftBottom(), b.RightBottom()); StrokeLine( b.RightTop(), b.RightBottom()); SetHighColor(255,255,255,255); // background +++++ // name BString name = g ? g->name() : B_TRANSLATE("(no group)"); // +++++ constrain width SetFont(&m_boldFont); DrawString(name.String(), m_namePosition); SetFont(&m_plainFont); // node count uint32 count; if (g != NULL) count = g->countNodes(); else count = 0; BString nodeCount = ""; static BStringFormat format( B_TRANSLATE("{0, plural, one{# node} other{# nodes}}")); format.Format(nodeCount, count); // +++++ constrain width DrawString(nodeCount.String(), m_nodeCountPosition); // status BString status = B_TRANSLATE("No errors."); // +++++ constrain width DrawString(status.String(), m_statusPosition); } virtual void MouseDown( BPoint point) { NodeGroup* g = m_parent->m_group; if(!g) return; font_height fh; m_boldFont.GetHeight(&fh); BRect nameBounds( m_namePosition.x, m_namePosition.y - fh.ascent, m_namePosition.x + m_maxNameWidth, m_namePosition.y + (fh.ascent+fh.leading-4.0)); if(nameBounds.Contains(point)) { ConvertToScreen(&nameBounds); nameBounds.OffsetBy(-7.0, -3.0); new TextControlFloater( nameBounds, B_ALIGN_LEFT, &m_boldFont, g->name(), m_parent, new BMessage(TransportView::M_SET_NAME)); } } public: // implementation void _initViews() { // +++++ } void _initColors() { // +++++ these colors need to be centrally defined SetViewColor(16, 64, 96, 255); SetLowColor(16, 64, 96, 255); SetHighColor(255,255,255,255); } void _updateLayout() { float _edge_pad_x = 3.0; float _edge_pad_y = 1.0; BRect b = Bounds(); font_height fh; m_plainFont.GetHeight(&fh); float realWidth = b.Width() - (_edge_pad_x * 2); m_maxNameWidth = realWidth * 0.7; m_maxNodeCountWidth = realWidth - m_maxNameWidth; m_namePosition.x = _edge_pad_x; m_namePosition.y = _edge_pad_x + fh.ascent - 2.0; m_nodeCountPosition = m_namePosition; m_nodeCountPosition.x = m_maxNameWidth; m_maxStatusWidth = realWidth; m_statusPosition.x = _edge_pad_x; m_statusPosition.y = b.Height() - (fh.descent + fh.leading + _edge_pad_y); } private: TransportView* m_parent; BFont m_plainFont; BFont m_boldFont; BPoint m_namePosition; float m_maxNameWidth; BPoint m_nodeCountPosition; float m_maxNodeCountWidth; BPoint m_statusPosition; float m_maxStatusWidth; }; __END_CORTEX_NAMESPACE // -------------------------------------------------------- // // *** ctors // -------------------------------------------------------- // TransportView::TransportView( NodeManager* manager, const char* name) : BView( BRect(), name, B_FOLLOW_ALL_SIDES, B_WILL_DRAW|B_FRAME_EVENTS), m_manager(manager), m_group(0) { // initialize _initLayout(); _constructControls(); // _updateLayout(); deferred until AttachedToWindow(): 24aug99 _disableControls(); SetViewColor( tint_color( ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_1_TINT)); } // -------------------------------------------------------- // // *** BView // -------------------------------------------------------- // void TransportView::AttachedToWindow() { _inherited::AttachedToWindow(); // finish layout _updateLayout(); // watch the node manager (for time-source create/delete notification) RouteApp* app = dynamic_cast(be_app); ASSERT(app); add_observer(this, app->manager); } void TransportView::AllAttached() { _inherited::AllAttached(); // set message targets for view-configuation controls for(target_set::iterator it = m_localTargets.begin(); it != m_localTargets.end(); ++it) { ASSERT(*it); (*it)->SetTarget(this); } } void TransportView::DetachedFromWindow() { _inherited::DetachedFromWindow(); RouteApp* app = dynamic_cast(be_app); ASSERT(app); remove_observer(this, app->manager); } void TransportView::FrameResized( float width, float height) { _inherited::FrameResized(width, height); // _updateLayout(); } void TransportView::KeyDown( const char* bytes, int32 count) { switch(bytes[0]) { case B_SPACE: { RouteApp* app = dynamic_cast(be_app); ASSERT(app); BMessenger(app->routeWindow).SendMessage( RouteWindow::M_TOGGLE_GROUP_ROLLING); break; } default: _inherited::KeyDown(bytes, count); } } void TransportView::MouseDown( BPoint where) { MakeFocus(true); } // -------------------------------------------------------- // // *** BHandler // -------------------------------------------------------- // void TransportView::MessageReceived( BMessage* message) { status_t err; uint32 groupID; // PRINT(( // "TransportView::MessageReceived()\n")); // message->PrintToStream(); switch(message->what) { case NodeGroup::M_RELEASED: { err = message->FindInt32("groupID", (int32*)&groupID); if(err < B_OK) { PRINT(( "* TransportView::MessageReceived(NodeGroup::M_RELEASED)\n" " no groupID!\n")); } if(!m_group || groupID != m_group->id()) { PRINT(( "* TransportView::MessageReceived(NodeGroup::M_RELEASED)\n" " mismatched groupID.\n")); break; } _releaseGroup(); // // BMessage m(M_REMOVE_OBSERVER); // m.AddMessenger("observer", BMessenger(this)); // message->SendReply(&m); } break; case NodeGroup::M_OBSERVER_ADDED: err = message->FindInt32("groupID", (int32*)&groupID); if(err < B_OK) { PRINT(( "* TransportView::MessageReceived(NodeGroup::M_OBSERVER_ADDED)\n" " no groupID!\n")); break; } if(!m_group || groupID != m_group->id()) { PRINT(( "* TransportView::MessageReceived(NodeGroup::M_OBSERVER_ADDED)\n" " mismatched groupID; ignoring.\n")); break; } _enableControls(); break; case NodeGroup::M_TRANSPORT_STATE_CHANGED: uint32 groupID; err = message->FindInt32("groupID", (int32*)&groupID); if(err < B_OK) { PRINT(( "* TransportView::MessageReceived(NodeGroup::M_TRANSPORT_STATE_CHANGED)\n" " no groupID!\n")); break; } if(!m_group || groupID != m_group->id()) { PRINT(( "* TransportView::MessageReceived(NodeGroup::M_TRANSPORT_STATE_CHANGED)\n" " mismatched groupID; ignoring.\n")); break; } _updateTransportButtons(); break; case NodeGroup::M_TIME_SOURCE_CHANGED: //_updateTimeSource(); +++++ check group? break; case NodeGroup::M_RUN_MODE_CHANGED: //_updateRunMode(); +++++ check group? break; // * CONTROL PROCESSING case NodeGroup::M_SET_START_POSITION: { if(!m_group) break; bigtime_t position = _scalePosition( m_regionStartView->value()); message->AddInt64("position", position); BMessenger(m_group).SendMessage(message); // update start-button duty/label [e.moon 11oct99] if(m_group->transportState() == NodeGroup::TRANSPORT_STOPPED) _updateTransportButtons(); break; } case NodeGroup::M_SET_END_POSITION: { if(!m_group) break; bigtime_t position = _scalePosition( m_regionEndView->value()); message->AddInt64("position", position); BMessenger(m_group).SendMessage(message); // update start-button duty/label [e.moon 11oct99] if(m_group->transportState() == NodeGroup::TRANSPORT_STOPPED) _updateTransportButtons(); break; } case M_SET_NAME: { const char* name; err = message->FindString("_value", &name); if(err < B_OK) { PRINT(( "! TransportView::MessageReceived(M_SET_NAME): no _value!\n")); break; } if(m_group) { m_group->setName(name); m_infoView->Invalidate(); } } break; case RouteAppNodeManager::M_TIME_SOURCE_CREATED: _timeSourceCreated(message); break; case RouteAppNodeManager::M_TIME_SOURCE_DELETED: _timeSourceDeleted(message); break; default: _inherited::MessageReceived(message); break; } } // -------------------------------------------------------- // // *** BHandler impl. // -------------------------------------------------------- // void TransportView::_handleSelectGroup( BMessage* message) { uint32 groupID; status_t err = message->FindInt32("groupID", (int32*)&groupID); if(err < B_OK) { PRINT(( "* TransportView::_handleSelectGroup(): no groupID\n")); return; } if(m_group && groupID != m_group->id()) _releaseGroup(); _selectGroup(groupID); Invalidate(); } // -------------------------------------------------------- // // *** internal operations // -------------------------------------------------------- // // select the given group; initialize controls // (if 0, gray out all controls) void TransportView::_selectGroup( uint32 groupID) { status_t err; if(m_group) _releaseGroup(); if(!groupID) { _disableControls(); return; } err = m_manager->findGroup(groupID, &m_group); if(err < B_OK) { PRINT(( "* TransportView::_selectGroup(%" B_PRId32 "): findGroup() failed:\n" " %s\n", groupID, strerror(err))); return; } _observeGroup(); } void TransportView::_observeGroup() { ASSERT(m_group); add_observer(this, m_group); } void TransportView::_releaseGroup() { ASSERT(m_group); remove_observer(this, m_group); m_group = 0; } // -------------------------------------------------------- // // *** CONTROLS // -------------------------------------------------------- // const char _run_mode_strings[][20] = { B_TRANSLATE_MARK("Offline"), B_TRANSLATE_MARK("Decrease precision"), B_TRANSLATE_MARK("Increase latency"), B_TRANSLATE_MARK("Drop data"), B_TRANSLATE_MARK("Recording") }; const int _run_modes = 5; //const char _time_source_strings[][20] = { // "DAC time source", // "System clock" //}; //const int _time_sources = 2; const char* _region_start_label = B_TRANSLATE("From:"); const char* _region_end_label = B_TRANSLATE("To:"); void TransportView::_constructControls() { BMessage* m; // * create and populate, but don't position, the views: // // create and populate, but don't position, the views: // m_nameView = new BStringView( // BRect(), // "nameView", // "Group Name", // B_FOLLOW_NONE); // AddChild(m_nameView); m_infoView = new _GroupInfoView( BRect(), this, "infoView"); AddChild(m_infoView); m_runModeView = new BMenuField( BRect(), "runModeView", B_TRANSLATE("Run mode:"), new BPopUpMenu("runModeMenu")); _populateRunModeMenu( m_runModeView->Menu()); AddChild(m_runModeView); m_timeSourceView = new BMenuField( BRect(), "timeSourceView", B_TRANSLATE("Time source:"), new BPopUpMenu("timeSourceMenu")); _populateTimeSourceMenu( m_timeSourceView->Menu()); AddChild(m_timeSourceView); m_fromLabel = new BStringView(BRect(), 0, B_TRANSLATE("Roll from")); AddChild(m_fromLabel); m = new BMessage(NodeGroup::M_SET_START_POSITION); m_regionStartView = new NumericValControl( BRect(), "regionStartView", m, 2, 4, // * DIGITS false, ValControl::ALIGN_FLUSH_LEFT); // redirect view back to self. this gives me the chance to // augment the message with the position before sending _addLocalTarget(m_regionStartView); AddChild(m_regionStartView); m_toLabel = new BStringView(BRect(), 0, B_TRANSLATE("to")); AddChild(m_toLabel); m = new BMessage(NodeGroup::M_SET_END_POSITION); m_regionEndView = new NumericValControl( BRect(), "regionEndView", m, 2, 4, // * DIGITS false, ValControl::ALIGN_FLUSH_LEFT); // redirect view back to self. this gives me the chance to // augment the message with the position before sending _addLocalTarget(m_regionEndView); AddChild(m_regionEndView); // m = new BMessage(NodeGroup::M_SET_START_POSITION); // m_regionStartView = new BTextControl( // BRect(), // "regionStartView", // _region_start_label, // "0", // m); // // _addGroupTarget(m_regionStartView); //// m_regionStartView->TextView()->SetAlignment(B_ALIGN_RIGHT); // // AddChild(m_regionStartView); // // m = new BMessage(NodeGroup::M_SET_END_POSITION); // m_regionEndView = new BTextControl( // BRect(), // "regionEndView", // _region_end_label, // "0", // m); // // _addGroupTarget(m_regionEndView); //// m_regionEndView->TextView()->SetAlignment(B_ALIGN_RIGHT); // AddChild(m_regionEndView); m = new BMessage(NodeGroup::M_START); m_startButton = new BButton( BRect(), "startButton", B_TRANSLATE("Start"), m); _addGroupTarget(m_startButton); AddChild(m_startButton); m = new BMessage(NodeGroup::M_STOP); m_stopButton = new BButton( BRect(), "stopButton", B_TRANSLATE("Stop"), m); _addGroupTarget(m_stopButton); AddChild(m_stopButton); m = new BMessage(NodeGroup::M_PREROLL); m_prerollButton = new BButton( BRect(), "prerollButton", B_TRANSLATE("Preroll"), m); _addGroupTarget(m_prerollButton); AddChild(m_prerollButton); } // convert a position control's value to bigtime_t // [e.moon 11oct99] bigtime_t TransportView::_scalePosition( double value) { return bigtime_t(value * 1000000.0); } void TransportView::_populateRunModeMenu( BMenu* menu) { BMessage* m; for(int n = 0; n < _run_modes; ++n) { m = new BMessage(NodeGroup::M_SET_RUN_MODE); m->AddInt32("runMode", n+1); BMenuItem* i = new BMenuItem( B_TRANSLATE(_run_mode_strings[n]), m); menu->AddItem(i); _addGroupTarget(i); } } void TransportView::_populateTimeSourceMenu( BMenu* menu) { // find the standard time sources status_t err; media_node dacTimeSource, systemTimeSource; BMessage* m; BMenuItem* i; err = m_manager->roster->GetTimeSource(&dacTimeSource); if(err == B_OK) { m = new BMessage(NodeGroup::M_SET_TIME_SOURCE); m->AddData( "timeSourceNode", B_RAW_TYPE, &dacTimeSource, sizeof(media_node)); i = new BMenuItem( B_TRANSLATE("DAC time source"), m); menu->AddItem(i); _addGroupTarget(i); } err = m_manager->roster->GetSystemTimeSource(&systemTimeSource); if(err == B_OK) { m = new BMessage(NodeGroup::M_SET_TIME_SOURCE); m->AddData( "timeSourceNode", B_RAW_TYPE, &systemTimeSource, sizeof(media_node)); i = new BMenuItem( B_TRANSLATE("System clock"), m); menu->AddItem(i); _addGroupTarget(i); } // find other time source nodes Autolock _l(m_manager); void* cookie = 0; NodeRef* r; char nameBuffer[B_MEDIA_NAME_LENGTH+16]; bool needSeparator = (menu->CountItems() > 0); while(m_manager->getNextRef(&r, &cookie) == B_OK) { if(!(r->kind() & B_TIME_SOURCE)) continue; if(r->id() == dacTimeSource.node) continue; if(r->id() == systemTimeSource.node) continue; if(needSeparator) { needSeparator = false; menu->AddItem(new BSeparatorItem()); } m = new BMessage(NodeGroup::M_SET_TIME_SOURCE); m->AddData( "timeSourceNode", B_RAW_TYPE, &r->node(), sizeof(media_node)); sprintf(nameBuffer, "%s: %" B_PRId32, r->name(), r->id()); i = new BMenuItem( nameBuffer, m); menu->AddItem(i); _addGroupTarget(i); } // BMessage* m; // for(int n = 0; n < _time_sources; ++n) { // m = new BMessage(NodeGroup::M_SET_TIME_SOURCE); // m->AddData( // "timeSourceNode", // B_RAW_TYPE, // &m_timeSourcePresets[n], // sizeof(media_node)); // // +++++ copy media_node of associated time source! //// m->AddInt32("timeSource", n); // // BMenuItem* i = new BMenuItem( // _time_source_strings[n], m); // menu->AddItem(i); // _addGroupTarget(i); // } } // add the given invoker to be retargeted to this // view (used for controls whose messages need a bit more // processing before being forwarded to the NodeManager.) void TransportView::_addLocalTarget( BInvoker* invoker) { m_localTargets.push_back(invoker); if(Window()) invoker->SetTarget(this); } void TransportView::_addGroupTarget( BInvoker* invoker) { m_groupTargets.push_back(invoker); if(m_group) invoker->SetTarget(m_group); } void TransportView::_refreshTransportSettings() { if(m_group) _updateTransportButtons(); } void TransportView::_disableControls() { // PRINT(( // "*** _disableControls()\n")); BWindow* w = Window(); if(w) w->BeginViewTransaction(); // m_nameView->SetText("(no group)"); m_infoView->Invalidate(); m_runModeView->SetEnabled(false); m_runModeView->Menu()->Superitem()->SetLabel(B_TRANSLATE("(none)")); m_timeSourceView->SetEnabled(false); m_timeSourceView->Menu()->Superitem()->SetLabel(B_TRANSLATE("(none)")); m_regionStartView->SetEnabled(false); m_regionStartView->setValue(0); m_regionEndView->SetEnabled(false); m_regionEndView->setValue(0); m_startButton->SetEnabled(false); m_stopButton->SetEnabled(false); m_prerollButton->SetEnabled(false); if(w) w->EndViewTransaction(); // PRINT(( // "*** DONE: _disableControls()\n")); } void TransportView::_enableControls() { // PRINT(( // "*** _enableControls()\n")); // ASSERT(m_group); Autolock _l(m_group); // +++++ why? BWindow* w = Window(); if(w) { w->BeginViewTransaction(); // clear focused view // 19sep99: TransportWindow is currently a B_AVOID_FOCUS window; the // only way views get focused is if they ask to be (which ValControl // currently does.) BView* focused = w->CurrentFocus(); if(focused) focused->MakeFocus(false); } // BString nameViewText = m_group->name(); // nameViewText << ": " << m_group->countNodes() << " nodes."; // m_nameView->SetText(nameViewText.String()); m_infoView->Invalidate(); m_runModeView->SetEnabled(true); _updateRunMode(); m_timeSourceView->SetEnabled(true); _updateTimeSource(); _updateTransportButtons(); // +++++ ick. hard-coded scaling factors make me queasy m_regionStartView->SetEnabled(true); m_regionStartView->setValue( ((double)m_group->startPosition()) / 1000000.0); m_regionEndView->SetEnabled(true); m_regionEndView->setValue( ((double)m_group->endPosition()) / 1000000.0); // target controls on group for(target_set::iterator it = m_groupTargets.begin(); it != m_groupTargets.end(); ++it) { ASSERT(*it); (*it)->SetTarget(m_group); } if(w) { w->EndViewTransaction(); } // PRINT(( // "*** DONE: _enableControls()\n")); } void TransportView::_updateTransportButtons() { ASSERT(m_group); switch(m_group->transportState()) { case NodeGroup::TRANSPORT_INVALID: case NodeGroup::TRANSPORT_STARTING: case NodeGroup::TRANSPORT_STOPPING: m_startButton->SetEnabled(false); m_stopButton->SetEnabled(false); m_prerollButton->SetEnabled(false); break; case NodeGroup::TRANSPORT_STOPPED: m_startButton->SetEnabled(true); m_stopButton->SetEnabled(false); m_prerollButton->SetEnabled(true); break; case NodeGroup::TRANSPORT_RUNNING: case NodeGroup::TRANSPORT_ROLLING: m_startButton->SetEnabled(false); m_stopButton->SetEnabled(true); m_prerollButton->SetEnabled(false); break; } // based on group settings, set the start button to do either // a simple start or a roll (atomic start/stop.) [e.moon 11oct99] ASSERT(m_startButton->Message()); // get current region settings bigtime_t startPosition = _scalePosition(m_regionStartView->value()); bigtime_t endPosition = _scalePosition(m_regionEndView->value()); // get current run-mode setting uint32 runMode = 0; BMenuItem* i = m_runModeView->Menu()->FindMarked(); ASSERT(i); runMode = m_runModeView->Menu()->IndexOf(i) + 1; if( endPosition > startPosition && (runMode == BMediaNode::B_OFFLINE || !m_group->canCycle())) { m_startButton->SetLabel(B_TRANSLATE("Roll")); m_startButton->Message()->what = NodeGroup::M_ROLL; } else { m_startButton->SetLabel(B_TRANSLATE("Start")); m_startButton->Message()->what = NodeGroup::M_START; } } void TransportView::_updateTimeSource() { ASSERT(m_group); media_node tsNode; status_t err = m_group->getTimeSource(&tsNode); if(err < B_OK) { PRINT(( "! TransportView::_updateTimeSource(): m_group->getTimeSource():\n" " %s\n", strerror(err))); return; } BMenu* menu = m_timeSourceView->Menu(); ASSERT(menu); if(tsNode == media_node::null) { menu->Superitem()->SetLabel(B_TRANSLATE("(none)")); return; } // find menu item int32 n; for(n = menu->CountItems()-1; n >= 0; --n) { const void* data; media_node itemNode; BMessage* message = menu->ItemAt(n)->Message(); if(!message) continue; ssize_t size = sizeof(media_node); err = message->FindData( "timeSourceNode", B_RAW_TYPE, &data, &size); if(err < B_OK) continue; itemNode = *((media_node*)data); if(itemNode != tsNode) continue; // found it PRINT(( "### _updateTimeSource: %s\n", menu->ItemAt(n)->Label())); menu->ItemAt(n)->SetMarked(true); break; } // ASSERT(m_timeSourcePresets); // int n; // for(n = 0; n < _time_sources; ++n) { // if(m_timeSourcePresets[n] == tsNode) { // BMenuItem* i = m_timeSourceView->Menu()->ItemAt(n); // ASSERT(i); // i->SetMarked(true); // break; // } // } if(n < 0) menu->Superitem()->SetLabel(B_TRANSLATE("(\?\?\?)")); } void TransportView::_updateRunMode() { ASSERT(m_group); BMenu* menu = m_runModeView->Menu(); uint32 runMode = m_group->runMode() - 1; // real run mode starts at 1 ASSERT((uint32)menu->CountItems() > runMode); menu->ItemAt(runMode)->SetMarked(true); } //void TransportView::_initTimeSources() { // // status_t err; // media_node node; // err = m_manager->roster->GetTimeSource(&node); // if(err == B_OK) { // m_timeSources.push_back(node.node); // } // // err = m_manager->roster->GetSystemTimeSource(&m_timeSourcePresets[1]); // if(err < B_OK) { // PRINT(( // "* TransportView::_initTimeSources():\n" // " GetSystemTimeSource() failed: %s\n", strerror(err))); // } //} // [e.moon 2dec99] void TransportView::_timeSourceCreated( BMessage* message) { status_t err; media_node_id id; err = message->FindInt32("nodeID", &id); if(err < B_OK) return; // PRINT(("### _timeSourceCreated(): %" B_PRId32 "\n", id)); NodeRef* ref; err = m_manager->getNodeRef(id, &ref); if(err < B_OK) { PRINT(( "!!! TransportView::_timeSourceCreated(): node %" B_PRId32 " doesn't exist\n", id)); return; } char nameBuffer[B_MEDIA_NAME_LENGTH+16]; BMessage* m = new BMessage(NodeGroup::M_SET_TIME_SOURCE); m->AddData( "timeSourceNode", B_RAW_TYPE, &ref->node(), sizeof(media_node)); sprintf(nameBuffer, "%s: %" B_PRId32, ref->name(), ref->id()); BMenuItem* i = new BMenuItem( nameBuffer, m); BMenu* menu = m_timeSourceView->Menu(); menu->AddItem(i); _addGroupTarget(i); } // +++++ void TransportView::_timeSourceDeleted( BMessage* message) { status_t err; media_node_id id; err = message->FindInt32("nodeID", &id); if(err < B_OK) return; // PRINT(("### _timeSourceDeleted(): %" B_PRId32 "\n", id)); BMenu* menu = m_timeSourceView->Menu(); ASSERT(menu); // find menu item int32 n; for(n = menu->CountItems()-1; n >= 0; --n) { const void* data; media_node itemNode; BMessage* message = menu->ItemAt(n)->Message(); if(!message) continue; ssize_t size = sizeof(media_node); err = message->FindData( "timeSourceNode", B_RAW_TYPE, &data, &size); if(err < B_OK) continue; itemNode = *((media_node*)data); if(itemNode.node != id) continue; // found it; remove the item menu->RemoveItem(n); break; } } // -------------------------------------------------------- // // *** LAYOUT *** // -------------------------------------------------------- // const float _edge_pad_x = 3.0; const float _edge_pad_y = 3.0; const float _column_pad_x = 4.0; const float _field_pad_x = 20.0; const float _text_view_pad_x = 10.0; const float _control_pad_x = 5.0; const float _control_pad_y = 10.0; const float _menu_field_pad_x = 30.0; const float _label_pad_x = 8.0; const float _transport_pad_y = 4.0; const float _transport_button_width = 60.0; const float _transport_button_height = 22.0; const float _transport_button_pad_x = 4.0; const float _lock_button_width = 42.0; const float _lock_button_height = 16.0; class TransportView::_layout_state { public: _layout_state() {} // +++++ }; inline float _menu_width( const BMenu* menu, const BFont* font) { float max = 0.0; int total = menu->CountItems(); for(int n = 0; n < total; ++n) { float w = font->StringWidth( menu->ItemAt(n)->Label()); if(w > max) max = w; } return max; } // -------------------------------------------------------- // void TransportView::_initLayout() { m_layout = new _layout_state(); } void TransportView::_updateLayout() // +++++ { BWindow* window = Window(); if(window) window->BeginViewTransaction(); // calculate the ideal size of the view // * max label width float maxLabelWidth = 0.0; float w; maxLabelWidth = be_bold_font->StringWidth( m_runModeView->Label()); w = be_bold_font->StringWidth( m_timeSourceView->Label()); if(w > maxLabelWidth) maxLabelWidth = w; // w = be_bold_font->StringWidth( // m_regionStartView->Label()); // if(w > maxLabelWidth) // maxLabelWidth = w; // // w = be_bold_font->StringWidth( // m_regionEndView->Label()); // if(w > maxLabelWidth) // maxLabelWidth = w; // * max field width float maxFieldWidth = 0.0; maxFieldWidth = _menu_width( m_runModeView->Menu(), be_plain_font); w = _menu_width( m_timeSourceView->Menu(), be_plain_font); if(w > maxFieldWidth) maxFieldWidth = w; // * column width float columnWidth = maxLabelWidth + maxFieldWidth + _label_pad_x + _field_pad_x; // figure columns float column1_x = _edge_pad_x; float column2_x = column1_x + columnWidth + _column_pad_x; // * sum to figure view width float viewWidth = column2_x + columnWidth + _edge_pad_x; // make room for buttons float buttonSpan = (_transport_button_width*3) + (_transport_button_pad_x*2); if(columnWidth < buttonSpan) viewWidth += (buttonSpan - columnWidth); // float insideWidth = viewWidth - (_edge_pad_x*2); // * figure view height a row at a time font_height fh; be_plain_font->GetHeight(&fh); float lineHeight = fh.ascent + fh.descent + fh.leading; float prefInfoWidth, prefInfoHeight; m_infoView->GetPreferredSize(&prefInfoWidth, &prefInfoHeight); float row_1_height = max(prefInfoHeight, _transport_button_height); float row1_y = _edge_pad_y; float row2_y = row1_y + row_1_height + _transport_pad_y; float row3_y = row2_y + lineHeight + _control_pad_y; // float row4_y = row3_y + lineHeight + _control_pad_y + _transport_pad_y; // float row5_y = row4_y + lineHeight + _control_pad_y; float viewHeight = row3_y + lineHeight + _control_pad_y + _edge_pad_y; // Place controls m_infoView->MoveTo( column1_x+1.0, row1_y+1.0); m_infoView->ResizeTo( columnWidth, prefInfoHeight); BRect br( column2_x, row1_y, column2_x+_transport_button_width, row1_y+_transport_button_height); if(prefInfoHeight > _transport_button_height) br.OffsetBy(0.0, (prefInfoHeight - _transport_button_height)/2); m_startButton->MoveTo(br.LeftTop()); m_startButton->ResizeTo(br.Width(), br.Height()); br.OffsetBy(_transport_button_width + _transport_button_pad_x, 0.0); m_stopButton->MoveTo(br.LeftTop()); m_stopButton->ResizeTo(br.Width(), br.Height()); br.OffsetBy(_transport_button_width + _transport_button_pad_x, 0.0); m_prerollButton->MoveTo(br.LeftTop()); m_prerollButton->ResizeTo(br.Width(), br.Height()); m_runModeView->MoveTo( column2_x, row2_y); m_runModeView->ResizeTo( columnWidth, lineHeight); m_runModeView->SetDivider( maxLabelWidth+_label_pad_x); m_runModeView->SetAlignment( B_ALIGN_LEFT); m_timeSourceView->MoveTo( column2_x, row3_y); m_timeSourceView->ResizeTo( columnWidth, lineHeight); m_timeSourceView->SetDivider( maxLabelWidth+_label_pad_x); m_timeSourceView->SetAlignment( B_ALIGN_LEFT); // float regionControlWidth = columnWidth; // float regionControlHeight = lineHeight + 4.0; // m_regionStartView->TextView()->SetResizingMode( // B_FOLLOW_LEFT_RIGHT|B_FOLLOW_TOP); // "FROM" BPoint rtLeftTop(column1_x, row2_y + 5.0); BPoint rtRightBottom; m_fromLabel->MoveTo(rtLeftTop); m_fromLabel->ResizeToPreferred(); rtRightBottom = rtLeftTop + BPoint( m_fromLabel->Bounds().Width(), m_fromLabel->Bounds().Height()); // (region-start) rtLeftTop.x = rtRightBottom.x+4; m_regionStartView->MoveTo(rtLeftTop + BPoint(0.0, 2.0)); m_regionStartView->ResizeToPreferred(); rtRightBottom = rtLeftTop + BPoint( m_regionStartView->Bounds().Width(), m_regionStartView->Bounds().Height()); // m_regionStartView->SetDivider( // maxLabelWidth); // m_regionStartView->TextView()->ResizeTo( // regionControlWidth-(maxLabelWidth+_text_view_pad_x), // regionControlHeight-4.0); // "TO" rtLeftTop.x = rtRightBottom.x + 6; m_toLabel->MoveTo(rtLeftTop); m_toLabel->ResizeToPreferred(); rtRightBottom = rtLeftTop + BPoint( m_toLabel->Bounds().Width(), m_toLabel->Bounds().Height()); // (region-end) rtLeftTop.x = rtRightBottom.x + 4; m_regionEndView->MoveTo(rtLeftTop + BPoint(0.0, 2.0)); m_regionEndView->ResizeToPreferred(); // m_regionEndView->SetDivider( // maxLabelWidth); // m_regionEndView->TextView()->ResizeTo( // regionControlWidth-(maxLabelWidth+_text_view_pad_x), // regionControlHeight-4.0); BRect b = Bounds(); float targetWidth = (b.Width() < viewWidth) ? viewWidth : b.Width(); float targetHeight = (b.Height() < viewHeight) ? viewHeight : b.Height(); // Resize view to fit contents ResizeTo(targetWidth, targetHeight); if(window) { window->ResizeTo(targetWidth, targetHeight); } // // +++++ testing NumericValControl [23aug99] // float valWidth, valHeight; // m_valView->GetPreferredSize(&valWidth, &valHeight); // PRINT(( // "\n\nm_valView preferred size: %.1f x %.1f\n\n", // valWidth, valHeight)); // if(window) window->EndViewTransaction(); } // -------------------------------------------------------- // // *** dtor // -------------------------------------------------------- // TransportView::~TransportView() { if(m_group) _releaseGroup(); if(m_layout) delete m_layout; } // END -- TransportView.cpp --