diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 46f7418eb..ec1bdefc4 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -114,6 +114,7 @@ set( libSources playlist/dynamic/widgets/ReadOrWriteWidget.cpp playlist/dynamic/widgets/MiscControlWidgets.cpp playlist/dynamic/widgets/CollapsibleControls.cpp + playlist/dynamic/widgets/DynamicSetupWidget.cpp network/bufferiodevice.cpp network/msgprocessor.cpp @@ -257,6 +258,7 @@ set( libHeaders playlist/dynamic/widgets/ReadOrWriteWidget.h playlist/dynamic/widgets/MiscControlWidgets.h playlist/dynamic/widgets/CollapsibleControls.h + playlist/dynamic/widgets/DynamicSetupWidget.h utils/tomahawkutils.h utils/querylabel.h diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp index 978eeaf6a..8507bc797 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include using namespace Tomahawk; @@ -107,6 +109,11 @@ EchonestSteerer::EchonestSteerer( QWidget* parent ) connect( &m_resizeAnim, SIGNAL( frameChanged( int ) ), this, SLOT( resizeFrame( int ) ) ); + + m_fadeAnim = new QPropertyAnimation( this, "opacity", this ); + m_fadeAnim->setDuration( ANIM_DURATION ); + m_fadeAnim->setStartValue( 0 ); + m_fadeAnim->setStartValue( 100 ); resize( sizeHint() ); } @@ -115,23 +122,37 @@ EchonestSteerer::paintEvent( QPaintEvent* ) { QPainter p( this ); QRect r = contentsRect(); + QPalette pal = palette(); - p.setBackgroundMode( Qt::TransparentMode ); - p.setRenderHint( QPainter::Antialiasing ); - p.setOpacity( 0.7 ); - - QPen pen( palette().dark().color(), .5 ); - p.setPen( pen ); - p.setBrush( palette().highlight() ); - - p.drawRoundedRect( r, 10, 10 ); - - p.setOpacity( .95 ); - p.setBrush( QBrush() ); - p.setPen( pen ); - p.drawRoundedRect( r, 10, 10 ); + DynamicWidget::paintRoundedFilledRect( p, pal, r, m_opacity ); } +void +EchonestSteerer::setOpacity( qreal opacity ) +{ + m_opacity = opacity / 100.0; + if( m_opacity == 1 ) + show(); + else if( m_opacity == 0 ) + hide(); + repaint(); +} + +void +EchonestSteerer::fadeIn() +{ + m_fadeAnim->setDirection( QAbstractAnimation::Forward ); + m_fadeAnim->start(); +} + +void +EchonestSteerer::fadeOut() +{ + m_fadeAnim->setDirection( QAbstractAnimation::Backward ); + m_fadeAnim->start(); +} + + void EchonestSteerer::changed() { @@ -191,7 +212,7 @@ EchonestSteerer::resizeFrame( int width ) { // qDebug() << "RESIZING TO:" << width; resize( width, sizeHint().height() ); - update(); + repaint(); emit resized(); } diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.h b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.h index 70a562657..c1a0400bd 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.h +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.h @@ -20,6 +20,7 @@ #include #include +class QPropertyAnimation; class QToolButton; class QLabel; class QComboBox; @@ -33,6 +34,7 @@ namespace Tomahawk class EchonestSteerer : public QWidget { Q_OBJECT + Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity ) public: EchonestSteerer( QWidget* parent = 0 ); @@ -42,6 +44,10 @@ public: public slots: void resetSteering( bool automatic = false ); + void fadeIn(); + void fadeOut(); + qreal opacity() const { return m_opacity; } + void setOpacity( qreal opacity ); signals: void steerField( const QString& field ); void steerDescription( const QString& desc ); @@ -74,6 +80,9 @@ private: // animations QTimeLine m_resizeAnim; bool m_expanding; + + QPropertyAnimation* m_fadeAnim; + qreal m_opacity; }; }; diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp new file mode 100644 index 000000000..b589dee4e --- /dev/null +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp @@ -0,0 +1,147 @@ +/**************************************************************************************** + * Copyright (c) 2010-2011 Leo Franchi * + * * + * 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. If not, see . * + ****************************************************************************************/ + +#include "DynamicSetupWidget.h" + +#include "ReadOrWriteWidget.h" +#include "playlist/dynamic/DynamicPlaylist.h" +#include "playlist/dynamic/GeneratorFactory.h" +#include "DynamicWidget.h" +#include "source.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Tomahawk; + + +DynamicSetupWidget::DynamicSetupWidget( const Tomahawk::dynplaylist_ptr& playlist, QWidget* parent ) + : QWidget( parent ) + , m_playlist( playlist ) + , m_headerText( 0 ) + , m_layout( new QHBoxLayout ) + , m_generatorCombo( 0 ) + , m_logo( 0 ) + , m_generateButton( 0 ) + , m_genNumber( 0 ) +{ + + setContentsMargins( 0, 0, 0, 0 ); + m_headerText = new QLabel( tr( "Type:" ), this ); + m_layout->addWidget( m_headerText ); + + QComboBox * genCombo = new QComboBox( this ); + foreach( const QString& type, GeneratorFactory::types() ) + genCombo->addItem( type ); + m_generatorCombo = new ReadOrWriteWidget( genCombo, m_playlist->author()->isLocal(), this ); + m_layout->addWidget( m_generatorCombo ); + + m_generateButton = new QPushButton( tr( "Generate" ), this ); + m_generateButton->setAttribute( Qt::WA_LayoutUsesWidgetRect ); + connect( m_generateButton, SIGNAL( clicked( bool ) ), this, SLOT( generatePressed( bool ) ) ); + if( m_playlist->mode() == OnDemand ) + m_generateButton->hide(); + else + m_layout->addWidget( m_generateButton ); + + + m_genNumber = new QSpinBox( this ); + m_genNumber->setValue( 15 ); + m_genNumber->setMinimum( 0 ); + if( m_playlist->mode() == OnDemand ) + m_genNumber->hide(); + else + m_layout->addWidget( m_genNumber ); + + m_layout->addSpacing( 30 ); + + m_logo = new QLabel( this ); + if( !m_playlist->generator()->logo().isNull() ) { + QPixmap p = m_playlist->generator()->logo().scaledToHeight( 22, Qt::SmoothTransformation ); + m_logo->setPixmap( p ); + } + m_layout->addWidget(m_logo); + + setLayout( m_layout ); + + m_fadeAnim = new QPropertyAnimation( this, "opacity" ); + m_fadeAnim->setDuration( 500 ); + m_fadeAnim->setStartValue( 0.00 ); + m_fadeAnim->setEndValue( 1.0 ); + + setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + resize( sizeHint() ); +} + +DynamicSetupWidget::~DynamicSetupWidget() +{ + +} + +void +DynamicSetupWidget::setPlaylist( const Tomahawk::dynplaylist_ptr& playlist ) +{ + +} + +void +DynamicSetupWidget::fadeIn() +{ + m_fadeAnim->setDirection( QAbstractAnimation::Forward ); + m_fadeAnim->start(); +} + +void +DynamicSetupWidget::fadeOut() +{ + m_fadeAnim->setDirection( QAbstractAnimation::Forward ); + m_fadeAnim->start(); +} + +void +DynamicSetupWidget::generatePressed( bool ) +{ + emit generatePressed( m_genNumber->value() ); +} + +void +DynamicSetupWidget::setOpacity( qreal opacity ) +{ + m_opacity = opacity; + if( m_opacity == 0 ) + hide(); + else if( m_opacity == 1 ) + show(); + repaint(); +} + +void +DynamicSetupWidget::paintEvent( QPaintEvent* e ) +{ + QPainter p( this ); + QRect r = contentsRect(); + QPalette pal = palette(); + + DynamicWidget::paintRoundedFilledRect( p, pal, r, m_opacity ); + + QWidget::paintEvent( e ); +} diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.h b/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.h new file mode 100644 index 000000000..4d475f8a8 --- /dev/null +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.h @@ -0,0 +1,78 @@ +/**************************************************************************************** + * Copyright (c) 2010-2011 Leo Franchi * + * * + * 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. If not, see . * + ****************************************************************************************/ + +#ifndef DYNAMIC_SETUP_WIDGET_H +#define DYNAMIC_SETUP_WIDGET_H + +#include +#include + +class QPropertyAnimation; +class QPaintEvent; +class QHBoxLayout; +class QSpinBox; +class QPushButton; +class QLabel; +class ReadOrWriteWidget; +class QLabel; + +namespace Tomahawk +{ + +/** + * Widget used to choose a type of dynamic playlist, and to set the number/generate if it's a static one. + */ +class DynamicSetupWidget : public QWidget +{ + Q_OBJECT + Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity ) +public: + DynamicSetupWidget( const Tomahawk::dynplaylist_ptr& playlist, QWidget* parent = 0 ); + virtual ~DynamicSetupWidget(); + + void setPlaylist( const dynplaylist_ptr& playlist ); + + void fadeIn(); + void fadeOut(); + + qreal opacity() const { return m_opacity; } + void setOpacity( qreal opacity ); + + virtual void paintEvent( QPaintEvent* ); +signals: + void generatePressed( int num ); + void typeChanged( const QString& playlistType ); + +private slots: + void generatePressed( bool ); + +private: + dynplaylist_ptr m_playlist; + + QLabel* m_headerText; + QHBoxLayout* m_layout; + ReadOrWriteWidget* m_generatorCombo; + QLabel* m_logo; + QPushButton* m_generateButton; + QSpinBox* m_genNumber; + + QPropertyAnimation* m_fadeAnim; + qreal m_opacity; +}; + +}; + +#endif diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp index d9787e3d5..5a0a0e27b 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp @@ -34,6 +34,8 @@ #include "DynamicControlWrapper.h" #include "dynamic/DynamicView.h" #include +#include "DynamicSetupWidget.h" +#include using namespace Tomahawk; @@ -42,6 +44,7 @@ DynamicWidget::DynamicWidget( const Tomahawk::dynplaylist_ptr& playlist, QWidget , m_layout( new QVBoxLayout ) , m_resolveOnNextLoad( false ) , m_seqRevLaunched( 0 ) + , m_setup( 0 ) , m_runningOnDemand( false ) , m_controlsChanged( false ) , m_steering( 0 ) @@ -66,7 +69,7 @@ DynamicWidget::DynamicWidget( const Tomahawk::dynplaylist_ptr& playlist, QWidget m_generateButton = new QPushButton( tr( "Generate" ), this ); m_generateButton->setAttribute( Qt::WA_LayoutUsesWidgetRect ); - connect( m_generateButton, SIGNAL( clicked( bool ) ), this, SLOT( generateOrStart() ) ); + connect( m_generateButton, SIGNAL( clicked( bool ) ), this, SLOT( generate() ) ); m_headerLayout->addWidget( m_generateButton ); m_headerLayout->addStretch( 1 ); @@ -83,8 +86,6 @@ DynamicWidget::DynamicWidget( const Tomahawk::dynplaylist_ptr& playlist, QWidget } m_headerLayout->addWidget(m_logo); - m_layout->addLayout( m_headerLayout ); - m_controls = new CollapsibleControls( this ); m_layout->addWidget( m_controls ); @@ -96,6 +97,25 @@ DynamicWidget::DynamicWidget( const Tomahawk::dynplaylist_ptr& playlist, QWidget connect( m_model, SIGNAL( collapseFromTo( int, int ) ), m_view, SLOT( collapseEntries( int, int ) ), Qt::QueuedConnection ); connect( m_model, SIGNAL( trackGenerationFailure( QString ) ), m_view, SLOT( showMessage( QString ) ) ); + + + m_setup = new DynamicSetupWidget( playlist, this ); + if( playlist->mode() == Static ) { + m_setup->hide(); + + m_layout->addLayout( m_headerLayout ); + } else { + m_setup->fadeIn(); + + // hide the widgets, removing them from layout + // TODO HACK these need to go away, need a good UI design + m_headerText->hide(); + m_generatorCombo->hide(); + m_generateButton->hide(); + m_genNumber->hide(); + m_logo->hide(); + } + loadDynamicPlaylist( playlist ); m_layout->setContentsMargins( 0, 0, 0, 0 ); @@ -103,6 +123,12 @@ DynamicWidget::DynamicWidget( const Tomahawk::dynplaylist_ptr& playlist, QWidget m_layout->setSpacing( 0 ); setLayout( m_layout ); + + connect( m_setup, SIGNAL( generatePressed( int ) ), this, SLOT( generate( int ) ) ); + connect( m_setup, SIGNAL( typeChanged( QString ) ), this, SLOT( playlistTypeChanged( QString ) ) ); + + layoutFloatingWidgets(); + connect( m_controls, SIGNAL( controlChanged( Tomahawk::dyncontrol_ptr ) ), this, SLOT( controlChanged( Tomahawk::dyncontrol_ptr ) ), Qt::QueuedConnection ); connect( m_controls, SIGNAL( controlsChanged() ), this, SLOT( controlsChanged() ), Qt::QueuedConnection ); } @@ -147,15 +173,36 @@ DynamicWidget::loadDynamicPlaylist( const Tomahawk::dynplaylist_ptr& playlist ) disconnect( m_playlist->generator().data(), SIGNAL( error( QString, QString ) ), this, SLOT( generatorError( QString, QString ) ) ); } + if( m_playlist.isNull() || m_playlist->mode() != playlist->mode() ) { // update our ui with the appropriate controls + if( playlist->mode() == Static ) { + m_setup->hide(); + + m_layout->insertLayout( 0, m_headerLayout ); + } else { + m_setup->fadeIn(); + + // hide the widgets, removing them from layout + // TODO HACK these need to go away, need a good UI design + m_headerText->hide(); + m_generatorCombo->hide(); + m_generateButton->hide(); + m_genNumber->hide(); + m_logo->hide(); + m_layout->removeItem( m_headerLayout ); + } + } + m_playlist = playlist; m_view->setOnDemand( m_playlist->mode() == OnDemand ); m_view->setReadOnly( !m_playlist->author()->isLocal() ); m_model->loadPlaylist( m_playlist ); m_controlsChanged = false; + m_setup->setPlaylist( m_playlist ); if( !m_playlist.isNull() ) m_controls->setControls( m_playlist, m_playlist->author()->isLocal() ); + m_generatorCombo->setWritable( playlist->author()->isLocal() ); m_generatorCombo->setLabel( qobject_cast< QComboBox* >( m_generatorCombo->writableWidget() )->currentText() ); @@ -196,13 +243,18 @@ DynamicWidget::sizeHint() const void DynamicWidget::resizeEvent(QResizeEvent* ) { - layoutSteerer(); + layoutFloatingWidgets(); } void -DynamicWidget::layoutSteerer() +DynamicWidget::layoutFloatingWidgets() { - if( m_runningOnDemand && m_steering ) { + if( m_playlist->mode() == OnDemand && !m_runningOnDemand ) { + int x = ( width() / 2 ) - ( m_setup->size().width() / 2 ); + int y = height() - m_setup->size().height() - 40; // padding + + m_setup->move( x, y ); + } else if( m_runningOnDemand && m_steering ) { int x = ( width() / 2 ) - ( m_steering->size().width() / 2 ); int y = height() - m_steering->size().height() - 40; // padding @@ -214,52 +266,70 @@ void DynamicWidget::hideEvent( QHideEvent* ev ) { if( m_runningOnDemand ) { - generateOrStart(); + stopStation(); } QWidget::hideEvent( ev ); } void -DynamicWidget::generateOrStart() +DynamicWidget::generate( int num ) { if( m_playlist->mode() == Static ) { // get the items from the generator, and put them in the playlist - m_playlist->generator()->generate( m_genNumber->value() ); + m_playlist->generator()->generate( num == -1 ? m_genNumber->value() : num ); // HACK while in transition } else if( m_playlist->mode() == OnDemand ) { - if( m_runningOnDemand == false ) { - m_runningOnDemand = true; - m_model->startOnDemand(); - - m_generateButton->setText( tr( "Stop" ) ); - - - // show the steering controls - if( m_playlist->generator()->onDemandSteerable() ) { - // position it horizontally centered, above the botton. - m_steering = m_playlist->generator()->steeringWidget(); - Q_ASSERT( m_steering ); - - int x = ( width() / 2 ) - ( m_steering->size().width() / 2 ); - int y = height() - m_steering->size().height() - 40; // padding - - m_steering->setParent( this ); - m_steering->move( x, y ); - m_steering->show(); - - connect( m_steering, SIGNAL( resized() ), this, SLOT( layoutSteerer() ) ); - } - } else { // stop - m_model->stopOnDemand(); - m_runningOnDemand = false; - delete m_steering; - m_steering = 0; - m_generateButton->setText( tr( "Start" ) ); - } + } } +void +DynamicWidget::stopStation() +{ + m_model->stopOnDemand(); + m_runningOnDemand = false; + + // TODO until i add a qwidget interface + QMetaObject::invokeMethod( m_steering, SLOT( fadeOut() ), Qt::DirectConnection ); + + m_generateButton->setText( tr( "Start" ) ); +} + +void +DynamicWidget::startStation() +{ + m_runningOnDemand = true; + m_model->startOnDemand(); + + m_generateButton->setText( tr( "Stop" ) ); + + m_setup->fadeOut(); + // show the steering controls + if( m_playlist->generator()->onDemandSteerable() ) { + // position it horizontally centered, above the botton. + m_steering = m_playlist->generator()->steeringWidget(); + Q_ASSERT( m_steering ); + + int x = ( width() / 2 ) - ( m_steering->size().width() / 2 ); + int y = height() - m_steering->size().height() - 40; // padding + + m_steering->setParent( this ); + m_steering->move( x, y ); + + // TODO until i add a qwidget interface + QMetaObject::invokeMethod( m_steering, SLOT( fadeIn() ), Qt::DirectConnection ); + + connect( m_steering, SIGNAL( resized() ), this, SLOT( layoutFloatingWidgets() ) ); + } +} + +void +DynamicWidget::playlistTypeChanged( QString ) +{ + // TODO +} + void DynamicWidget::applyModeChange( int mode ) { @@ -321,5 +391,24 @@ DynamicWidget::generatorError( const QString& title, const QString& content ) m_view->showMessageTimeout( title, content ); if( m_runningOnDemand ) - generateOrStart(); + stopStation(); +} + +void +DynamicWidget::paintRoundedFilledRect( QPainter& p, QPalette& pal, QRect& r, qreal opacity ) +{ + p.setBackgroundMode( Qt::TransparentMode ); + p.setRenderHint( QPainter::Antialiasing ); + p.setOpacity( 0.7 ); + + QPen pen( pal.dark().color(), .5 ); + p.setPen( pen ); + p.setBrush( pal.highlight() ); + + p.drawRoundedRect( r, 10, 10 ); + + p.setOpacity( opacity ); + p.setBrush( QBrush() ); + p.setPen( pen ); + p.drawRoundedRect( r, 10, 10 ); } diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h index f457712ef..bafb136ee 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h @@ -39,6 +39,9 @@ class ReadOrWriteWidget; namespace Tomahawk { +class DynamicSetupWidget; + + class DynamicModel; @@ -65,18 +68,24 @@ public: virtual QSize sizeHint() const; virtual void resizeEvent( QResizeEvent* ); virtual void hideEvent(QHideEvent* ); + + static void paintRoundedFilledRect( QPainter& p, QPalette& pal, QRect& r, qreal opacity = .95 ); public slots: void onRevisionLoaded( const Tomahawk::DynamicPlaylistRevision& rev ); + void playlistTypeChanged(QString); + + void startStation(); + void stopStation(); private slots: - void generateOrStart(); + void generate( int = -1 ); void tracksGenerated( const QList< Tomahawk::query_ptr>& queries ); void generatorError( const QString& title, const QString& content ); void controlsChanged(); void controlChanged( const Tomahawk::dyncontrol_ptr& control ); - void layoutSteerer(); + void layoutFloatingWidgets(); private: void applyModeChange( int mode ); @@ -85,6 +94,9 @@ private: bool m_resolveOnNextLoad; int m_seqRevLaunched; // if we shoot off multiple createRevision calls, we don'y want to set one of the middle ones + // setup controls + DynamicSetupWidget* m_setup; + // used in OnDemand mode bool m_runningOnDemand; bool m_controlsChanged;