1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-13 17:43:59 +02:00

first pass of moving setup for dynamic playlists to hover widget

This commit is contained in:
Leo Franchi
2011-02-10 23:40:13 -05:00
parent 8990037c1b
commit 7fc0dbf48f
7 changed files with 414 additions and 56 deletions

View File

@@ -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

View File

@@ -26,6 +26,8 @@
#include <Playlist.h>
#include <QPainter>
#include <QToolButton>
#include <dynamic/widgets/DynamicWidget.h>
#include <QPropertyAnimation>
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();
}

View File

@@ -20,6 +20,7 @@
#include <QWidget>
#include <QTimeLine>
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;
};
};

View File

@@ -0,0 +1,147 @@
/****************************************************************************************
* Copyright (c) 2010-2011 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "DynamicSetupWidget.h"
#include "ReadOrWriteWidget.h"
#include "playlist/dynamic/DynamicPlaylist.h"
#include "playlist/dynamic/GeneratorFactory.h"
#include "DynamicWidget.h"
#include "source.h"
#include <QHBoxLayout>
#include <QComboBox>
#include <QLabel>
#include <QPushButton>
#include <QSpinBox>
#include <QPropertyAnimation>
#include <QPaintEvent>
#include <QPainter>
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 );
}

View File

@@ -0,0 +1,78 @@
/****************************************************************************************
* Copyright (c) 2010-2011 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef DYNAMIC_SETUP_WIDGET_H
#define DYNAMIC_SETUP_WIDGET_H
#include <QWidget>
#include <typedefs.h>
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

View File

@@ -34,6 +34,8 @@
#include "DynamicControlWrapper.h"
#include "dynamic/DynamicView.h"
#include <qevent.h>
#include "DynamicSetupWidget.h"
#include <QPainter>
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 );
}

View File

@@ -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;