#ifndef SINGLE_SOURCE_COMPILE /* * bb_track.cpp - implementation of class bbTrack and bbTCO * * Copyright (c) 2004-2007 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program (see COPYING); if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * */ #include "qt3support.h" #ifdef QT4 #include #include #include #include #else #include #include #include #include #endif #include "bb_track.h" #include "bb_editor.h" #include "embed.h" #include "engine.h" #include "gui_templates.h" #include "mixer.h" #include "name_label.h" #include "rename_dialog.h" #include "song_editor.h" #include "templates.h" bbTrack::infoMap bbTrack::s_infoMap; bbTCO::bbTCO( track * _track, const QColor & _c ) : trackContentObject( _track ), m_name( ( dynamic_cast( _track ) != NULL ) ? dynamic_cast( _track )->trackLabel()->text() : QString( "" ) ), m_color( _c.isValid() ? _c : QColor( 64, 128, 255 ) ) { #ifndef QT4 setBackgroundMode( Qt::NoBackground ); #endif tact t = engine::getBBEditor()->lengthOfBB( bbTrack::numOfBBTrack( getTrack() ) ); if( t > 0 ) { saveJournallingState( FALSE ); changeLength( midiTime( t, 0 ) ); restoreJournallingState(); } } bbTCO::~bbTCO() { } void bbTCO::constructContextMenu( QMenu * _cm ) { #ifdef QT4 QAction * a = new QAction( embed::getIconPixmap( "bb_track" ), tr( "Open in Beat+Baseline-Editor" ), _cm ); _cm->insertAction( _cm->actions()[0], a ); connect( a, SIGNAL( triggered( bool ) ), this, SLOT( openInBBEditor( bool ) ) ); #else _cm->insertItem( embed::getIconPixmap( "bb_track" ), tr( "Open in Beat+Baseline-Editor" ), this, SLOT( openInBBEditor() ), 0, -1, 0 ); #endif #ifdef QT4 _cm->insertSeparator( _cm->actions()[1] ); #else _cm->insertSeparator( 1 ); #endif #ifdef QT4 _cm->addSeparator(); #else _cm->insertSeparator(); #endif _cm->addAction( embed::getIconPixmap( "reload" ), tr( "Reset name" ), this, SLOT( resetName() ) ); _cm->addAction( embed::getIconPixmap( "rename" ), tr( "Change name" ), this, SLOT( changeName() ) ); _cm->addAction( embed::getIconPixmap( "colorize" ), tr( "Change color" ), this, SLOT( changeColor() ) ); } void bbTCO::mouseDoubleClickEvent( QMouseEvent * ) { openInBBEditor(); } void bbTCO::paintEvent( QPaintEvent * ) { QColor col = m_color; if( getTrack()->muted() || muted() ) { col = QColor( 160, 160, 160 ); } if( isSelected() == TRUE ) { col = QColor( tMax( col.red() - 128, 0 ), tMax( col.green() - 128, 0 ), 255 ); } #ifdef QT4 QPainter p( this ); QLinearGradient lingrad( 0, 0, 0, height() ); lingrad.setColorAt( 0, col.light( 130 ) ); lingrad.setColorAt( 1, col.light( 70 ) ); p.fillRect( rect(), lingrad ); #else // create pixmap for whole widget QPixmap pm( rect().size() ); // and a painter for it QPainter p( &pm ); // COOL gradient ;-) for( int y = 1; y < height() - 1; ++y ) { p.setPen( col.light( 130 - y * 60 / height() ) ); p.drawLine( 1, y, width() - 1, y ); } #endif tact t = engine::getBBEditor()->lengthOfBB( bbTrack::numOfBBTrack( getTrack() ) ); if( length() > 64 && t > 0 ) { for( int x = static_cast( t * pixelsPerTact() ); x < width()-2; x += static_cast( t * pixelsPerTact() ) ) { p.setPen( col.light( 80 ) ); p.drawLine( x, 1, x, 5 ); p.setPen( col.light( 120 ) ); p.drawLine( x, height() - 6, x, height() - 2 ); } } p.setPen( col.dark() ); #ifndef QT3 p.drawRect( 0, 0, rect().right(), rect().bottom() ); #else p.drawRect( rect() ); #endif p.setFont( pointSize<7>( p.font() ) ); p.setPen( QColor( 0, 0, 0 ) ); p.drawText( 2, p.fontMetrics().height() - 1, m_name ); if( muted() ) { p.drawPixmap( 3, p.fontMetrics().height() + 1, embed::getIconPixmap( "muted", 16, 16 ) ); } #ifndef QT4 bitBlt( this, rect().topLeft(), &pm ); #endif } void bbTCO::saveSettings( QDomDocument & _doc, QDomElement & _this ) { _this.setAttribute( "name", m_name ); if( _this.parentNode().nodeName() == "clipboard" ) { _this.setAttribute( "pos", -1 ); } else { _this.setAttribute( "pos", startPosition() ); } _this.setAttribute( "len", length() ); _this.setAttribute( "muted", muted() ); _this.setAttribute( "color", m_color.rgb() ); } void bbTCO::loadSettings( const QDomElement & _this ) { m_name = _this.attribute( "name" ); if( _this.attribute( "pos" ).toInt() >= 0 ) { movePosition( _this.attribute( "pos" ).toInt() ); } changeLength( _this.attribute( "len" ).toInt() ); if( _this.attribute( "muted" ).toInt() != muted() ) { toggleMute(); } if( _this.attribute( "color" ).toUInt() != 0 ) { m_color.setRgb( _this.attribute( "color" ).toUInt() ); } } void bbTCO::openInBBEditor( bool ) { engine::getBBEditor()->setCurrentBB( bbTrack::numOfBBTrack( getTrack() ) ); engine::getBBEditor()->show(); engine::getBBEditor()->setFocus(); } void bbTCO::openInBBEditor( void ) { openInBBEditor( FALSE ); } void bbTCO::resetName( void ) { if( dynamic_cast( getTrack() ) != NULL ) { m_name = dynamic_cast( getTrack() )-> trackLabel()->text(); } } void bbTCO::changeName( void ) { renameDialog rename_dlg( m_name ); rename_dlg.exec(); } void bbTCO::changeColor( void ) { QColor _new_color = QColorDialog::getColor( m_color ); if( !_new_color.isValid() ) { return; } if( isSelected() ) { vvector selected = engine::getSongEditor()->selectedObjects(); for( vvector::iterator it = selected.begin(); it != selected.end(); ++it ) { bbTCO * bb_tco = dynamic_cast( *it ); if( bb_tco ) { bb_tco->setColor( _new_color ); } } } else { setColor( _new_color ); } } void bbTCO::setColor( QColor _new_color ) { if( _new_color != m_color ) { m_color = _new_color; engine::getSongEditor()->setModified(); update(); } } bbTrack::bbTrack( trackContainer * _tc ) : track( _tc ) { getTrackWidget()->setFixedHeight( 32 ); // drag'n'drop with bb-tracks only causes troubles (and makes no sense // too), so disable it getTrackWidget()->setAcceptDrops( FALSE ); csize bbNum = s_infoMap.size(); s_infoMap[this] = bbNum; m_trackLabel = new nameLabel( tr( "Beat/Baseline %1" ).arg( bbNum ), getTrackSettingsWidget() ); m_trackLabel->setPixmap( embed::getIconPixmap( "bb_track" ) ); m_trackLabel->setGeometry( 1, 1, DEFAULT_SETTINGS_WIDGET_WIDTH - 2, 29 ); m_trackLabel->show(); connect( m_trackLabel, SIGNAL( clicked() ), this, SLOT( clickedTrackLabel() ) ); connect( m_trackLabel, SIGNAL( nameChanged() ), engine::getBBEditor(), SLOT( updateComboBox() ) ); connect( m_trackLabel, SIGNAL( pixmapChanged() ), engine::getBBEditor(), SLOT( updateComboBox() ) ); engine::getBBEditor()->setCurrentBB( bbNum ); engine::getBBEditor()->updateComboBox(); _tc->updateAfterTrackAdd(); } bbTrack::~bbTrack() { engine::getMixer()->removePlayHandles( this ); csize bb = s_infoMap[this]; engine::getBBEditor()->removeBB( bb ); for( infoMap::iterator it = s_infoMap.begin(); it != s_infoMap.end(); ++it ) { #ifdef QT4 if( it.value() > bb ) { --it.value(); } #else if( it.data() > bb ) { --it.data(); } #endif } s_infoMap.remove( this ); engine::getBBEditor()->updateComboBox(); } track::trackTypes bbTrack::type( void ) const { return( BB_TRACK ); } // play _frames frames of given TCO within starting with _start bool FASTCALL bbTrack::play( const midiTime & _start, const fpab_t _frames, const f_cnt_t _frame_base, Sint16 _tco_num ) { sendMidiTime( _start ); if( _tco_num >= 0 ) { return( engine::getBBEditor()->play( _start, _frames, _frame_base, s_infoMap[this] ) ); } vlist tcos; getTCOsInRange( tcos, _start, _start + static_cast( _frames / engine::framesPerTact64th() ) ); if ( tcos.size() == 0 ) { return( FALSE ); } midiTime lastPosition; midiTime lastLen; for( vlist::iterator it = tcos.begin(); it != tcos.end(); ++it ) { if( !( *it )->muted() && ( *it )->startPosition() >= lastPosition ) { lastPosition = ( *it )->startPosition(); lastLen = ( *it )->length(); } } if( _start - lastPosition < lastLen ) { return( engine::getBBEditor()->play( _start - lastPosition, _frames, _frame_base, s_infoMap[this] ) ); } return( FALSE ); } trackContentObject * bbTrack::createTCO( const midiTime & _pos ) { // if we're creating a new bbTCO, we colorize it according to the // previous bbTCO, so we have to get all TCOs from 0 to _pos and // pickup the last and take the color if it vlist tcos; getTCOsInRange( tcos, 0, _pos ); if( tcos.size() > 0 && dynamic_cast( tcos.back() ) != NULL ) { return( new bbTCO( this, dynamic_cast( tcos.back() )->color() ) ); } return( new bbTCO( this ) ); } void bbTrack::saveTrackSpecificSettings( QDomDocument & _doc, QDomElement & _this ) { _this.setAttribute( "name", m_trackLabel->text() ); _this.setAttribute( "icon", m_trackLabel->pixmapFile() ); /* _this.setAttribute( "current", s_infoMap[this] == engine::getBBEditor()->currentBB() );*/ if( s_infoMap[this] == 0 && _this.parentNode().parentNode().nodeName() != "clone" && _this.parentNode().nodeName() != "journaldata" ) { ( (journallingObject *)( engine::getBBEditor() ) )->saveState( _doc, _this ); } int track_num = 0; trackVector tracks = engine::getBBEditor()->tracks(); for( trackVector::iterator it = tracks.begin(); it != tracks.end(); ++it, ++track_num ) { if( automationDisabled( *it ) ) { QDomElement disabled = _doc.createElement( "automation-disabled" ); disabled.setAttribute( "track", track_num ); _this.appendChild( disabled ); } } } void bbTrack::loadTrackSpecificSettings( const QDomElement & _this ) { m_trackLabel->setText( _this.attribute( "name" ) ); if( _this.attribute( "icon" ) != "" ) { m_trackLabel->setPixmapFile( _this.attribute( "icon" ) ); } engine::getBBEditor()->updateComboBox(); QDomNode node = _this.namedItem( trackContainer::classNodeName() ); if( node.isElement() ) { ( (journallingObject *)engine::getBBEditor() )->restoreState( node.toElement() ); } /* doesn't work yet because bbTrack-ctor also sets current bb so if bb-tracks are created after this function is called, this doesn't help at all.... if( _this.attribute( "current" ).toInt() ) { engine::getBBEditor()->setCurrentBB( s_infoMap[this] ); }*/ trackVector tracks = engine::getBBEditor()->tracks(); node = _this.firstChild(); while( !node.isNull() ) { if( node.isElement() && node.nodeName() == "automation-disabled" ) { disableAutomation( tracks[node.toElement().attribute( "track" ).toInt()] ); } node = node.nextSibling(); } } // return pointer to bbTrack specified by _bb_num bbTrack * bbTrack::findBBTrack( csize _bb_num ) { for( infoMap::iterator it = s_infoMap.begin(); it != s_infoMap.end(); ++it ) { #ifdef QT4 if( it.value() == _bb_num ) #else if( it.data() == _bb_num ) #endif { return( it.key() ); } } return( NULL ); } csize bbTrack::numOfBBTrack( track * _track ) { if( dynamic_cast( _track ) != NULL ) { return( s_infoMap[dynamic_cast( _track )] ); } return( 0 ); } void bbTrack::swapBBTracks( track * _track1, track * _track2 ) { bbTrack * t1 = dynamic_cast( _track1 ); bbTrack * t2 = dynamic_cast( _track2 ); if( t1 != NULL && t2 != NULL ) { qSwap( s_infoMap[t1], s_infoMap[t2] ); engine::getBBEditor()->swapBB( s_infoMap[t1], s_infoMap[t2] ); engine::getBBEditor()->setCurrentBB( s_infoMap[t1] ); } } void bbTrack::clickedTrackLabel( void ) { engine::getBBEditor()->setCurrentBB( s_infoMap[this] ); engine::getBBEditor()->show(); } #include "bb_track.moc" #endif