mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-17 11:30:49 +02:00
more work on the new station view
This commit is contained in:
122
data/qml/CoverImage.qml
Normal file
122
data/qml/CoverImage.qml
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
import QtQuick 1.1
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
// Labels & Cover
|
||||||
|
property string artistName
|
||||||
|
property string trackName
|
||||||
|
property string artworkId
|
||||||
|
|
||||||
|
// The border color for the cover image
|
||||||
|
property color borderColor: "black"
|
||||||
|
// The border width for the cover image
|
||||||
|
property int borderWidth: 2
|
||||||
|
|
||||||
|
// needed to adjust the shadow
|
||||||
|
property color backgroundColor: "black"
|
||||||
|
|
||||||
|
// sets the brightness for the item and its mirror (1: brightest, 0: darkest)
|
||||||
|
property double itemBrightness: 1
|
||||||
|
property double mirrorBrightness: .5
|
||||||
|
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: print("cover clicked")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: coverImage
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
color: "white"
|
||||||
|
border.color: borderColor
|
||||||
|
border.width: borderWidth
|
||||||
|
|
||||||
|
Image {
|
||||||
|
anchors.fill: parent
|
||||||
|
//anchors.margins: borderWidth
|
||||||
|
source: "image://albumart/" + artworkId
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: textBackground
|
||||||
|
anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
|
||||||
|
height: 32
|
||||||
|
anchors.margins: 5
|
||||||
|
color: "black"
|
||||||
|
opacity: 0.5
|
||||||
|
radius: 3
|
||||||
|
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
color: "white"
|
||||||
|
font.bold: true
|
||||||
|
text: trackName
|
||||||
|
anchors { left: textBackground.left; right: textBackground.right; top: textBackground.top }
|
||||||
|
anchors.margins: 2
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
color: "white"
|
||||||
|
text: artistName
|
||||||
|
anchors { left: textBackground.left; right: textBackground.right; bottom: textBackground.bottom }
|
||||||
|
anchors.margins: 2
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Loader {
|
||||||
|
sourceComponent: coverImage
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: mirroredCover
|
||||||
|
sourceComponent: coverImage
|
||||||
|
opacity: parent.mirrorOpacity
|
||||||
|
anchors.fill: parent
|
||||||
|
transform : [
|
||||||
|
Rotation {
|
||||||
|
angle: 180; origin.y: root.height
|
||||||
|
axis.x: 1; axis.y: 0; axis.z: 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: itemShadow
|
||||||
|
color: backgroundColor
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.bottomMargin: - parent.height
|
||||||
|
|
||||||
|
// scaling might be off a pixel... make sure that the shadow is at least as large as the image
|
||||||
|
anchors.leftMargin: -2
|
||||||
|
anchors.rightMargin: -2
|
||||||
|
anchors.topMargin: -2
|
||||||
|
|
||||||
|
opacity: 1 - itemBrightness
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: mirrorShadow
|
||||||
|
color: parent.backgroundColor
|
||||||
|
height: parent.height + 2
|
||||||
|
width: parent.width + 4
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: parent.height
|
||||||
|
|
||||||
|
gradient: Gradient {
|
||||||
|
// TODO: no clue how to get the RGB component of the container rectangle color
|
||||||
|
// For now the Qt.rgba needs to be manually updated to match the backgroundColor
|
||||||
|
GradientStop { position: 0.0; color: Qt.rgba(0, 0, 0, 1-mirrorBrightness) }
|
||||||
|
GradientStop { position: 0.5; color: backgroundColor }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -5,171 +5,118 @@ Rectangle {
|
|||||||
id: scene
|
id: scene
|
||||||
color: "black"
|
color: "black"
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
state: echonestStation.configured ? "list" : "configure"
|
||||||
|
|
||||||
property int coverSize: 230
|
property int coverSize: 230
|
||||||
|
|
||||||
Component {
|
states: [
|
||||||
id: coverImage
|
State {
|
||||||
|
name: "configure" //; when: scene.state === "configure"
|
||||||
|
PropertyChanges { target: coverView; anchors.leftMargin: scene.width + scene.coverSize + 20 }
|
||||||
|
PropertyChanges { target: styleCloud; anchors.leftMargin: 0 }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
Rectangle {
|
transitions: [
|
||||||
height: scene.coverSize
|
Transition {
|
||||||
width: scene.coverSize
|
NumberAnimation {
|
||||||
color: scene.color
|
target: coverView
|
||||||
border.color: scene.color
|
properties: "anchors.leftMargin"; easing.type: Easing.InOutQuad; duration: 500
|
||||||
border.width: 2
|
|
||||||
|
|
||||||
property string artistName
|
|
||||||
property string trackName
|
|
||||||
property string artworkId
|
|
||||||
|
|
||||||
Image {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: parent.border.width
|
|
||||||
source: "image://albumart/" + parent.artworkId
|
|
||||||
}
|
}
|
||||||
|
NumberAnimation {
|
||||||
Rectangle {
|
target: styleCloud
|
||||||
id: textBackground
|
properties: "anchors.leftMargin"; easing.type: Easing.InOutQuad; duration: 500
|
||||||
anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
|
|
||||||
height: 32
|
|
||||||
anchors.margins: 5
|
|
||||||
color: "black"
|
|
||||||
opacity: 0.5
|
|
||||||
radius: 3
|
|
||||||
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
color: "white"
|
|
||||||
font.bold: true
|
|
||||||
text: trackName
|
|
||||||
anchors { left: textBackground.left; right: textBackground.right; top: textBackground.top }
|
|
||||||
anchors.margins: 2
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
color: "white"
|
|
||||||
text: artistName
|
|
||||||
anchors { left: textBackground.left; right: textBackground.right; bottom: textBackground.bottom }
|
|
||||||
anchors.margins: 2
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onClicked: print("cover clicked")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
|
|
||||||
Component {
|
|
||||||
id: mirroredDelegate
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: mirroredItem
|
|
||||||
height: scene.coverSize
|
|
||||||
width: scene.coverSize
|
|
||||||
|
|
||||||
z: x
|
|
||||||
scale: PathView.itemScale
|
|
||||||
|
|
||||||
property double itemOpacity: PathView.itemOpacity
|
|
||||||
property double shadowOp: PathView.shadowOpacity
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: dynamicModel.itemFromIndex( index )
|
|
||||||
onCoverChanged: {
|
|
||||||
// We need to unset and re-set it because QML wouldn't re-query the image if it still has the same url
|
|
||||||
normalCover.item.artworkId = ""
|
|
||||||
mirroredCover.item.artworkId = ""
|
|
||||||
normalCover.item.artworkId = index
|
|
||||||
mirroredCover.item.artworkId = index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Component.onCompleted: print("created delegate for", dynamicModel.itemFromIndex( index ) )
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: normalCover
|
|
||||||
sourceComponent: coverImage
|
|
||||||
opacity: parent.itemOpacity
|
|
||||||
onLoaded: {
|
|
||||||
item.trackName = trackName
|
|
||||||
item.artistName = artistName
|
|
||||||
item.artworkId = index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loader {
|
|
||||||
id: mirroredCover
|
|
||||||
sourceComponent: coverImage
|
|
||||||
opacity: parent.itemOpacity
|
|
||||||
onLoaded: {
|
|
||||||
item.trackName = trackName
|
|
||||||
item.artistName = artistName
|
|
||||||
item.artworkId = index
|
|
||||||
}
|
|
||||||
transform : [
|
|
||||||
Rotation {
|
|
||||||
angle: 180; origin.y: scene.coverSize
|
|
||||||
axis.x: 1; axis.y: 0; axis.z: 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
color: scene.color
|
|
||||||
anchors.fill: parent
|
|
||||||
opacity: mirroredItem.shadowOp
|
|
||||||
}
|
|
||||||
Rectangle {
|
|
||||||
color: scene.color
|
|
||||||
height: scene.coverSize
|
|
||||||
width: scene.coverSize
|
|
||||||
anchors.centerIn: parent
|
|
||||||
anchors.verticalCenterOffset: scene.coverSize
|
|
||||||
gradient: Gradient {
|
|
||||||
// TODO: no clue how to get the RGB component of the container rectangle color
|
|
||||||
// For now the Qt.rgba needs to be manually updated to match scene.color
|
|
||||||
GradientStop { position: 0.0; color: Qt.rgba(0, 0, 0, mirroredItem.shadowOp + ( (1 - mirroredItem.shadowOp) * .4)) }
|
|
||||||
GradientStop { position: 0.5; color: scene.color }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PathView {
|
PathView {
|
||||||
id: view
|
id: coverView
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
highlight: appHighlight
|
|
||||||
|
|
||||||
preferredHighlightBegin: 0.07
|
|
||||||
preferredHighlightEnd: 0.07
|
preferredHighlightBegin: 0.07 // scene.width / 11000
|
||||||
|
preferredHighlightEnd: preferredHighlightBegin
|
||||||
pathItemCount: 4
|
pathItemCount: 4
|
||||||
highlightMoveDuration: 500
|
highlightMoveDuration: 500
|
||||||
|
|
||||||
model: dynamicModel
|
model: dynamicModel
|
||||||
currentIndex: currentlyPlayedIndex
|
currentIndex: currentlyPlayedIndex
|
||||||
|
|
||||||
delegate: mirroredDelegate
|
delegate: CoverImage {
|
||||||
|
height: scene.coverSize
|
||||||
|
width: scene.coverSize
|
||||||
|
|
||||||
|
scale: PathView.itemScale
|
||||||
|
|
||||||
|
artistName: model.artistName
|
||||||
|
trackName: model.trackName
|
||||||
|
artworkId: index
|
||||||
|
|
||||||
|
itemBrightness: PathView.itemBrightness
|
||||||
|
z: x
|
||||||
|
}
|
||||||
|
|
||||||
path: Path {
|
path: Path {
|
||||||
startX: scene.width / 2 + 20
|
startX: coverView.width / 2 + 20
|
||||||
startY: 155
|
startY: 155
|
||||||
|
|
||||||
PathAttribute { name: "itemOpacity"; value: 0 }
|
PathAttribute { name: "itemOpacity"; value: 0 }
|
||||||
PathAttribute { name: "shadowOpacity"; value: 0 }
|
PathAttribute { name: "itemBrightness"; value: 0 }
|
||||||
PathAttribute { name: "itemScale"; value: 1.5 }
|
PathAttribute { name: "itemScale"; value: 1.5 }
|
||||||
PathLine { x: scene.width / 2; y: 150 }
|
PathLine { x: coverView.width / 2; y: 150 }
|
||||||
PathAttribute { name: "itemOpacity"; value: 1 }
|
PathAttribute { name: "itemOpacity"; value: 1 }
|
||||||
PathAttribute { name: "shadowOpacity"; value: 0 }
|
PathAttribute { name: "itemBrightness"; value: 1 }
|
||||||
PathAttribute { name: "itemScale"; value: 1.0 }
|
PathAttribute { name: "itemScale"; value: 1.0 }
|
||||||
PathLine { x: scene.width / 2 - 100; y: 180;}
|
PathLine { x: coverView.width / 2 - 100; y: 180;}
|
||||||
PathAttribute { name: "itemOpacity"; value: 1 }
|
PathAttribute { name: "itemOpacity"; value: 1 }
|
||||||
PathAttribute { name: "shadowOpacity"; value: 0 }
|
PathAttribute { name: "itemBrightness"; value: 1 }
|
||||||
PathAttribute { name: "itemScale"; value: 0.6 }
|
PathAttribute { name: "itemScale"; value: 0.6 }
|
||||||
PathLine { x: 100; y: 100;}
|
PathLine { x: 100; y: 100;}
|
||||||
PathAttribute { name: "itemOpacity"; value: 1 }
|
PathAttribute { name: "itemOpacity"; value: 1 }
|
||||||
PathAttribute { name: "shadowOpacity"; value: 1 }
|
PathAttribute { name: "itemBrighness"; value: 0.4 }
|
||||||
PathAttribute { name: "itemScale"; value: 0.4 }
|
PathAttribute { name: "itemScale"; value: 0.4 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: styleCloud
|
||||||
|
anchors { left: parent.left; top: parent.top; bottom: parent.bottom }
|
||||||
|
anchors.leftMargin: scene.width
|
||||||
|
width: scene.width
|
||||||
|
|
||||||
|
function randomNumber(min, max) {
|
||||||
|
var date = new Date();
|
||||||
|
return Math.floor((max - min) * Math.random(date.getSeconds())) + min
|
||||||
|
}
|
||||||
|
|
||||||
|
Flow {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.width - 100
|
||||||
|
//model: controlModel
|
||||||
|
spacing: 3
|
||||||
|
Repeater {
|
||||||
|
model: generator.styles()
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
width: delegateText.width
|
||||||
|
height: 28
|
||||||
|
Text {
|
||||||
|
id: delegateText
|
||||||
|
color: "white"
|
||||||
|
//text: controlModel.controlAt( index ).summary
|
||||||
|
text: modelData
|
||||||
|
font.pixelSize: styleCloud.randomNumber(11, 28)
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.verticalCenterOffset: styleCloud.randomNumber(0, 15)
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: echonestStation.setMainControl(modelData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -148,5 +148,6 @@
|
|||||||
<file>data/images/scrollbar-horizontal-handle.png</file>
|
<file>data/images/scrollbar-horizontal-handle.png</file>
|
||||||
<file>data/qml/ArtistInfoScene.qml</file>
|
<file>data/qml/ArtistInfoScene.qml</file>
|
||||||
<file>data/qml/StationScene.qml</file>
|
<file>data/qml/StationScene.qml</file>
|
||||||
|
<file>data/qml/CoverImage.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@@ -56,6 +56,7 @@ void
|
|||||||
Tomahawk::GeneratorInterface::addControl( const Tomahawk::dyncontrol_ptr& control )
|
Tomahawk::GeneratorInterface::addControl( const Tomahawk::dyncontrol_ptr& control )
|
||||||
{
|
{
|
||||||
m_controls << control;
|
m_controls << control;
|
||||||
|
emit controlAdded( control );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -77,6 +78,7 @@ void
|
|||||||
Tomahawk::GeneratorInterface::removeControl( const Tomahawk::dyncontrol_ptr& control )
|
Tomahawk::GeneratorInterface::removeControl( const Tomahawk::dyncontrol_ptr& control )
|
||||||
{
|
{
|
||||||
m_controls.removeAll( control );
|
m_controls.removeAll( control );
|
||||||
|
controlRemoved( control );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -59,7 +59,7 @@ public:
|
|||||||
// empty QString means use default
|
// empty QString means use default
|
||||||
/// The generator will keep track of all the controls it creates. No need to tell it about controls
|
/// The generator will keep track of all the controls it creates. No need to tell it about controls
|
||||||
/// you ask it to create
|
/// you ask it to create
|
||||||
virtual dyncontrol_ptr createControl( const QString& type = QString() );
|
Q_INVOKABLE virtual dyncontrol_ptr createControl( const QString& type = QString() );
|
||||||
|
|
||||||
/// A logo to display for this generator, if it has one
|
/// A logo to display for this generator, if it has one
|
||||||
virtual QPixmap logo();
|
virtual QPixmap logo();
|
||||||
@@ -127,6 +127,8 @@ signals:
|
|||||||
void error( const QString& title, const QString& body);
|
void error( const QString& title, const QString& body);
|
||||||
void generated( const QList< Tomahawk::query_ptr>& queries );
|
void generated( const QList< Tomahawk::query_ptr>& queries );
|
||||||
void nextTrackGenerated( const Tomahawk::query_ptr& track );
|
void nextTrackGenerated( const Tomahawk::query_ptr& track );
|
||||||
|
void controlAdded(const dyncontrol_ptr& control);
|
||||||
|
void controlRemoved(const dyncontrol_ptr& control);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString m_type;
|
QString m_type;
|
||||||
|
@@ -150,6 +150,7 @@ dyncontrol_ptr
|
|||||||
EchonestGenerator::createControl( const QString& type )
|
EchonestGenerator::createControl( const QString& type )
|
||||||
{
|
{
|
||||||
m_controls << dyncontrol_ptr( new EchonestControl( type, GeneratorFactory::typeSelectors( m_type ) ) );
|
m_controls << dyncontrol_ptr( new EchonestControl( type, GeneratorFactory::typeSelectors( m_type ) ) );
|
||||||
|
emit controlAdded( m_controls.last() );
|
||||||
return m_controls.last();
|
return m_controls.last();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -71,7 +71,7 @@ public:
|
|||||||
explicit EchonestGenerator( QObject* parent = 0 );
|
explicit EchonestGenerator( QObject* parent = 0 );
|
||||||
virtual ~EchonestGenerator();
|
virtual ~EchonestGenerator();
|
||||||
|
|
||||||
virtual dyncontrol_ptr createControl( const QString& type = QString() );
|
Q_INVOKABLE virtual dyncontrol_ptr createControl( const QString& type = QString() );
|
||||||
virtual QPixmap logo();
|
virtual QPixmap logo();
|
||||||
virtual void generate ( int number = -1 );
|
virtual void generate ( int number = -1 );
|
||||||
virtual void startOnDemand();
|
virtual void startOnDemand();
|
||||||
@@ -80,7 +80,7 @@ public:
|
|||||||
virtual bool onDemandSteerable() const { return true; }
|
virtual bool onDemandSteerable() const { return true; }
|
||||||
virtual QWidget* steeringWidget();
|
virtual QWidget* steeringWidget();
|
||||||
|
|
||||||
static QStringList styles();
|
Q_INVOKABLE static QStringList styles();
|
||||||
static QStringList moods();
|
static QStringList moods();
|
||||||
static QStringList userCatalogs();
|
static QStringList userCatalogs();
|
||||||
static QByteArray catalogId( const QString& collectionId );
|
static QByteArray catalogId( const QString& collectionId );
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
#include "playlist/PlayableProxyModel.h"
|
#include "playlist/PlayableProxyModel.h"
|
||||||
#include "utils/TomahawkUtilsGui.h"
|
#include "utils/TomahawkUtilsGui.h"
|
||||||
#include "dynamic/DynamicModel.h"
|
#include "dynamic/DynamicModel.h"
|
||||||
|
#include "dynamic/echonest/EchonestControl.h"
|
||||||
#include "dynamic/GeneratorInterface.h"
|
#include "dynamic/GeneratorInterface.h"
|
||||||
#include "PlayableItem.h"
|
#include "PlayableItem.h"
|
||||||
#include "Source.h"
|
#include "Source.h"
|
||||||
@@ -30,19 +31,40 @@ DynamicQmlWidget::DynamicQmlWidget( const dynplaylist_ptr& playlist, QWidget* pa
|
|||||||
m_model = new DynamicModel( this );
|
m_model = new DynamicModel( this );
|
||||||
m_proxyModel = new PlayableProxyModel( this );
|
m_proxyModel = new PlayableProxyModel( this );
|
||||||
m_proxyModel->setSourcePlayableModel( m_model );
|
m_proxyModel->setSourcePlayableModel( m_model );
|
||||||
m_proxyModel->setShowOfflineResults( false );
|
m_proxyModel->setShowOfflineResults( true );
|
||||||
|
|
||||||
m_model->loadPlaylist( m_playlist );
|
m_model->loadPlaylist( m_playlist );
|
||||||
m_model->startOnDemand();
|
|
||||||
|
|
||||||
|
// Initially seed the playlist
|
||||||
m_playlist->generator()->generate( 20 );
|
m_playlist->generator()->generate( 20 );
|
||||||
m_playlist->resolve();
|
|
||||||
|
|
||||||
rootContext()->setContextProperty( "dynamicModel", m_proxyModel );
|
qDebug() << "###got" << m_playlist->generator()->controls().size() << "controls";
|
||||||
currentItemChanged( m_model->currentItem() );
|
|
||||||
|
qmlRegisterUncreatableType<EchonestStation>("tomahawk", 1, 0, "EchonestStation", "bla");
|
||||||
|
|
||||||
// TODO: In case QML is used in more places, this should probably be moved to some generic place
|
// TODO: In case QML is used in more places, this should probably be moved to some generic place
|
||||||
qmlRegisterType<PlayableItem>("tomahawk", 1, 0, "PlayableItem");
|
qmlRegisterType<PlayableItem>("tomahawk", 1, 0, "PlayableItem");
|
||||||
|
// qmlRegisterUncreatableType<Tomahawk::DynamicControl>("tomahawk", 1, 0, "DynamicControl", "use generator.createControl() isntead");
|
||||||
|
// qmlRegisterUncreatableType<Tomahawk::EchonestControl>("tomahawk", 1, 0, "EchonestControl", "use Generator.createControl() instead");
|
||||||
|
qmlRegisterUncreatableType<DynamicControl>("tomahawk", 1, 0, "DynamicControl", "use generator.createControl() isntead");
|
||||||
|
qmlRegisterUncreatableType<EchonestControl>("tomahawk", 1, 0, "EchonestControl", "use Generator.createControl() instead");
|
||||||
|
qmlRegisterUncreatableType<GeneratorInterface>("tomahawk", 1, 0, "Generator", "you cannot create it on your own - should be set in context");
|
||||||
|
|
||||||
|
QStringList generatorControls;
|
||||||
|
|
||||||
|
foreach(dyncontrol_ptr control, m_playlist->generator()->controls()) {
|
||||||
|
qDebug() << "**CTRL" << control->summary() << control->input() << control->match() << control->type() << control->selectedType();
|
||||||
|
generatorControls << control->summary();
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlModel *controls = new ControlModel(m_playlist->generator(), this);
|
||||||
|
|
||||||
|
EchonestStation *station = new EchonestStation(m_playlist->generator(), this);
|
||||||
|
rootContext()->setContextProperty( "echonestStation", station);
|
||||||
|
rootContext()->setContextProperty( "controlModel", controls );
|
||||||
|
rootContext()->setContextProperty( "dynamicModel", m_proxyModel );
|
||||||
|
rootContext()->setContextProperty( "generator", m_playlist->generator().data() );
|
||||||
|
currentItemChanged( m_model->currentItem() );
|
||||||
|
|
||||||
setSource( QUrl( "qrc" RESPATH "qml/StationScene.qml" ) );
|
setSource( QUrl( "qrc" RESPATH "qml/StationScene.qml" ) );
|
||||||
|
|
||||||
@@ -127,19 +149,12 @@ void DynamicQmlWidget::currentItemChanged( const QPersistentModelIndex ¤tI
|
|||||||
void
|
void
|
||||||
DynamicQmlWidget::tracksGenerated( const QList< query_ptr >& queries )
|
DynamicQmlWidget::tracksGenerated( const QList< query_ptr >& queries )
|
||||||
{
|
{
|
||||||
int limit = -1; // only limit the "preview" of a station
|
qDebug() << queries.count() << "tracks generated";
|
||||||
// if ( m_playlist->author()->isLocal() && m_playlist->mode() == Static )
|
m_model->tracksGenerated( queries, queries.count() );
|
||||||
// {
|
|
||||||
// m_resolveOnNextLoad = true;
|
|
||||||
// }
|
|
||||||
// else if ( m_playlist->mode() == OnDemand )
|
|
||||||
// {
|
|
||||||
limit = 5;
|
|
||||||
// }
|
|
||||||
|
|
||||||
m_model->tracksGenerated( queries, limit );
|
|
||||||
m_playlist->resolve();
|
m_playlist->resolve();
|
||||||
|
|
||||||
|
// Ok... we have some intial stuff, switch to dynamic mode
|
||||||
|
//m_model->startOnDemand();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicQmlWidget::onRevisionLoaded(DynamicPlaylistRevision)
|
void DynamicQmlWidget::onRevisionLoaded(DynamicPlaylistRevision)
|
||||||
|
@@ -53,6 +53,7 @@ public:
|
|||||||
|
|
||||||
QPixmap requestPixmap( const QString &id, QSize *size, const QSize &requestedSize );
|
QPixmap requestPixmap( const QString &id, QSize *size, const QSize &requestedSize );
|
||||||
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void currentItemChanged( const QPersistentModelIndex ¤tIndex );
|
void currentItemChanged( const QPersistentModelIndex ¤tIndex );
|
||||||
void tracksGenerated( const QList< Tomahawk::query_ptr>& queries );
|
void tracksGenerated( const QList< Tomahawk::query_ptr>& queries );
|
||||||
@@ -64,5 +65,79 @@ private:
|
|||||||
dynplaylist_ptr m_playlist;
|
dynplaylist_ptr m_playlist;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "dynamic/GeneratorInterface.h"
|
||||||
|
|
||||||
|
namespace Tomahawk
|
||||||
|
{
|
||||||
|
class EchonestStation: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(bool configured READ configured NOTIFY configuredChanged)
|
||||||
|
Q_PROPERTY(Tomahawk::DynamicControl* mainControl READ mainControl)
|
||||||
|
|
||||||
|
public:
|
||||||
|
EchonestStation(geninterface_ptr generator, QObject *parent = 0) : QObject(parent), m_generator(generator) {}
|
||||||
|
|
||||||
|
Tomahawk::DynamicControl* mainControl() {
|
||||||
|
foreach(dyncontrol_ptr control, m_generator->controls()) {
|
||||||
|
qDebug() << "got control" << control->selectedType();
|
||||||
|
if(control->selectedType() == "Artist" || control->selectedType() == "Style") {
|
||||||
|
return control.data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool configured() { return mainControl() != 0; }
|
||||||
|
|
||||||
|
Q_INVOKABLE void setMainControl(const QString &type) {
|
||||||
|
dyncontrol_ptr control = m_generator->createControl("echonest");
|
||||||
|
control->setSelectedType("Style");
|
||||||
|
control->setMatch("1");
|
||||||
|
control->setInput(type);
|
||||||
|
qDebug() << "created control" << control->type() << control->selectedType() << control->match();
|
||||||
|
m_generator->generate(20);
|
||||||
|
|
||||||
|
emit configuredChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void configuredChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
geninterface_ptr m_generator;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Tomahawk
|
||||||
|
{
|
||||||
|
|
||||||
|
class ControlModel: public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ControlModel(geninterface_ptr generator, QObject *parent = 0): QAbstractListModel(parent), m_generator(generator) {
|
||||||
|
connect(generator.data(), SIGNAL(controlAdded(const dyncontrol_ptr&)), SLOT(controlAdded()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent) const { return m_generator->controls().size(); }
|
||||||
|
QVariant data(const QModelIndex &index, int role) const {
|
||||||
|
return "blabla";
|
||||||
|
}
|
||||||
|
Q_INVOKABLE Tomahawk::DynamicControl *controlAt( int index ) { qDebug() << "returning" << m_generator->controls().at(index).data(); return m_generator->controls().at(index).data(); }
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void controlAdded() {
|
||||||
|
qDebug() << "control added";
|
||||||
|
beginInsertRows(QModelIndex(), m_generator->controls().size() - 1, m_generator->controls().size() - 1);
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
geninterface_ptr m_generator;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif // DYNAMIC_QML_WIDGET_H
|
#endif // DYNAMIC_QML_WIDGET_H
|
||||||
|
Reference in New Issue
Block a user