From cd0176b5afe18eef71bc45c66ec2017a109a0602 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Wed, 29 Jul 2015 22:35:06 +0200 Subject: [PATCH] Controllers are rendered more dynamically ControllerRackView now uses a layout to organize the ControllerViews. The ControllerViews in turn use layouts to organize their widgets (labels and push button). ControllerView now inherits from QFrame instead of QWidget. The (static) background image for controllers was deleted because the ControllerView can now be resized dynamically. Song: Added specific signals for added and removed controllers. Also removed a TODO by putting the functionality to remove all controllers in a method (removeAllControllers). Deleted Controllers now don't unregister from Song during deletion. This has to be done by the client (Hollywood principle - "Don't call us, we call you."). TODO: For some strange reason I cannot programmatically resize the controller rack to make it fit the controllers on my screen. --- data/themes/default/controller_bg.png | Bin 5240 -> 0 bytes include/ControllerRackView.h | 9 +- include/ControllerView.h | 7 +- include/Song.h | 4 + src/core/Controller.cpp | 5 -- src/core/Song.cpp | 38 ++++++--- src/gui/widgets/ControllerRackView.cpp | 113 +++++++++++++------------ src/gui/widgets/ControllerView.cpp | 56 +++++------- 8 files changed, 120 insertions(+), 112 deletions(-) delete mode 100644 data/themes/default/controller_bg.png diff --git a/data/themes/default/controller_bg.png b/data/themes/default/controller_bg.png deleted file mode 100644 index 6d7830fffc51792f273d452d67921378d180dcd0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5240 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 m_controllerViews; QScrollArea * m_scrollArea; + QVBoxLayout * m_scrollAreaLayout; QPushButton * m_addButton; + // Stores the index of where to insert the next ControllerView. + // Needed so that the StretchItem always stays at the last position. + int m_nextIndex; } ; #endif diff --git a/include/ControllerView.h b/include/ControllerView.h index f1d73c400..8903c0e3c 100644 --- a/include/ControllerView.h +++ b/include/ControllerView.h @@ -25,7 +25,7 @@ #ifndef CONTROLLER_VIEW_H #define CONTROLLER_VIEW_H -#include +#include #include "AutomatableModel.h" #include "Controller.h" @@ -39,7 +39,7 @@ class QMdiSubWindow; class LedCheckBox; -class ControllerView : public QWidget, public ModelView +class ControllerView : public QFrame, public ModelView { Q_OBJECT public: @@ -70,15 +70,14 @@ signals: protected: virtual void contextMenuEvent( QContextMenuEvent * _me ); - virtual void paintEvent( QPaintEvent * _pe ); virtual void modelChanged(); virtual void mouseDoubleClickEvent( QMouseEvent * event ); private: - QPixmap m_bg; QMdiSubWindow * m_subWindow; ControllerDialog * m_controllerDlg; + QLabel * m_nameLabel; bool m_show; } ; diff --git a/include/Song.h b/include/Song.h index 8f33a208b..8c7d6d899 100644 --- a/include/Song.h +++ b/include/Song.h @@ -323,6 +323,8 @@ private: void saveControllerStates( QDomDocument & doc, QDomElement & element ); void restoreControllerStates( const QDomElement & element ); + void removeAllControllers(); + AutomationTrack * m_globalAutomationTrack; @@ -376,6 +378,8 @@ signals: void lengthChanged( int tacts ); void tempoChanged( bpm_t newBPM ); void timeSignatureChanged( int oldTicksPerTact, int ticksPerTact ); + void controllerAdded( Controller * ); + void controllerRemoved( Controller * ); } ; diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp index 325399e0b..bb9ecef4f 100644 --- a/src/core/Controller.cpp +++ b/src/core/Controller.cpp @@ -95,11 +95,6 @@ Controller::~Controller() s_controllers.remove( idx ); } - if( Engine::getSong() ) - { - Engine::getSong()->removeController( this ); - } - m_valueBuffer.clear(); // Remove connections by destroyed signal } diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 21ab0ed49..fe9a124b3 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -828,11 +828,7 @@ void Song::clearProject() gui->getProjectNotes()->clear(); } - // Move to function - while( !m_controllers.empty() ) - { - delete m_controllers.last(); - } + removeAllControllers(); emit dataChanged(); @@ -1215,6 +1211,19 @@ void Song::restoreControllerStates( const QDomElement & element ) } + +void Song::removeAllControllers() +{ + for (int i = 0; i < m_controllers.size(); ++i) + { + delete m_controllers.at(i); + } + + m_controllers.clear(); +} + + + void Song::exportProjectTracks() { exportProject( true ); @@ -1383,12 +1392,14 @@ void Song::setModified() -void Song::addController( Controller * c ) +void Song::addController( Controller * controller ) { - if( c != NULL && m_controllers.contains( c ) == false ) + if( controller && !m_controllers.contains( controller ) ) { - m_controllers.append( c ); - emit dataChanged(); + m_controllers.append( controller ); + emit controllerAdded( controller ); + + this->setModified(); } } @@ -1402,11 +1413,10 @@ void Song::removeController( Controller * controller ) { m_controllers.remove( index ); - if( Engine::getSong() ) - { - Engine::getSong()->setModified(); - } - emit dataChanged(); + emit controllerRemoved( controller ); + delete controller; + + this->setModified(); } } diff --git a/src/gui/widgets/ControllerRackView.cpp b/src/gui/widgets/ControllerRackView.cpp index 182571093..b727869af 100644 --- a/src/gui/widgets/ControllerRackView.cpp +++ b/src/gui/widgets/ControllerRackView.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "Song.h" #include "embed.h" @@ -43,32 +44,32 @@ ControllerRackView::ControllerRackView( ) : - QWidget() + QWidget(), + m_nextIndex(0) { - setMinimumWidth( 250 ); - setMaximumWidth( 250 ); - resize( 250, 160 ); - setWindowIcon( embed::getIconPixmap( "controller" ) ); setWindowTitle( tr( "Controller Rack" ) ); m_scrollArea = new QScrollArea( this ); - m_scrollArea->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn ); - m_scrollArea->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); m_scrollArea->setPalette( QApplication::palette( m_scrollArea ) ); - m_scrollArea->setMinimumHeight( 64 ); + + QWidget * scrollAreaWidget = new QWidget( m_scrollArea ); + m_scrollAreaLayout = new QVBoxLayout( scrollAreaWidget ); + m_scrollAreaLayout->addStretch(); + scrollAreaWidget->setLayout( m_scrollAreaLayout ); + + m_scrollArea->setWidget( scrollAreaWidget ); + m_scrollArea->setWidgetResizable( true ); m_addButton = new QPushButton( this ); m_addButton->setText( tr( "Add" ) ); - QWidget * w = new QWidget(); - m_scrollArea->setWidget( w ); - connect( m_addButton, SIGNAL( clicked() ), this, SLOT( addController() ) ); - connect( Engine::getSong(), SIGNAL( dataChanged() ), - this, SLOT( update() ) ); + Song * song = Engine::getSong(); + connect( song, SIGNAL( controllerAdded( Controller* ) ), SLOT( onControllerAdded( Controller* ) ) ); + connect( song, SIGNAL( controllerRemoved( Controller* ) ), SLOT( onControllerRemoved( Controller* ) ) ); QVBoxLayout * layout = new QVBoxLayout(); layout->addWidget( m_scrollArea ); @@ -82,8 +83,10 @@ ControllerRackView::ControllerRackView( ) : flags &= ~Qt::WindowMaximizeButtonHint; subWin->setWindowFlags( flags ); - parentWidget()->setAttribute( Qt::WA_DeleteOnClose, false ); - parentWidget()->move( 880, 310 ); + subWin->setAttribute( Qt::WA_DeleteOnClose, false ); + subWin->move( 880, 310 ); + + resize( 600, 400 ); } @@ -91,8 +94,6 @@ ControllerRackView::ControllerRackView( ) : ControllerRackView::~ControllerRackView() { - // delete scroll-area with all children - delete m_scrollArea; } @@ -119,8 +120,7 @@ void ControllerRackView::deleteController( ControllerView * _view ) { Controller * c = _view->getController(); - int connectionCount = c->connectionCount(); - if( connectionCount > 0 ) + if( c->connectionCount() > 0 ) { QMessageBox msgBox; msgBox.setIcon( QMessageBox::Question ); @@ -134,58 +134,63 @@ void ControllerRackView::deleteController( ControllerView * _view ) } } - - m_controllerViews.erase( qFind( m_controllerViews.begin(), - m_controllerViews.end(), _view ) ); - delete _view; - delete c; - update(); + Song * song = Engine::getSong(); + song->removeController( c ); } -void ControllerRackView::update() +void ControllerRackView::onControllerAdded( Controller * controller ) { - QWidget * w = m_scrollArea->widget(); - Song * s = Engine::getSong(); + QWidget * scrollAreaWidget = m_scrollArea->widget(); - setUpdatesEnabled( false ); + ControllerView * controllerView = new ControllerView( controller, scrollAreaWidget ); - int i = 0; - for( i = 0; i < m_controllerViews.size(); ++i ) - { - delete m_controllerViews[i]; - } + connect( controllerView, SIGNAL( deleteController( ControllerView * ) ), + this, SLOT( deleteController( ControllerView * ) ), Qt::QueuedConnection ); - m_controllerViews.clear(); - - for( i = 0; i < s->m_controllers.size(); ++i ) - { - ControllerView * v = new ControllerView( s->m_controllers[i], w ); - - connect( v, SIGNAL( deleteController( ControllerView * ) ), - this, SLOT( deleteController( ControllerView * ) ), - Qt::QueuedConnection ); - - m_controllerViews.append( v ); - v->move( 0, i*32 ); - v->show(); - } - - w->setFixedSize( 210, i*32 ); - - setUpdatesEnabled( true ); - QWidget::update(); + m_controllerViews.append( controllerView ); + m_scrollAreaLayout->insertWidget( m_nextIndex, controllerView ); + ++m_nextIndex; } + + +void ControllerRackView::onControllerRemoved( Controller * removedController ) +{ + ControllerView * viewOfRemovedController = 0; + + QVector::const_iterator end = m_controllerViews.end(); + for ( QVector::const_iterator it = m_controllerViews.begin(); it != end; ++it) + { + ControllerView *currentControllerView = *it; + if ( currentControllerView->getController() == removedController ) + { + viewOfRemovedController = currentControllerView; + break; + } + } + + if (viewOfRemovedController ) + { + m_controllerViews.erase( qFind( m_controllerViews.begin(), + m_controllerViews.end(), viewOfRemovedController ) ); + + delete viewOfRemovedController; + --m_nextIndex; + } +} + + + + void ControllerRackView::addController() { // TODO: Eventually let the user pick from available controller types Engine::getSong()->addController( new LfoController( Engine::getSong() ) ); - update(); // fix bug which always made ControllerRackView loose focus when adding // new controller diff --git a/src/gui/widgets/ControllerView.cpp b/src/gui/widgets/ControllerView.cpp index b6ed84333..54cf8c8b7 100644 --- a/src/gui/widgets/ControllerView.cpp +++ b/src/gui/widgets/ControllerView.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "ControllerView.h" @@ -46,22 +47,32 @@ ControllerView::ControllerView( Controller * _model, QWidget * _parent ) : - QWidget( _parent ), + QFrame( _parent ), ModelView( _model, this ), - m_bg( embed::getIconPixmap( "controller_bg" ) ), m_subWindow( NULL ), m_controllerDlg( NULL ), m_show( true ) { - setFixedSize( 210, 32 ); + this->setFrameStyle( QFrame::StyledPanel ); + this->setFrameShadow( QFrame::Raised ); + + QVBoxLayout *vBoxLayout = new QVBoxLayout(this); + + QHBoxLayout *hBox = new QHBoxLayout(); + vBoxLayout->addLayout(hBox); + + QLabel *label = new QLabel( "" + _model->displayName() + "", this); + + hBox->addWidget(label); + + QPushButton * controlsButton = new QPushButton( tr( "Controls" ), this ); + connect( controlsButton, SIGNAL( clicked() ), SLOT( editControls() ) ); + + hBox->addWidget(controlsButton); + + m_nameLabel = new QLabel(_model->name(), this); + vBoxLayout->addWidget(m_nameLabel); - QPushButton * ctls_btn = new QPushButton( tr( "Controls" ), this ); - - QFont f = ctls_btn->font(); - ctls_btn->setFont( pointSize<8>( f ) ); - ctls_btn->setGeometry( 140, 2, 50, 14 ); - connect( ctls_btn, SIGNAL( clicked() ), - this, SLOT( editControls() ) ); m_controllerDlg = getController()->createDialog( gui->mainWindow()->workspace() ); @@ -90,7 +101,6 @@ ControllerView::ControllerView( Controller * _model, QWidget * _parent ) : ControllerView::~ControllerView() { - delete m_subWindow; } @@ -128,28 +138,6 @@ void ControllerView::deleteController() -void ControllerView::paintEvent( QPaintEvent * ) -{ - QPainter p( this ); - p.drawPixmap( 0, 0, m_bg ); - - QFont f = pointSizeF( font(), 7.5f ); - f.setBold( true ); - p.setFont( f ); - - Controller * c = castModel(); - - p.setPen( QColor( 64, 64, 64 ) ); - p.drawText( 7, 13, c->displayName() ); - p.setPen( Qt::white ); - p.drawText( 6, 12, c->displayName() ); - - f.setBold( false ); - p.setFont( f ); - p.drawText( 8, 26, c->name() ); -} - - void ControllerView::mouseDoubleClickEvent( QMouseEvent * event ) { @@ -162,7 +150,7 @@ void ControllerView::mouseDoubleClickEvent( QMouseEvent * event ) if( ok && !new_name.isEmpty() ) { c->setName( new_name ); - update(); + m_nameLabel->setText( new_name ); } }