[UI] Playqueue: added loop and shuffle
This commit is contained in:
+45
-36
@@ -175,6 +175,8 @@ _playQueue(nullptr)
|
|||||||
_mediaPlayer->playbackEnded().connect(_playQueue, &PlayQueue::handlePlaybackComplete);
|
_mediaPlayer->playbackEnded().connect(_playQueue, &PlayQueue::handlePlaybackComplete);
|
||||||
_mediaPlayer->playNext().connect(_playQueue, &PlayQueue::playNext);
|
_mediaPlayer->playNext().connect(_playQueue, &PlayQueue::playNext);
|
||||||
_mediaPlayer->playPrevious().connect(_playQueue, &PlayQueue::playPrevious);
|
_mediaPlayer->playPrevious().connect(_playQueue, &PlayQueue::playPrevious);
|
||||||
|
_mediaPlayer->shuffle().connect(boost::bind(&PlayQueue::setShuffle, _playQueue, _1));
|
||||||
|
_mediaPlayer->loop().connect(boost::bind(&PlayQueue::setLoop,_playQueue, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -183,42 +185,6 @@ Audio::search(const std::string& searchText)
|
|||||||
_filterChain.searchKeyword(searchText);
|
_filterChain.searchKeyword(searchText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Audio::playSelectedTracks(PlayQueueAddType addType)
|
|
||||||
{
|
|
||||||
int firstTrackPos = 0;
|
|
||||||
std::vector<Database::Track::id_type> trackIds;
|
|
||||||
|
|
||||||
switch(addType)
|
|
||||||
{
|
|
||||||
case PlayQueueAddAllTracks:
|
|
||||||
// Play all the tracks, from the first one
|
|
||||||
firstTrackPos = 0;
|
|
||||||
_trackView->getTracks(trackIds);
|
|
||||||
break;
|
|
||||||
case PlayQueueAddSelectedTracks:
|
|
||||||
// If nothing or only ONE selected, get them all
|
|
||||||
if (_trackView->getNbSelectedTracks() <= 1)
|
|
||||||
{
|
|
||||||
// Start to play at the selected track, if any
|
|
||||||
firstTrackPos = _trackView->getFirstSelectedTrackPosition();
|
|
||||||
_trackView->getTracks(trackIds);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Play all the selected tracks, frm the first one
|
|
||||||
firstTrackPos = 0;
|
|
||||||
_trackView->getSelectedTracks(trackIds);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
_playQueue->clear();
|
|
||||||
_playQueue->addTracks(trackIds);
|
|
||||||
|
|
||||||
_playQueue->play(firstTrackPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Audio::addSelectedTracks(void)
|
Audio::addSelectedTracks(void)
|
||||||
{
|
{
|
||||||
@@ -232,6 +198,49 @@ Audio::addSelectedTracks(void)
|
|||||||
_playQueue->addTracks(trackIds);
|
_playQueue->addTracks(trackIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Audio::playSelectedTracks(PlayQueueAddType addType)
|
||||||
|
{
|
||||||
|
std::vector<Database::Track::id_type> trackIds;
|
||||||
|
|
||||||
|
_playQueue->clear();
|
||||||
|
|
||||||
|
switch(addType)
|
||||||
|
{
|
||||||
|
case PlayQueueAddAllTracks:
|
||||||
|
// Play all the tracks
|
||||||
|
_trackView->getTracks(trackIds);
|
||||||
|
_playQueue->addTracks(trackIds);
|
||||||
|
_playQueue->play();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case PlayQueueAddSelectedTracks:
|
||||||
|
// If nothing selected, get all the track and play everything
|
||||||
|
if (_trackView->getNbSelectedTracks() == 0)
|
||||||
|
{
|
||||||
|
_trackView->getTracks(trackIds);
|
||||||
|
_playQueue->addTracks(trackIds);
|
||||||
|
_playQueue->play();
|
||||||
|
}
|
||||||
|
// If only ONE selected, get them all and pre select the track
|
||||||
|
else if (_trackView->getNbSelectedTracks() == 1)
|
||||||
|
{
|
||||||
|
// Start to play at the selected track, if any
|
||||||
|
_trackView->getTracks(trackIds);
|
||||||
|
_playQueue->addTracks(trackIds);
|
||||||
|
_playQueue->play(_trackView->getFirstSelectedTrackPosition());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Play all the selected tracks
|
||||||
|
_trackView->getSelectedTracks(trackIds);
|
||||||
|
_playQueue->addTracks(trackIds);
|
||||||
|
_playQueue->play();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Audio::playTrack(boost::filesystem::path p)
|
Audio::playTrack(boost::filesystem::path p)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <Wt/WMediaPlayer>
|
#include <Wt/WMediaPlayer>
|
||||||
#include <Wt/WProgressBar>
|
#include <Wt/WProgressBar>
|
||||||
|
#include <Wt/WCheckBox>
|
||||||
|
|
||||||
#include "AudioMediaPlayer.hpp"
|
#include "AudioMediaPlayer.hpp"
|
||||||
|
|
||||||
@@ -39,6 +40,18 @@ AudioMediaPlayer::AudioMediaPlayer( Wt::WContainerWidget *parent)
|
|||||||
{
|
{
|
||||||
Wt::WContainerWidget *container = new Wt::WContainerWidget(this);
|
Wt::WContainerWidget *container = new Wt::WContainerWidget(this);
|
||||||
|
|
||||||
|
Wt::WCheckBox *loop = new Wt::WCheckBox("Loop", this);
|
||||||
|
loop->changed().connect(std::bind([=] ()
|
||||||
|
{
|
||||||
|
_loop.emit( loop->checkState() == Wt::Checked);
|
||||||
|
}));
|
||||||
|
|
||||||
|
Wt::WCheckBox *shuffle = new Wt::WCheckBox("Shuffle", this);
|
||||||
|
shuffle->changed().connect(std::bind([=] ()
|
||||||
|
{
|
||||||
|
_shuffle.emit( shuffle->checkState() == Wt::Checked);
|
||||||
|
}));
|
||||||
|
|
||||||
Wt::WPushButton *prevBtn = new Wt::WPushButton("<<", container );
|
Wt::WPushButton *prevBtn = new Wt::WPushButton("<<", container );
|
||||||
_playBtn = new Wt::WPushButton("Play", container );
|
_playBtn = new Wt::WPushButton("Play", container );
|
||||||
_pauseBtn = new Wt::WPushButton("Pause", container );
|
_pauseBtn = new Wt::WPushButton("Pause", container );
|
||||||
|
|||||||
@@ -42,12 +42,12 @@ class AudioMediaPlayer : public Wt::WContainerWidget
|
|||||||
|
|
||||||
void load(const Transcode::Parameters& parameters);
|
void load(const Transcode::Parameters& parameters);
|
||||||
|
|
||||||
// Signal slot Ended
|
// Signal slots
|
||||||
Wt::Signal<void>& playbackEnded() {return _playbackEnded;}
|
Wt::Signal<void>& playbackEnded() {return _playbackEnded;}
|
||||||
// Signal slot Next
|
|
||||||
Wt::Signal<void>& playNext() {return _playNext;}
|
Wt::Signal<void>& playNext() {return _playNext;}
|
||||||
// Signal Slot Previous
|
|
||||||
Wt::Signal<void>& playPrevious() {return _playPrevious;}
|
Wt::Signal<void>& playPrevious() {return _playPrevious;}
|
||||||
|
Wt::Signal<bool>& shuffle() {return _shuffle;}
|
||||||
|
Wt::Signal<bool>& loop() {return _loop;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -66,6 +66,8 @@ class AudioMediaPlayer : public Wt::WContainerWidget
|
|||||||
Wt::Signal<void> _playbackEnded;
|
Wt::Signal<void> _playbackEnded;
|
||||||
Wt::Signal<void> _playNext;
|
Wt::Signal<void> _playNext;
|
||||||
Wt::Signal<void> _playPrevious;
|
Wt::Signal<void> _playPrevious;
|
||||||
|
Wt::Signal<bool> _shuffle;
|
||||||
|
Wt::Signal<bool> _loop;
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
Wt::WMediaPlayer* _mediaPlayer;
|
Wt::WMediaPlayer* _mediaPlayer;
|
||||||
|
|||||||
+255
-48
@@ -17,6 +17,9 @@
|
|||||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <boost/random/mersenne_twister.hpp>
|
||||||
|
#include <boost/random/uniform_int_distribution.hpp>
|
||||||
|
|
||||||
#include <Wt/WItemDelegate>
|
#include <Wt/WItemDelegate>
|
||||||
|
|
||||||
#include "logger/Logger.hpp"
|
#include "logger/Logger.hpp"
|
||||||
@@ -41,32 +44,184 @@ namespace {
|
|||||||
model->setData(row2, i, tmp); // tmp-> 2
|
model->setData(row2, i, tmp); // tmp-> 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace UserInterface {
|
namespace UserInterface {
|
||||||
|
|
||||||
static const int trackIdInvalid = -1;
|
static const int trackPosInvalid = -1;
|
||||||
|
|
||||||
|
class TrackSelector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TrackSelector();
|
||||||
|
|
||||||
|
void setShuffle(bool enable);
|
||||||
|
void setLoop(bool enable) { _loop = enable; }
|
||||||
|
|
||||||
|
int getPrevious(void);
|
||||||
|
int getNext(void);
|
||||||
|
int getCurrent(void);
|
||||||
|
|
||||||
|
// Set the internal pos thanks to the track pos
|
||||||
|
void setPosByRowId(int rowId);
|
||||||
|
void setPos(int pos) { _curPos = pos; }
|
||||||
|
|
||||||
|
void setSize(std::size_t size);
|
||||||
|
std::size_t getSize(void) const { return _size;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void refreshPositions();
|
||||||
|
|
||||||
|
bool _loop;
|
||||||
|
bool _shuffle;
|
||||||
|
|
||||||
|
std::size_t _size;
|
||||||
|
std::size_t _curPos;
|
||||||
|
|
||||||
|
std::vector<int> _trackPos;
|
||||||
|
};
|
||||||
|
|
||||||
|
TrackSelector::TrackSelector()
|
||||||
|
: _loop(false),
|
||||||
|
_shuffle(false),
|
||||||
|
_curPos(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TrackSelector::refreshPositions()
|
||||||
|
{
|
||||||
|
_trackPos.clear();
|
||||||
|
|
||||||
|
if (_size == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < _size; ++i)
|
||||||
|
_trackPos.push_back(i);
|
||||||
|
|
||||||
|
// Now shuffle
|
||||||
|
// Perform size/2 permutations
|
||||||
|
boost::random::mt19937 rng; // produces randomness out of thin air
|
||||||
|
rng.seed(static_cast<unsigned int>(std::time(0)));
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < _size; ++i)
|
||||||
|
{
|
||||||
|
boost::random::uniform_int_distribution<> distribution(i, _size - 1);
|
||||||
|
int val1 = distribution(rng);
|
||||||
|
int tmp = _trackPos[i];
|
||||||
|
_trackPos[i] = _trackPos[val1];
|
||||||
|
_trackPos[val1] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
TrackSelector::getCurrent()
|
||||||
|
{
|
||||||
|
return _shuffle ? _trackPos[_curPos] : _curPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TrackSelector::setShuffle(bool enable)
|
||||||
|
{
|
||||||
|
_shuffle = enable;
|
||||||
|
|
||||||
|
if (_shuffle)
|
||||||
|
setPosByRowId(_curPos);
|
||||||
|
else
|
||||||
|
setPos(_trackPos[_curPos]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
TrackSelector::getNext()
|
||||||
|
{
|
||||||
|
if (_size == 0)
|
||||||
|
return trackPosInvalid;
|
||||||
|
|
||||||
|
if (_curPos == _size - 1)
|
||||||
|
{
|
||||||
|
if (!_loop)
|
||||||
|
return trackPosInvalid;
|
||||||
|
else
|
||||||
|
_curPos = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++_curPos;
|
||||||
|
|
||||||
|
return _shuffle ? _trackPos[_curPos] : _curPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
TrackSelector::getPrevious()
|
||||||
|
{
|
||||||
|
if (_size == 0)
|
||||||
|
return trackPosInvalid;
|
||||||
|
|
||||||
|
if (_curPos == 0)
|
||||||
|
{
|
||||||
|
if (!_loop)
|
||||||
|
return trackPosInvalid;
|
||||||
|
else
|
||||||
|
_curPos = _size - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
--_curPos;
|
||||||
|
|
||||||
|
return _shuffle ? _trackPos[_curPos] : _curPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TrackSelector::setPosByRowId(int rowId)
|
||||||
|
{
|
||||||
|
if (_shuffle)
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < _trackPos.size(); ++i)
|
||||||
|
{
|
||||||
|
if (rowId == _trackPos[i])
|
||||||
|
{
|
||||||
|
_curPos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_curPos = rowId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TrackSelector::setSize(std::size_t size)
|
||||||
|
{
|
||||||
|
_size = size;
|
||||||
|
_curPos = 0;
|
||||||
|
refreshPositions();
|
||||||
|
}
|
||||||
|
|
||||||
class PlayQueueItemDelegate : public Wt::WItemDelegate
|
class PlayQueueItemDelegate : public Wt::WItemDelegate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PlayQueueItemDelegate(Wt::WObject *parent = 0) : Wt::WItemDelegate(parent), _selectedRowId(trackIdInvalid) {}
|
PlayQueueItemDelegate(Wt::WObject *parent = 0) : Wt::WItemDelegate(parent), _selectedRowPos(trackPosInvalid) {}
|
||||||
|
|
||||||
void setSelectedRowId(int rowId) { _selectedRowId = rowId; }
|
void setSelectedRowPos(int rowPos) { _selectedRowPos = rowPos; }
|
||||||
|
|
||||||
Wt::WWidget* update(Wt::WWidget *widget, const Wt::WModelIndex &index, Wt::WFlags< Wt::ViewItemRenderFlag > flags)
|
Wt::WWidget* update(Wt::WWidget *widget, const Wt::WModelIndex &index, Wt::WFlags< Wt::ViewItemRenderFlag > flags)
|
||||||
{
|
{
|
||||||
Wt::WWidget* res = Wt::WItemDelegate::update(widget, index, flags);
|
Wt::WWidget* res = Wt::WItemDelegate::update(widget, index, flags);
|
||||||
|
|
||||||
if (res && index.isValid() && index.row() == _selectedRowId)
|
if (res && index.isValid())
|
||||||
res->toggleStyleClass("playqueue-playing", true);
|
{
|
||||||
|
if (_selectedRowPos != trackPosInvalid && index.row() == _selectedRowPos)
|
||||||
|
res->toggleStyleClass("playqueue-playing", true);
|
||||||
|
else
|
||||||
|
res->toggleStyleClass("playqueue-playing", false);
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
int _selectedRowId;
|
int _selectedRowPos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -74,7 +229,8 @@ class PlayQueueItemDelegate : public Wt::WItemDelegate
|
|||||||
PlayQueue::PlayQueue(Database::Handler& db, Wt::WContainerWidget* parent)
|
PlayQueue::PlayQueue(Database::Handler& db, Wt::WContainerWidget* parent)
|
||||||
: Wt::WTableView(parent),
|
: Wt::WTableView(parent),
|
||||||
_db(db),
|
_db(db),
|
||||||
_playedId(trackIdInvalid)
|
_curPlayedTrackPos(trackPosInvalid),
|
||||||
|
_trackSelector(new TrackSelector())
|
||||||
{
|
{
|
||||||
_model = new Wt::WStandardItemModel(0, 4, this);
|
_model = new Wt::WStandardItemModel(0, 4, this);
|
||||||
|
|
||||||
@@ -109,16 +265,41 @@ _playedId(trackIdInvalid)
|
|||||||
this->setSelectedIndexes( indexSet );
|
this->setSelectedIndexes( indexSet );
|
||||||
|
|
||||||
// Read the requested track
|
// Read the requested track
|
||||||
readTrack(idx.row());
|
play(idx.row());
|
||||||
|
|
||||||
}, std::placeholders::_1, std::placeholders::_2));
|
}, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PlayQueue::play(int trackId)
|
PlayQueue::setShuffle(bool enable)
|
||||||
{
|
{
|
||||||
readTrack(trackId);
|
_trackSelector->setShuffle(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PlayQueue::setLoop(bool enable)
|
||||||
|
{
|
||||||
|
_trackSelector->setLoop(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PlayQueue::play()
|
||||||
|
{
|
||||||
|
_trackSelector->setPos(0);
|
||||||
|
|
||||||
|
if (!readTrack(_trackSelector->getCurrent()))
|
||||||
|
playNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PlayQueue::play(int rowId)
|
||||||
|
{
|
||||||
|
// Update the track selector to use the requested track as current position
|
||||||
|
_trackSelector->setPosByRowId(rowId);
|
||||||
|
|
||||||
|
if (!readTrack(_trackSelector->getCurrent()))
|
||||||
|
playNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -143,6 +324,8 @@ PlayQueue::addTracks(const std::vector<Database::Track::id_type>& trackIds)
|
|||||||
_model->setData(dataRow, 3, track->getDuration());
|
_model->setData(dataRow, 3, track->getDuration());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_trackSelector->setSize( _model->rowCount() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -151,68 +334,88 @@ PlayQueue::clear(void)
|
|||||||
_model->removeRows(0, _model->rowCount());
|
_model->removeRows(0, _model->rowCount());
|
||||||
|
|
||||||
// Reset play id
|
// Reset play id
|
||||||
_playedId = trackIdInvalid;
|
_curPlayedTrackPos = trackPosInvalid;
|
||||||
|
_trackSelector->setSize( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PlayQueue::handlePlaybackComplete(void)
|
PlayQueue::handlePlaybackComplete(void)
|
||||||
{
|
{
|
||||||
// Play the next track
|
playNext();
|
||||||
if (_playedId != trackIdInvalid)
|
|
||||||
readTrack(_playedId + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PlayQueue::playNext(void)
|
PlayQueue::playNext(void)
|
||||||
{
|
{
|
||||||
readTrack( _playedId != trackIdInvalid ? _playedId + 1 : 0);
|
std::size_t nbTries = _trackSelector->getSize();
|
||||||
|
|
||||||
|
while (nbTries > 0)
|
||||||
|
{
|
||||||
|
int pos = _trackSelector->getNext();
|
||||||
|
if (pos == trackPosInvalid)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (readTrack(pos))
|
||||||
|
break;
|
||||||
|
|
||||||
|
--nbTries;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PlayQueue::playPrevious(void)
|
PlayQueue::playPrevious(void)
|
||||||
{
|
{
|
||||||
readTrack( _playedId >= 1 ? _playedId - 1 : 0);
|
std::size_t nbTries = _trackSelector->getSize();
|
||||||
|
|
||||||
|
while (nbTries > 0)
|
||||||
|
{
|
||||||
|
int pos = _trackSelector->getPrevious();
|
||||||
|
if (pos == trackPosInvalid)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (readTrack(pos))
|
||||||
|
break;
|
||||||
|
|
||||||
|
--nbTries;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
PlayQueue::readTrack(int rowId)
|
PlayQueue::readTrack(int rowPos)
|
||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||||
|
|
||||||
while (rowId < _model->rowCount())
|
LMS_LOG(MOD_UI, SEV_DEBUG) << "Reading track at pos " << rowPos;
|
||||||
|
Database::Track::id_type trackId = boost::any_cast<Database::Track::id_type>(_model->data(rowPos, 0));
|
||||||
|
|
||||||
|
Database::Track::pointer track = Database::Track::getById(_db.getSession(), trackId);
|
||||||
|
if (track)
|
||||||
{
|
{
|
||||||
Database::Track::id_type trackId = boost::any_cast<Database::Track::id_type>(_model->data(rowId, 0));
|
setPlayingTrackPos(rowPos);
|
||||||
|
|
||||||
Database::Track::pointer track = Database::Track::getById(_db.getSession(), trackId);
|
_sigTrackPlay.emit(track->getPath());
|
||||||
if (track)
|
|
||||||
{
|
|
||||||
setPlayingTrackId(rowId);
|
|
||||||
|
|
||||||
_sigTrackPlay.emit(track->getPath());
|
return true;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++rowId;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PlayQueue::setPlayingTrackId(int newRowId)
|
PlayQueue::setPlayingTrackPos(int newRowPos)
|
||||||
{
|
{
|
||||||
int oldRowId = _playedId;
|
int oldRowPos = _curPlayedTrackPos;
|
||||||
_playedId = newRowId;
|
_curPlayedTrackPos = newRowPos;
|
||||||
|
|
||||||
_itemDelegate->setSelectedRowId(newRowId);
|
_itemDelegate->setSelectedRowPos(newRowPos);
|
||||||
|
|
||||||
// Hack re-set the data in order to trigger the rerending of the widget
|
// Hack re-set the data in order to trigger the rerending of the widget
|
||||||
// calling the update method of our custom item delegate gives bad results
|
// calling the update method of our custom item delegate gives bad results
|
||||||
if (oldRowId >= 0)
|
if (oldRowPos >= 0)
|
||||||
modelForceRefreshDataRow(_model, oldRowId);
|
modelForceRefreshDataRow(_model, oldRowPos);
|
||||||
|
|
||||||
if (newRowId >= 0)
|
if (newRowPos >= 0)
|
||||||
modelForceRefreshDataRow(_model, newRowId);
|
modelForceRefreshDataRow(_model, newRowPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -229,9 +432,11 @@ PlayQueue::delSelected(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the current played track is removed, make sure to unselect it
|
// If the current played track is removed, make sure to unselect it
|
||||||
_itemDelegate->setSelectedRowId(trackIdInvalid);
|
_itemDelegate->setSelectedRowPos(trackPosInvalid);
|
||||||
|
_trackSelector->setSize(_model->rowCount());
|
||||||
|
|
||||||
renumber(minId, _model->rowCount() - 1);
|
renumber(minId, _model->rowCount() - 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -260,14 +465,15 @@ PlayQueue::moveSelectedUp(void)
|
|||||||
maxId = index.row();
|
maxId = index.row();
|
||||||
|
|
||||||
// Update playing status
|
// Update playing status
|
||||||
if (_playedId == index.row())
|
if (_curPlayedTrackPos == index.row())
|
||||||
setPlayingTrackId(_playedId - 1);
|
setPlayingTrackPos(_curPlayedTrackPos - 1);
|
||||||
else if (_playedId == index.row() - 1)
|
else if (_curPlayedTrackPos == index.row() - 1)
|
||||||
setPlayingTrackId(_playedId + 1);
|
setPlayingTrackPos(_curPlayedTrackPos + 1);
|
||||||
|
|
||||||
newIndexSet.insert( _model->index(index.row() - 1, 0));
|
newIndexSet.insert( _model->index(index.row() - 1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_trackSelector->setPosByRowId(_curPlayedTrackPos);
|
||||||
this->setSelectedIndexes( newIndexSet );
|
this->setSelectedIndexes( newIndexSet );
|
||||||
|
|
||||||
renumber(minId, maxId);
|
renumber(minId, maxId);
|
||||||
@@ -300,14 +506,15 @@ PlayQueue::moveSelectedDown(void)
|
|||||||
maxId = index.row() + 1;
|
maxId = index.row() + 1;
|
||||||
|
|
||||||
// Update playing status
|
// Update playing status
|
||||||
if (_playedId == index.row())
|
if (_curPlayedTrackPos == index.row())
|
||||||
setPlayingTrackId(_playedId + 1);
|
setPlayingTrackPos(_curPlayedTrackPos + 1);
|
||||||
else if (_playedId == index.row() + 1)
|
else if (_curPlayedTrackPos == index.row() + 1)
|
||||||
setPlayingTrackId(_playedId - 1);
|
setPlayingTrackPos(_curPlayedTrackPos - 1);
|
||||||
|
|
||||||
newIndexSet.insert( _model->index(index.row() + 1, 0));
|
newIndexSet.insert( _model->index(index.row() + 1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_trackSelector->setPosByRowId(_curPlayedTrackPos);
|
||||||
this->setSelectedIndexes( newIndexSet );
|
this->setSelectedIndexes( newIndexSet );
|
||||||
|
|
||||||
renumber(minId, maxId);
|
renumber(minId, maxId);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
namespace UserInterface {
|
namespace UserInterface {
|
||||||
|
|
||||||
class PlayQueueItemDelegate;
|
class PlayQueueItemDelegate;
|
||||||
|
class TrackSelector;
|
||||||
|
|
||||||
class PlayQueue : public Wt::WTableView
|
class PlayQueue : public Wt::WTableView
|
||||||
{
|
{
|
||||||
@@ -39,8 +40,12 @@ class PlayQueue : public Wt::WTableView
|
|||||||
|
|
||||||
void clear(void);
|
void clear(void);
|
||||||
|
|
||||||
|
void setShuffle(bool enable); // true to enable shuffle
|
||||||
|
void setLoop(bool enable); // true to enable loop
|
||||||
|
|
||||||
// Play functions
|
// Play functions
|
||||||
void play(int trackId = 0); // Play the queue
|
void play(void); // Play the queue from the beginning
|
||||||
|
void play(int rowId); // Play the queue from the given rowId
|
||||||
void playNext(void); // Play the next track
|
void playNext(void); // Play the next track
|
||||||
void playPrevious(void); // Play the previous track
|
void playPrevious(void); // Play the previous track
|
||||||
|
|
||||||
@@ -59,8 +64,8 @@ class PlayQueue : public Wt::WTableView
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void readTrack(int rowId);
|
bool readTrack(int rowId);
|
||||||
void setPlayingTrackId(int newRowId);
|
void setPlayingTrackPos(int newRowPos);
|
||||||
void renumber(int firstId, int lastId);
|
void renumber(int firstId, int lastId);
|
||||||
|
|
||||||
Wt::Signal< boost::filesystem::path > _sigTrackPlay;
|
Wt::Signal< boost::filesystem::path > _sigTrackPlay;
|
||||||
@@ -71,7 +76,8 @@ class PlayQueue : public Wt::WTableView
|
|||||||
|
|
||||||
PlayQueueItemDelegate* _itemDelegate;
|
PlayQueueItemDelegate* _itemDelegate;
|
||||||
|
|
||||||
int _playedId;
|
int _curPlayedTrackPos;
|
||||||
|
std::unique_ptr<TrackSelector> _trackSelector;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user