mirror of
https://github.com/LMMS/lmms.git
synced 2026-04-03 05:44:38 -04:00
523 lines
11 KiB
C++
523 lines
11 KiB
C++
/*
|
|
* TrackContainerView.cpp - view-component for TrackContainer
|
|
*
|
|
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
|
*
|
|
* 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 <QtGui/QApplication>
|
|
#include <QtGui/QLayout>
|
|
#include <QtGui/QMdiArea>
|
|
#include <QtGui/QProgressDialog>
|
|
#include <QtGui/QScrollBar>
|
|
#include <QtGui/QWheelEvent>
|
|
|
|
|
|
#include "TrackContainerView.h"
|
|
#include "TrackContainer.h"
|
|
#include "bb_track.h"
|
|
#include "MainWindow.h"
|
|
#include "debug.h"
|
|
#include "file_browser.h"
|
|
#include "ImportFilter.h"
|
|
#include "Instrument.h"
|
|
#include "InstrumentTrack.h"
|
|
#include "DataFile.h"
|
|
#include "rubberband.h"
|
|
#include "song.h"
|
|
#include "string_pair_drag.h"
|
|
#include "track.h"
|
|
|
|
|
|
TrackContainerView::TrackContainerView( TrackContainer * _tc ) :
|
|
QWidget(),
|
|
ModelView( NULL, this ),
|
|
JournallingObject(),
|
|
SerializingObjectHook(),
|
|
m_currentPosition( 0, 0 ),
|
|
m_tc( _tc ),
|
|
m_trackViews(),
|
|
m_scrollArea( new scrollArea( this ) ),
|
|
m_ppt( DEFAULT_PIXELS_PER_TACT ),
|
|
m_rubberBand( new rubberBand( m_scrollArea ) ),
|
|
m_origin()
|
|
{
|
|
m_tc->setHook( this );
|
|
|
|
QVBoxLayout * layout = new QVBoxLayout( this );
|
|
layout->setMargin( 0 );
|
|
layout->setSpacing( 0 );
|
|
layout->addWidget( m_scrollArea );
|
|
|
|
QWidget * scrollContent = new QWidget;
|
|
m_scrollLayout = new QVBoxLayout( scrollContent );
|
|
m_scrollLayout->setMargin( 0 );
|
|
m_scrollLayout->setSpacing( 0 );
|
|
m_scrollLayout->setSizeConstraint( QLayout::SetMinAndMaxSize );
|
|
|
|
m_scrollArea->setWidget( scrollContent );
|
|
|
|
m_scrollArea->show();
|
|
m_rubberBand->hide();
|
|
|
|
setAcceptDrops( true );
|
|
|
|
connect( engine::getSong(), SIGNAL( timeSignatureChanged( int, int ) ),
|
|
this, SLOT( realignTracks() ) );
|
|
connect( m_tc, SIGNAL( trackAdded( track * ) ),
|
|
this, SLOT( createTrackView( track * ) ),
|
|
Qt::QueuedConnection );
|
|
}
|
|
|
|
|
|
|
|
|
|
TrackContainerView::~TrackContainerView()
|
|
{
|
|
while( !m_trackViews.empty() )
|
|
{
|
|
delete m_trackViews.takeLast();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::saveSettings( QDomDocument & _doc,
|
|
QDomElement & _this )
|
|
{
|
|
MainWindow::saveWidgetState( this, _this );
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::loadSettings( const QDomElement & _this )
|
|
{
|
|
MainWindow::restoreWidgetState( this, _this );
|
|
}
|
|
|
|
|
|
|
|
|
|
trackView * TrackContainerView::addTrackView( trackView * _tv )
|
|
{
|
|
/* QMap<QString, QVariant> map;
|
|
map["id"] = _tv->getTrack()->id();
|
|
addJournalEntry( JournalEntry( AddTrack, map ) );*/
|
|
|
|
m_trackViews.push_back( _tv );
|
|
m_scrollLayout->addWidget( _tv );
|
|
connect( this, SIGNAL( positionChanged( const MidiTime & ) ),
|
|
_tv->getTrackContentWidget(),
|
|
SLOT( changePosition( const MidiTime & ) ) );
|
|
realignTracks();
|
|
return( _tv );
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::removeTrackView( trackView * _tv )
|
|
{
|
|
int index = m_trackViews.indexOf( _tv );
|
|
if( index != -1 )
|
|
{
|
|
/* QMap<QString, QVariant> map;
|
|
DataFile dataFile( DataFile::JournalData );
|
|
_tv->getTrack()->saveState( dataFile, dataFile.content() );
|
|
map["id"] = _tv->getTrack()->id();
|
|
map["state"] = dataFile.toString();
|
|
addJournalEntry( JournalEntry( RemoveTrack, map ) );*/
|
|
|
|
m_trackViews.removeAt( index );
|
|
|
|
disconnect( _tv );
|
|
m_scrollLayout->removeWidget( _tv );
|
|
|
|
realignTracks();
|
|
if( engine::getSong() )
|
|
{
|
|
engine::getSong()->setModified();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::moveTrackViewUp( trackView * _tv )
|
|
{
|
|
for( int i = 1; i < m_trackViews.size(); ++i )
|
|
{
|
|
trackView * t = m_trackViews[i];
|
|
if( t == _tv )
|
|
{
|
|
bbTrack::swapBBTracks( t->getTrack(),
|
|
m_trackViews[i - 1]->getTrack() );
|
|
m_scrollLayout->removeWidget( t );
|
|
m_scrollLayout->insertWidget( i - 1, t );
|
|
qSwap( m_tc->m_tracks[i-1], m_tc->m_tracks[i] );
|
|
m_trackViews.swap( i - 1, i );
|
|
realignTracks();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::moveTrackViewDown( trackView * _tv )
|
|
{
|
|
for( int i = 0; i < m_trackViews.size()-1; ++i )
|
|
{
|
|
trackView * t = m_trackViews[i];
|
|
if( t == _tv )
|
|
{
|
|
bbTrack::swapBBTracks( t->getTrack(),
|
|
m_trackViews[i + 1]->getTrack() );
|
|
m_scrollLayout->removeWidget( t );
|
|
m_scrollLayout->insertWidget( i + 1, t );
|
|
qSwap( m_tc->m_tracks[i], m_tc->m_tracks[i+1] );
|
|
m_trackViews.swap( i, i + 1 );
|
|
realignTracks();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::realignTracks()
|
|
{
|
|
QWidget * content = m_scrollArea->widget();
|
|
content->setFixedWidth( width()
|
|
- m_scrollArea->verticalScrollBar()->width() );
|
|
content->setFixedHeight( content->minimumSizeHint().height() );
|
|
|
|
for( trackViewList::iterator it = m_trackViews.begin();
|
|
it != m_trackViews.end(); ++it )
|
|
{
|
|
( *it )->show();
|
|
( *it )->update();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::createTrackView( track * _t )
|
|
{
|
|
_t->createView( this );
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::deleteTrackView( trackView * _tv )
|
|
{
|
|
track * t = _tv->getTrack();
|
|
removeTrackView( _tv );
|
|
delete _tv;
|
|
|
|
engine::mixer()->lock();
|
|
delete t;
|
|
engine::mixer()->unlock();
|
|
}
|
|
|
|
|
|
|
|
|
|
const trackView * TrackContainerView::trackViewAt( const int _y ) const
|
|
{
|
|
const int abs_y = _y + m_scrollArea->verticalScrollBar()->value();
|
|
int y_cnt = 0;
|
|
|
|
// debug code
|
|
// qDebug( "abs_y %d", abs_y );
|
|
|
|
for( trackViewList::const_iterator it = m_trackViews.begin();
|
|
it != m_trackViews.end(); ++it )
|
|
{
|
|
const int y_cnt1 = y_cnt;
|
|
y_cnt += ( *it )->height();
|
|
if( abs_y >= y_cnt1 && abs_y < y_cnt )
|
|
{
|
|
return( *it );
|
|
}
|
|
}
|
|
return( NULL );
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TrackContainerView::allowRubberband() const
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::setPixelsPerTact( int _ppt )
|
|
{
|
|
m_ppt = _ppt;
|
|
|
|
// tell all TrackContentWidgets to update their background tile pixmap
|
|
for( trackViewList::Iterator it = m_trackViews.begin();
|
|
it != m_trackViews.end(); ++it )
|
|
{
|
|
( *it )->getTrackContentWidget()->updateBackground();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::clearAllTracks()
|
|
{
|
|
while( !m_trackViews.empty() )
|
|
{
|
|
trackView * tv = m_trackViews.takeLast();
|
|
track * t = tv->getTrack();
|
|
delete tv;
|
|
delete t;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::undoStep( JournalEntry & _je )
|
|
{
|
|
#if 0
|
|
saveJournallingState( false );
|
|
switch( _je.actionID() )
|
|
{
|
|
case AddTrack:
|
|
{
|
|
QMap<QString, QVariant> map = _je.data().toMap();
|
|
track * t =
|
|
dynamic_cast<track *>(
|
|
engine::projectJournal()->getJournallingObject(
|
|
map["id"].toInt() ) );
|
|
assert( t != NULL );
|
|
DataFile dataFile( DataFile::JournalData );
|
|
t->saveState( dataFile, dataFile.content() );
|
|
map["state"] = dataFile.toString();
|
|
_je.data() = map;
|
|
t->deleteLater();
|
|
break;
|
|
}
|
|
|
|
case RemoveTrack:
|
|
{
|
|
DataFile dataFile(
|
|
_je.data().toMap()["state"].toString().utf8() );
|
|
track::create( dataFile.content().firstChild().toElement(),
|
|
m_tc );
|
|
break;
|
|
}
|
|
}
|
|
restoreJournallingState();
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::redoStep( JournalEntry & _je )
|
|
{
|
|
#if 0
|
|
switch( _je.actionID() )
|
|
{
|
|
case AddTrack:
|
|
case RemoveTrack:
|
|
_je.actionID() = ( _je.actionID() == AddTrack ) ?
|
|
RemoveTrack : AddTrack;
|
|
undoStep( _je );
|
|
_je.actionID() = ( _je.actionID() == AddTrack ) ?
|
|
RemoveTrack : AddTrack;
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::dragEnterEvent( QDragEnterEvent * _dee )
|
|
{
|
|
stringPairDrag::processDragEnterEvent( _dee,
|
|
QString( "presetfile,pluginpresetfile,samplefile,instrument,"
|
|
"importedproject,track_%1,track_%2" ).
|
|
arg( track::InstrumentTrack ).
|
|
arg( track::SampleTrack ) );
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::dropEvent( QDropEvent * _de )
|
|
{
|
|
QString type = stringPairDrag::decodeKey( _de );
|
|
QString value = stringPairDrag::decodeValue( _de );
|
|
engine::mixer()->lock();
|
|
if( type == "instrument" )
|
|
{
|
|
InstrumentTrack * it = dynamic_cast<InstrumentTrack *>(
|
|
track::create( track::InstrumentTrack,
|
|
m_tc ) );
|
|
it->loadInstrument( value );
|
|
//it->toggledInstrumentTrackButton( true );
|
|
_de->accept();
|
|
}
|
|
else if( type == "samplefile" || type == "pluginpresetfile" )
|
|
{
|
|
InstrumentTrack * it = dynamic_cast<InstrumentTrack *>(
|
|
track::create( track::InstrumentTrack,
|
|
m_tc ) );
|
|
Instrument * i = it->loadInstrument(
|
|
engine::pluginFileHandling()[fileItem::extension(
|
|
value )]);
|
|
i->loadFile( value );
|
|
//it->toggledInstrumentTrackButton( true );
|
|
_de->accept();
|
|
}
|
|
else if( type == "presetfile" )
|
|
{
|
|
DataFile dataFile( value );
|
|
InstrumentTrack * it = dynamic_cast<InstrumentTrack *>(
|
|
track::create( track::InstrumentTrack,
|
|
m_tc ) );
|
|
it->setSimpleSerializing();
|
|
it->loadSettings( dataFile.content().toElement() );
|
|
//it->toggledInstrumentTrackButton( true );
|
|
_de->accept();
|
|
}
|
|
else if( type == "importedproject" )
|
|
{
|
|
ImportFilter::import( value, m_tc );
|
|
_de->accept();
|
|
}
|
|
else if( type.left( 6 ) == "track_" )
|
|
{
|
|
DataFile dataFile( value.toUtf8() );
|
|
track::create( dataFile.content().firstChild().toElement(), m_tc );
|
|
_de->accept();
|
|
}
|
|
engine::mixer()->unlock();
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::mousePressEvent( QMouseEvent * _me )
|
|
{
|
|
if( allowRubberband() == true )
|
|
{
|
|
m_origin = m_scrollArea->mapFromParent( _me->pos() );
|
|
m_rubberBand->setGeometry( QRect( m_origin, QSize() ) );
|
|
m_rubberBand->show();
|
|
}
|
|
QWidget::mousePressEvent( _me );
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::mouseMoveEvent( QMouseEvent * _me )
|
|
{
|
|
if( rubberBandActive() == true )
|
|
{
|
|
m_rubberBand->setGeometry( QRect( m_origin,
|
|
m_scrollArea->mapFromParent( _me->pos() ) ).
|
|
normalized() );
|
|
}
|
|
QWidget::mouseMoveEvent( _me );
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::mouseReleaseEvent( QMouseEvent * _me )
|
|
{
|
|
m_rubberBand->hide();
|
|
QWidget::mouseReleaseEvent( _me );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::resizeEvent( QResizeEvent * _re )
|
|
{
|
|
realignTracks();
|
|
QWidget::resizeEvent( _re );
|
|
}
|
|
|
|
|
|
|
|
|
|
TrackContainerView::scrollArea::scrollArea( TrackContainerView * _parent ) :
|
|
QScrollArea( _parent ),
|
|
m_trackContainerView( _parent )
|
|
{
|
|
setFrameStyle( QFrame::NoFrame );
|
|
setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
|
|
setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
|
|
}
|
|
|
|
|
|
|
|
|
|
TrackContainerView::scrollArea::~scrollArea()
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackContainerView::scrollArea::wheelEvent( QWheelEvent * _we )
|
|
{
|
|
// always pass wheel-event to parent-widget (song-editor
|
|
// bb-editor etc.) because they might want to use it for zooming
|
|
// or scrolling left/right if a modifier-key is pressed, otherwise
|
|
// they do not accept it and we pass it up to QScrollArea
|
|
m_trackContainerView->wheelEvent( _we );
|
|
if( !_we->isAccepted() )
|
|
{
|
|
QScrollArea::wheelEvent( _we );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "moc_TrackContainerView.cxx"
|
|
|