Part of a larger restructure, added MusicPlayer which is the main controller and a structure for the song queue
This commit is contained in:
79
src/Controller/MusicPlayer/MusicPlayer.cpp
Normal file
79
src/Controller/MusicPlayer/MusicPlayer.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "MusicPlayer.h"
|
||||
|
||||
MusicPlayer::~MusicPlayer( ) { }
|
||||
|
||||
void MusicPlayer::PlaySong(Song* song) {
|
||||
songHistory->push(songQueue->Top( ));
|
||||
songQueue->SetTop(song);
|
||||
|
||||
audio.PlaySong(songQueue->Top( )->GetPath( ));
|
||||
}
|
||||
|
||||
void MusicPlayer::NextSong( ) {
|
||||
if (songQueue->IsEmpty( )) {
|
||||
audio.StopMusic( );
|
||||
return;
|
||||
}
|
||||
|
||||
songHistory->push(songQueue->Top( ));
|
||||
songQueue->Next( );
|
||||
|
||||
audio.PlaySong(songQueue->Top( )->GetPath( ));
|
||||
}
|
||||
|
||||
void MusicPlayer::NextSong(Song* song, bool isPrioQueue) {
|
||||
if (songQueue->IsEmpty( )) {
|
||||
audio.StopMusic( );
|
||||
return;
|
||||
}
|
||||
|
||||
songHistory->push(songQueue->Top( ));
|
||||
songQueue->JumpToSong(song, isPrioQueue);
|
||||
|
||||
audio.PlaySong(songQueue->Top( )->GetPath( ));
|
||||
}
|
||||
|
||||
void MusicPlayer::PreviousSong( ) {
|
||||
if (songHistory->isEmpty( ))
|
||||
return;
|
||||
|
||||
songQueue->SetTop(songHistory->top( ));
|
||||
songHistory->pop( );
|
||||
|
||||
audio.PlaySong(songQueue->Top( )->GetPath( ));
|
||||
}
|
||||
|
||||
void MusicPlayer::SkipToTimestamp(unsigned const int& skipTo) {
|
||||
if (audio.IsMusicPlaying( ) == 0) return;
|
||||
|
||||
audio.SetMusicPos(skipTo);
|
||||
}
|
||||
|
||||
int MusicPlayer::GetSongProgression( ) {
|
||||
return audio.IsMusicPlaying( ) == 1 ? audio.GetMusicPos( ) : 0;
|
||||
}
|
||||
|
||||
Song* MusicPlayer::GetCurrentlyPlaying( ) {
|
||||
return songQueue->Top( );
|
||||
}
|
||||
|
||||
//For the PriorityQueue
|
||||
void MusicPlayer::AddSongToQueue(Song* song) {
|
||||
songQueue->AddToPriorityQueue(song);
|
||||
}
|
||||
|
||||
void MusicPlayer::RemoveSongFromQueue(Song* song) {
|
||||
songQueue->RemoveSongFromPriorityQueue(song);
|
||||
}
|
||||
|
||||
void MusicPlayer::MoveSongInQueue(Song* songToMove, Song* otherSong, bool beforeElseAfter) {
|
||||
songQueue->MoveSongInPriorityQueue(songToMove, otherSong, beforeElseAfter);
|
||||
}
|
||||
|
||||
void MusicPlayer::shuffleQueue( ) {
|
||||
shuffle ? songQueue->ShufflePlaylist( ) : songQueue->RestorePlaylist( );
|
||||
}
|
||||
|
||||
void MusicPlayer::setQueueLoop( ) {
|
||||
loop == All ? songQueue->LinkQueue(true) : songQueue->LinkQueue(false);
|
||||
}
|
||||
104
src/Controller/MusicPlayer/MusicPlayer.h
Normal file
104
src/Controller/MusicPlayer/MusicPlayer.h
Normal file
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../core/audio/audio.h"
|
||||
#include "../../core/SongHistory/SongHistory.hpp"
|
||||
#include "../../core/SongQueue/SongQueue.h"
|
||||
#include "../../core/song/song.h"
|
||||
|
||||
enum Loop {
|
||||
None,
|
||||
Once,
|
||||
All
|
||||
};
|
||||
|
||||
class MusicPlayer {
|
||||
public:
|
||||
static MusicPlayer& getInstance( ) {
|
||||
static MusicPlayer instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
private:
|
||||
MusicPlayer( );
|
||||
|
||||
// 0 no shuffle, 1 shuffling
|
||||
int shuffle = 0;
|
||||
// None, Once, All
|
||||
Loop loop = None;
|
||||
// 0 stopped, 1 playing
|
||||
bool playing = 0;
|
||||
|
||||
// Song queue, will be filled with the entire playlist by default
|
||||
SongQueue* songQueue;
|
||||
|
||||
// Contain all played songs
|
||||
SongHistory<Song*>* songHistory;
|
||||
|
||||
Audio& audio = Audio::getInstance( );
|
||||
|
||||
void shuffleQueue( );
|
||||
void setQueueLoop( );
|
||||
|
||||
public:
|
||||
~MusicPlayer( );
|
||||
|
||||
MusicPlayer(MusicPlayer const&) = delete;
|
||||
void operator=(MusicPlayer const&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Will start playing the given song and put itself at the queue top.
|
||||
*
|
||||
* @param song Song that will start playing
|
||||
*/
|
||||
void PlaySong(Song* song);
|
||||
|
||||
/**
|
||||
* @brief Skip the current song and play the next in queue,
|
||||
* if nothing is in queue it will stop playing anything.
|
||||
*
|
||||
*/
|
||||
void NextSong( );
|
||||
|
||||
/**
|
||||
* @brief Jumps the queue to the given song keeping the non altered queue intact
|
||||
*
|
||||
* @param song
|
||||
* @param isPrioQueue If the song is in the prio queue or normal queue
|
||||
*/
|
||||
void NextSong(Song* song, bool isPrioQueue);
|
||||
|
||||
/**
|
||||
* @brief Rewind the currently playing song to the beginning if playtime >= 5 seconds.
|
||||
* Otherwise play the top song in the history stack
|
||||
*
|
||||
*/
|
||||
void PreviousSong( );
|
||||
|
||||
/**
|
||||
* @brief Skip the song to the given timestamp
|
||||
*
|
||||
* @param skipTo time as positive integer
|
||||
*/
|
||||
void SkipToTimestamp(unsigned const int& skipTo);
|
||||
|
||||
/**
|
||||
* @brief Get the current Song progression as an positive integer
|
||||
*
|
||||
* @return int current timestamp
|
||||
*/
|
||||
int GetSongProgression( );
|
||||
|
||||
/**
|
||||
* @brief Get the Currently Playing Song
|
||||
*
|
||||
* @return Song& Song thats currently playing
|
||||
*/
|
||||
Song* GetCurrentlyPlaying( );
|
||||
|
||||
void SetShuffle(bool shuffle) { this->shuffle = shuffle; }
|
||||
void SetLoop(Loop loop) { this->loop = loop; }
|
||||
|
||||
void AddSongToQueue(Song* song);
|
||||
void RemoveSongFromQueue(Song* song);
|
||||
void MoveSongInQueue(Song* songToMove, Song* otherSong, bool beforeElseAfter);
|
||||
};
|
||||
0
src/Controller/Pages/PageController.hpp
Normal file
0
src/Controller/Pages/PageController.hpp
Normal file
@@ -1,46 +0,0 @@
|
||||
#include "MainWindow.h"
|
||||
|
||||
void MainWindow::setupMainWindow( ) {
|
||||
this->setWindowTitle("Crylia Player");
|
||||
this->setWindowIcon(QIcon(":aqua.jpg"));
|
||||
|
||||
QWidget* mw = new QWidget(this);
|
||||
mw->setContentsMargins(10, 10, 10, 10);
|
||||
|
||||
QOverlayout* ol = new QOverlayout(mw);
|
||||
mw->setLayout(ol);
|
||||
|
||||
Pages* p = new Pages(mw);
|
||||
PlaylistPage* pp = new PlaylistPage(mw);
|
||||
PlaylistWidget* pw = new PlaylistWidget(mw);
|
||||
FloatingControls* fc = new FloatingControls(mw, this->path);
|
||||
|
||||
QVBoxLayout* vbox = new QVBoxLayout( );
|
||||
vbox->addWidget(fc, 0, Qt::AlignBottom);
|
||||
|
||||
QHBoxLayout* hbox = new QHBoxLayout( );
|
||||
QVBoxLayout* vbox2 = new QVBoxLayout( );
|
||||
vbox2->addWidget(p);
|
||||
vbox2->addWidget(pw);
|
||||
hbox->addLayout(vbox2);
|
||||
hbox->addWidget(pp);
|
||||
|
||||
hbox->setSpacing(10);
|
||||
vbox2->setSpacing(10);
|
||||
|
||||
ol->addItem(vbox);
|
||||
ol->addItem(hbox);
|
||||
|
||||
this->setCentralWidget(mw);
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) {
|
||||
setupMainWindow( );
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(std::filesystem::path path, QWidget* parent)
|
||||
: QMainWindow(parent), path(path) {
|
||||
setupMainWindow( );
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow( ) { }
|
||||
@@ -1,27 +0,0 @@
|
||||
#include "pages.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QFrame>
|
||||
|
||||
Pages::Pages(QWidget* parent) :QFrame(parent) {
|
||||
|
||||
this->setStyleSheet(R"(
|
||||
background-color: #282828;
|
||||
border-radius: 12px;
|
||||
)");
|
||||
|
||||
this->setFixedSize(300, 180);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
|
||||
PageNavigator* home = new PageNavigator("Home", ":icons/home.svg");
|
||||
PageNavigator* localFiles = new PageNavigator("Local Files", ":icons/home.svg");
|
||||
PageNavigator* playlist = new PageNavigator("Playlist", ":icons/songControl/magnify.svg");
|
||||
|
||||
|
||||
layout->addWidget(home);
|
||||
layout->addWidget(localFiles);
|
||||
layout->addWidget(playlist);
|
||||
}
|
||||
|
||||
Pages::~Pages( ) { }
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QFrame>
|
||||
#include "../../Widgets/PageNavigator/PageNavigator.h"
|
||||
|
||||
class Pages : public QFrame {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
//Page[3] pages;
|
||||
|
||||
public:
|
||||
Pages(QWidget* parent = nullptr);
|
||||
~Pages( );
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
#include "PlaylistPage.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QScrollArea>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QScrollBar>
|
||||
#include <QLabel>
|
||||
|
||||
PlaylistPage::PlaylistPage(QWidget* parent) : QFrame(parent) {
|
||||
|
||||
this->setStyleSheet(R"(
|
||||
background-color: #282828;
|
||||
border-radius: 12px;
|
||||
)");
|
||||
}
|
||||
|
||||
PlaylistPage::~PlaylistPage( ) { }
|
||||
@@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QString>
|
||||
#include <QSvgRenderer>
|
||||
#include <QPainter>
|
||||
|
||||
static QPixmap RenderSvg(QString path, int w, int h) {
|
||||
QSvgRenderer renderer(path);
|
||||
QPixmap pixmap(w, h);
|
||||
pixmap.fill(Qt::transparent);
|
||||
QPainter painter(&pixmap);
|
||||
renderer.render(&painter);
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
#include "PageNavigator.h"
|
||||
#include "SelectHandler.hpp"
|
||||
|
||||
PageNavigator::PageNavigator(QString text, QString icon, QWidget* parent)
|
||||
:m_text(new QLabel(text)), m_icon(new QLabel( )) {
|
||||
|
||||
m_icon->setPixmap(icon);
|
||||
|
||||
setObjectName("PageNavigator");
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
setStyleSheet(R"(
|
||||
#PageNavigator{
|
||||
border: 4px solid #414141;
|
||||
border-radius: 8px;
|
||||
color: #E0E0E0;
|
||||
}
|
||||
)");
|
||||
|
||||
QFont font = m_text->font( );
|
||||
font.setPointSize(16);
|
||||
font.setWeight(QFont::Bold);
|
||||
m_text->setFont(font);
|
||||
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
layout->addWidget(m_icon, 0, Qt::AlignLeft);
|
||||
layout->addWidget(m_text, 1, Qt::AlignLeft);
|
||||
|
||||
connect(this, &QPushButton::clicked, [this]( ) {
|
||||
SelectHandler* sh = SelectHandler::GetInstance( );
|
||||
|
||||
sh->setSelected(this);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void PageNavigator::unselect( ) {
|
||||
setStyleSheet(R"(
|
||||
#PageNavigator{
|
||||
border: 4px solid #414141;
|
||||
border-radius: 6px;
|
||||
color: #E0E0E0;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
void PageNavigator::select( ) {
|
||||
setStyleSheet(R"(
|
||||
#PageNavigator{
|
||||
border: 4px solid #81D4FA;
|
||||
border-radius: 6px;
|
||||
color: #E0E0E0;
|
||||
}
|
||||
)");
|
||||
}
|
||||
68
src/View/MainWidget.cpp
Normal file
68
src/View/MainWidget.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "MainWidget.h"
|
||||
|
||||
void MainWidget::setupMainWidget( ) {
|
||||
setContentsMargins(10, 10, 10, 10);
|
||||
|
||||
QOverlayout* ol = new QOverlayout(this);
|
||||
setLayout(ol);
|
||||
|
||||
QVBoxLayout* vbox = new QVBoxLayout( );
|
||||
vbox->addWidget(floatingControlls, 0, Qt::AlignBottom);
|
||||
|
||||
QHBoxLayout* hbox = new QHBoxLayout( );
|
||||
QVBoxLayout* vbox2 = new QVBoxLayout( );
|
||||
vbox2->addWidget(pageNav);
|
||||
vbox2->addWidget(playlistNav);
|
||||
hbox->addLayout(vbox2);
|
||||
QHBoxLayout* stackedLayout = new QHBoxLayout( );
|
||||
|
||||
stackedLayout->addWidget(homePage);
|
||||
stackedLayout->addWidget(playlistPage);
|
||||
|
||||
playlistPage->setVisible(false);
|
||||
|
||||
hbox->addLayout(stackedLayout, 0);
|
||||
|
||||
hbox->setSpacing(10);
|
||||
vbox2->setSpacing(10);
|
||||
|
||||
ol->addItem(hbox);
|
||||
ol->addItem(vbox);
|
||||
|
||||
connect(pageNav, &PageNavModule::SelectChanged, [this, stackedLayout](PageNavigator* pn) {
|
||||
if (pn->GetText( ).toStdString( ) == "Home") {
|
||||
//stackedLayout->setCurrentIndex(0);
|
||||
stackedLayout->itemAt(0)->widget( )->setVisible(true);
|
||||
stackedLayout->itemAt(1)->widget( )->setVisible(false);
|
||||
}
|
||||
else if (pn->GetText( ).toStdString( ) == "Playlist") {
|
||||
//stackedLayout->setCurrentIndex(1);
|
||||
stackedLayout->itemAt(0)->widget( )->setVisible(false);
|
||||
stackedLayout->itemAt(1)->widget( )->setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void MainWidget::PageChangedAction( ) { }
|
||||
|
||||
MainWidget::MainWidget(QWidget* parent)
|
||||
: QWidget(parent),
|
||||
pageNav(new PageNavModule(this)),
|
||||
playlistNav(new PlaylistNavModule(this)),
|
||||
playlistPage(new PlaylistPage(this)),
|
||||
homePage(new HomePage(this)),
|
||||
floatingControlls(new FloatingControls(this)) {
|
||||
setupMainWidget( );
|
||||
}
|
||||
|
||||
MainWidget::MainWidget(std::filesystem::path path, QWidget* parent)
|
||||
: QWidget(parent),
|
||||
pageNav(new PageNavModule(this)),
|
||||
playlistNav(new PlaylistNavModule(this)),
|
||||
playlistPage(new PlaylistPage(this)),
|
||||
homePage(new HomePage(this)),
|
||||
floatingControlls(new FloatingControls(this, path)) {
|
||||
setupMainWidget( );
|
||||
}
|
||||
|
||||
MainWidget::~MainWidget( ) { }
|
||||
38
src/View/MainWidget.h
Normal file
38
src/View/MainWidget.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLayout>
|
||||
#include <filesystem>
|
||||
#include <QStackedLayout>
|
||||
|
||||
#include "Layouts/QOverlayout.h"
|
||||
#include "Modules/FloatingControls/FloatingControls.h"
|
||||
#include "Modules/PageNavModule/PageNavModule.h"
|
||||
#include "Modules/PlaylistNavModule/PlaylistNavModule.h"
|
||||
#include "Pages/Playlist/PlaylistPage.h"
|
||||
#include "Pages/Home/HomePage.h"
|
||||
|
||||
class MainWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
private:
|
||||
|
||||
PageNavModule* pageNav;
|
||||
PlaylistNavModule* playlistNav;
|
||||
|
||||
PlaylistPage* playlistPage;
|
||||
HomePage* homePage;
|
||||
|
||||
FloatingControls* floatingControlls;
|
||||
|
||||
void setupMainWidget( );
|
||||
|
||||
public:
|
||||
MainWidget(QWidget* parent = nullptr);
|
||||
MainWidget(std::filesystem::path path, QWidget* parent = nullptr);
|
||||
~MainWidget( );
|
||||
|
||||
private slots:
|
||||
void PageChangedAction( );
|
||||
|
||||
|
||||
};
|
||||
27
src/View/MainWindow.cpp
Executable file
27
src/View/MainWindow.cpp
Executable file
@@ -0,0 +1,27 @@
|
||||
#include "MainWindow.h"
|
||||
|
||||
void MainWindow::setupMainWindow( ) {
|
||||
this->setWindowTitle("Crylia Player");
|
||||
this->setWindowIcon(QIcon(":aqua.jpg"));
|
||||
|
||||
setObjectName("MainWindow");
|
||||
setStyleSheet(R"(
|
||||
#MainWindow{
|
||||
background-color: #121212;
|
||||
}
|
||||
)");
|
||||
|
||||
this->setCentralWidget(mainWidget);
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent)
|
||||
: QMainWindow(parent), mainWidget(new MainWidget(this)) {
|
||||
setupMainWindow( );
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(std::filesystem::path path, QWidget* parent)
|
||||
: QMainWindow(parent), mainWidget(new MainWidget(path, this)) {
|
||||
setupMainWindow( );
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow( ) { }
|
||||
@@ -7,23 +7,17 @@
|
||||
#include <QPixmap>
|
||||
#include <filesystem>
|
||||
|
||||
#include "Modules/FloatingControls/FloatingControls.h"
|
||||
#include "Layouts/QOverlayout.h"
|
||||
#include "Modules/PageNavigator/pages.h"
|
||||
#include "Pages/Playlist/PlaylistPage.h"
|
||||
#include "Modules/PlaylistNavigator/PlaylistWidget.h"
|
||||
#include "MainWidget.h"
|
||||
|
||||
class MainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget* parent = nullptr);
|
||||
MainWindow(std::filesystem::path path, QWidget* parent = nullptr);
|
||||
~MainWindow( );
|
||||
|
||||
private:
|
||||
// In case the program gets started with a song as an argument
|
||||
std::filesystem::path path;
|
||||
MainWidget* mainWidget;
|
||||
|
||||
void setupMainWindow( );
|
||||
};
|
||||
@@ -20,27 +20,6 @@ enum Repeat : short {
|
||||
NONE
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static void applyShadow(T obj, int blurRadius = 20, int xOffset = 10, int yOffset = 10, QString color = "#000000", int offset = 2) {
|
||||
QGraphicsDropShadowEffect* dropShadow = new QGraphicsDropShadowEffect( );
|
||||
dropShadow->setBlurRadius(blurRadius);
|
||||
dropShadow->setXOffset(xOffset);
|
||||
dropShadow->setYOffset(yOffset);
|
||||
dropShadow->setColor(color);
|
||||
dropShadow->setOffset(offset);
|
||||
obj->setGraphicsEffect(dropShadow);
|
||||
}
|
||||
|
||||
static QPixmap RenderSvg(QString path) {
|
||||
QSvgRenderer renderer(path);
|
||||
QPixmap pixmap(36, 36);
|
||||
pixmap.fill(Qt::transparent);
|
||||
QPainter painter(&pixmap);
|
||||
renderer.render(&painter);
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
static QPushButton* makeSongControlButton(QString name, QSize size = QSize(36, 36), QString color = "#D7D7D7") {
|
||||
QPushButton* button = new QPushButton( );
|
||||
button->setObjectName(name);
|
||||
@@ -50,7 +29,7 @@ static QPushButton* makeSongControlButton(QString name, QSize size = QSize(36, 3
|
||||
border: 0;
|
||||
}
|
||||
)");
|
||||
button->setIcon(RenderSvg(":/icons/songControl/" + name + ".svg"));
|
||||
button->setIcon(RenderSvg(":/icons/" + name + ".svg", 36, 36));
|
||||
button->setIconSize(size);
|
||||
button->setCursor(Qt::PointingHandCursor);
|
||||
QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( );
|
||||
@@ -70,7 +49,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path)
|
||||
songRepeat(NONE),
|
||||
artist("Artist"),
|
||||
songName("Song"),
|
||||
song(Audio::getInstance(path)) {
|
||||
song(Audio::getInstance( )) {
|
||||
this->setFixedHeight(100);
|
||||
this->setObjectName("main");
|
||||
this->setStyleSheet(R"(
|
||||
@@ -145,7 +124,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path)
|
||||
QHBoxLayout* songControlsLayout = new QHBoxLayout( );
|
||||
songControlsLayout->setAlignment(Qt::AlignCenter | Qt::AlignBottom);
|
||||
|
||||
QString buttonNames[5] = { "songRepeat", "prevSong", "play", "nextSong", "shuffle" };
|
||||
QString buttonNames[5] = { "shuffle", "prevSong", "play", "nextSong", "songRepeat" };
|
||||
QString col = "#D7D7D7";
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (buttonNames[i] == "shuffle" || buttonNames[i] == "songRepeat")
|
||||
@@ -158,16 +137,16 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path)
|
||||
QObject::connect(pb, &QPushButton::clicked, [pb, this]( ) {
|
||||
if (!song.IsMusicPlaying( )) {
|
||||
song.StartMusic( );
|
||||
pb->setIcon(RenderSvg(":/icons/songControl/pause.svg"));
|
||||
pb->setIcon(RenderSvg(":/icons/pause.svg", 36, 36));
|
||||
return;
|
||||
}
|
||||
if (GetPlayPause( )) {
|
||||
song.ResumeMusic( );
|
||||
pb->setIcon(RenderSvg(":/icons/songControl/pause.svg"));
|
||||
pb->setIcon(RenderSvg(":/icons/pause.svg", 36, 36));
|
||||
}
|
||||
else {
|
||||
song.PauseMusic( );
|
||||
pb->setIcon(RenderSvg(":/icons/songControl/play.svg"));
|
||||
pb->setIcon(RenderSvg(":/icons/play.svg", 36, 36));
|
||||
}
|
||||
togglePlayPause( );
|
||||
});
|
||||
@@ -279,7 +258,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path)
|
||||
QLabel* volumeIcon = new QLabel( );
|
||||
volumeIcon->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
volumeIcon->setObjectName("volumeIcon");
|
||||
volumeIcon->setPixmap(RenderSvg(":icons/songControl//volume-high.svg").scaled(QSize(24, 24), Qt::IgnoreAspectRatio));
|
||||
volumeIcon->setPixmap(RenderSvg(":icons/volume-high.svg", 36, 36).scaled(QSize(24, 24), Qt::IgnoreAspectRatio));
|
||||
QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( );
|
||||
colorize->setColor(QColor("#78AB70"));
|
||||
colorize->setStrength(1);
|
||||
@@ -344,7 +323,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path)
|
||||
QLabel* FullscreenLabel = new QLabel( );
|
||||
FullscreenLabel->setFixedSize(36, 24);
|
||||
FullscreenLabel->setObjectName("fullscreenLabel");
|
||||
FullscreenLabel->setPixmap(QPixmap(":icons/songControl//arrow-expand.svg").scaled(QSize(24, 24), Qt::IgnoreAspectRatio));
|
||||
FullscreenLabel->setPixmap(QPixmap(":icons/arrow-expand.svg").scaled(QSize(24, 24), Qt::IgnoreAspectRatio));
|
||||
|
||||
QVBoxLayout* FullscreenLayout = new QVBoxLayout( );
|
||||
FullscreenLayout->setAlignment(Qt::AlignCenter);
|
||||
@@ -1,12 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../../core/audio/audio.h"
|
||||
#include "../../Tools/SvgToPixmap.hpp"
|
||||
|
||||
#include <QFrame>
|
||||
#include <QSlider>
|
||||
#include <QPushButton>
|
||||
#include <QObject>
|
||||
#include <filesystem>
|
||||
#include <QStackedLayout>
|
||||
|
||||
enum Repeat : short;
|
||||
|
||||
32
src/View/Modules/PageNavModule/PageNavModule.cpp
Executable file
32
src/View/Modules/PageNavModule/PageNavModule.cpp
Executable file
@@ -0,0 +1,32 @@
|
||||
#include "PageNavModule.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QFrame>
|
||||
|
||||
PageNavModule::PageNavModule(QWidget* parent) :QFrame(parent) {
|
||||
|
||||
this->setStyleSheet(R"(
|
||||
background-color: #282828;
|
||||
border-radius: 12px;
|
||||
)");
|
||||
|
||||
applyShadow(this);
|
||||
|
||||
this->setFixedSize(300, 180);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
|
||||
PageNavigator* home = new PageNavigator("Home", ":icons/home-outline.svg", "#81D4FA");
|
||||
PageNavigator* localFiles = new PageNavigator("Local Files", ":icons/folder-outline.svg", "#FFE082");
|
||||
PageNavigator* playlist = new PageNavigator("Playlist", ":icons/magnify.svg", "#CE93D8");
|
||||
|
||||
layout->addWidget(home);
|
||||
layout->addWidget(localFiles);
|
||||
layout->addWidget(playlist);
|
||||
|
||||
connect(home, &PageNavigator::SelectedChanged, this, &PageNavModule::SelectChanged);
|
||||
connect(localFiles, &PageNavigator::SelectedChanged, this, &PageNavModule::SelectChanged);
|
||||
connect(playlist, &PageNavigator::SelectedChanged, this, &PageNavModule::SelectChanged);
|
||||
}
|
||||
|
||||
PageNavModule::~PageNavModule( ) { }
|
||||
20
src/View/Modules/PageNavModule/PageNavModule.h
Executable file
20
src/View/Modules/PageNavModule/PageNavModule.h
Executable file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVector>
|
||||
#include <QFrame>
|
||||
#include "../../Widgets/PageNavigator/PageNavigator.h"
|
||||
#include "../../Tools/SvgToPixmap.hpp"
|
||||
|
||||
class PageNavModule : public QFrame {
|
||||
Q_OBJECT
|
||||
private:
|
||||
QVector<PageNavigator> pages;
|
||||
|
||||
public:
|
||||
PageNavModule(QWidget* parent = nullptr);
|
||||
~PageNavModule( );
|
||||
|
||||
signals:
|
||||
void SelectChanged(PageNavigator* pn);
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "PlaylistWidget.h"
|
||||
#include "PlaylistNavModule.h"
|
||||
|
||||
PlaylistWidget::PlaylistWidget(QWidget* parent) : QFrame(parent) {
|
||||
PlaylistNavModule::PlaylistNavModule(QWidget* parent) : QFrame(parent) {
|
||||
|
||||
this->setStyleSheet(R"(
|
||||
background-color: #282828;
|
||||
@@ -14,4 +14,4 @@ PlaylistWidget::PlaylistWidget(QWidget* parent) : QFrame(parent) {
|
||||
|
||||
}
|
||||
|
||||
PlaylistWidget::~PlaylistWidget( ) { }
|
||||
PlaylistNavModule::~PlaylistNavModule( ) { }
|
||||
@@ -4,13 +4,13 @@
|
||||
#include <QFrame>
|
||||
#include <QLayout>
|
||||
|
||||
class PlaylistWidget : public QFrame {
|
||||
class PlaylistNavModule : public QFrame {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
|
||||
public:
|
||||
PlaylistWidget(QWidget* parent);
|
||||
~PlaylistWidget( );
|
||||
PlaylistNavModule(QWidget* parent);
|
||||
~PlaylistNavModule( );
|
||||
};
|
||||
14
src/View/Pages/Home/HomePage.cpp
Normal file
14
src/View/Pages/Home/HomePage.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "HomePage.h"
|
||||
|
||||
HomePage::HomePage(QWidget* parent)
|
||||
: QFrame(parent) {
|
||||
|
||||
setStyleSheet(R"(
|
||||
background-color: #28FF28;
|
||||
border-radius: 12px;
|
||||
)");
|
||||
|
||||
applyShadow(this);
|
||||
}
|
||||
|
||||
HomePage::~HomePage( ) { }
|
||||
15
src/View/Pages/Home/HomePage.h
Normal file
15
src/View/Pages/Home/HomePage.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QFrame>
|
||||
#include "../../Tools/SvgToPixmap.hpp"
|
||||
|
||||
|
||||
class HomePage : public QFrame {
|
||||
Q_OBJECT
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
HomePage(QWidget* parent = nullptr);
|
||||
~HomePage( );
|
||||
};
|
||||
14
src/View/Pages/Playlist/PlaylistPage.cpp
Executable file
14
src/View/Pages/Playlist/PlaylistPage.cpp
Executable file
@@ -0,0 +1,14 @@
|
||||
#include "PlaylistPage.h"
|
||||
|
||||
PlaylistPage::PlaylistPage(QWidget* parent)
|
||||
: QFrame(parent) {
|
||||
|
||||
setStyleSheet(R"(
|
||||
background-color: #2828ff;
|
||||
border-radius: 12px;
|
||||
)");
|
||||
|
||||
applyShadow(this);
|
||||
}
|
||||
|
||||
PlaylistPage::~PlaylistPage( ) { }
|
||||
@@ -2,13 +2,12 @@
|
||||
|
||||
#include <QWidget>
|
||||
#include <QFrame>
|
||||
#include "../../Tools/SvgToPixmap.hpp"
|
||||
|
||||
class PlaylistPage : public QFrame {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
public:
|
||||
PlaylistPage(QWidget* parent);
|
||||
PlaylistPage(QWidget* parent = nullptr);
|
||||
~PlaylistPage( );
|
||||
};
|
||||
29
src/View/Tools/SvgToPixmap.hpp
Normal file
29
src/View/Tools/SvgToPixmap.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPixmap>
|
||||
#include <QString>
|
||||
#include <QSvgRenderer>
|
||||
#include <QPainter>
|
||||
#include <QGraphicsDropShadowEffect>
|
||||
|
||||
static QPixmap RenderSvg(QString path, int w, int h) {
|
||||
QSvgRenderer renderer(path);
|
||||
QPixmap pixmap(w, h);
|
||||
pixmap.fill(Qt::transparent);
|
||||
QPainter painter(&pixmap);
|
||||
renderer.render(&painter);
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void applyShadow(T obj, int blurRadius = 20, int xOffset = 10, int yOffset = 10, QString color = "#000000", int offset = 2) {
|
||||
QGraphicsDropShadowEffect* dropShadow = new QGraphicsDropShadowEffect( );
|
||||
dropShadow->setBlurRadius(blurRadius);
|
||||
dropShadow->setXOffset(xOffset);
|
||||
dropShadow->setYOffset(yOffset);
|
||||
dropShadow->setColor(color);
|
||||
dropShadow->setOffset(offset);
|
||||
obj->setGraphicsEffect(dropShadow);
|
||||
}
|
||||
11
src/View/Widgets/NavigationButton/NavigationButton.cpp
Normal file
11
src/View/Widgets/NavigationButton/NavigationButton.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "NavigationButton.h"
|
||||
|
||||
NavigationButton::NavigationButton( ) { }
|
||||
|
||||
NavigationButton::~NavigationButton( ) { }
|
||||
|
||||
void setSelected(NavigationButton* newSelected);
|
||||
NavigationButton getSelected( ) { }
|
||||
|
||||
void NavigationButton::select( ) { }
|
||||
void NavigationButton::unselect( ) { }
|
||||
31
src/View/Widgets/NavigationButton/NavigationButton.h
Normal file
31
src/View/Widgets/NavigationButton/NavigationButton.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QString>
|
||||
|
||||
class NavigationButton : public QPushButton {
|
||||
Q_OBJECT
|
||||
private:
|
||||
QLabel* m_icon;
|
||||
QLabel* m_name;
|
||||
QString* m_colorHex;
|
||||
|
||||
static NavigationButton* m_selected;
|
||||
|
||||
public:
|
||||
static void setSelected(NavigationButton* newSelected);
|
||||
static NavigationButton* getSelected( );
|
||||
|
||||
NavigationButton( );
|
||||
~NavigationButton( );
|
||||
|
||||
signals:
|
||||
void unselected( );
|
||||
void selected( );
|
||||
|
||||
private slots:
|
||||
void select( );
|
||||
void unselect( );
|
||||
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
#include "PagesButton.h"
|
||||
|
||||
PagesButton::PagesButton( ) { }
|
||||
PagesButton::~PagesButton( ) { }
|
||||
11
src/View/Widgets/NavigationButton/PagesButton/PagesButton.h
Normal file
11
src/View/Widgets/NavigationButton/PagesButton/PagesButton.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "../NavigationButton.h"
|
||||
|
||||
class PagesButton : NavigationButton {
|
||||
private:
|
||||
|
||||
public:
|
||||
PagesButton( );
|
||||
~PagesButton( );
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
#include "PlaylistButton.h"
|
||||
|
||||
PlaylistButton::PlaylistButton( ) { }
|
||||
PlaylistButton::~PlaylistButton( ) { }
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "../NavigationButton.h"
|
||||
|
||||
class PlaylistButton : NavigationButton {
|
||||
private:
|
||||
|
||||
public:
|
||||
PlaylistButton( );
|
||||
~PlaylistButton( );
|
||||
};
|
||||
88
src/View/Widgets/PageNavigator/PageNavigator.cpp
Normal file
88
src/View/Widgets/PageNavigator/PageNavigator.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
#include "PageNavigator.h"
|
||||
#include "SelectHandler.hpp"
|
||||
#include "../../Tools/SvgToPixmap.hpp"
|
||||
|
||||
class SquareIcon : public QLabel {
|
||||
public:
|
||||
QSize sizeHint( ) const override {
|
||||
QSize hint = QLabel::sizeHint( );
|
||||
int side = qMin(hint.width( ), hint.height( ));
|
||||
return QSize(side, side);
|
||||
}
|
||||
};
|
||||
|
||||
PageNavigator::PageNavigator(QString text, QString icon, QString color, QWidget* parent)
|
||||
:m_text(new QLabel(text)), m_icon(new SquareIcon( )), m_color(color), m_iconPath(icon) {
|
||||
|
||||
|
||||
QSvgRenderer renderer(icon);
|
||||
|
||||
QPixmap pixmap(32, 32);
|
||||
pixmap.fill(Qt::transparent);
|
||||
QPainter painter(&pixmap);
|
||||
renderer.render(&painter, pixmap.rect( ));
|
||||
|
||||
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
|
||||
painter.fillRect(pixmap.rect( ), color);
|
||||
painter.end( );
|
||||
|
||||
m_icon->setPixmap(pixmap);
|
||||
|
||||
m_icon->setObjectName("icon");
|
||||
|
||||
setObjectName("PageNavigator");
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
setStyleSheet(R"(
|
||||
#PageNavigator{
|
||||
border: 4px solid #414141;
|
||||
border-radius: 6px;
|
||||
color: #E0E0E0;
|
||||
}
|
||||
)");
|
||||
|
||||
QFont font = m_text->font( );
|
||||
font.setPointSize(16);
|
||||
font.setWeight(QFont::Bold);
|
||||
m_text->setFont(font);
|
||||
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
layout->addWidget(m_icon, 0, Qt::AlignLeft);
|
||||
layout->addWidget(m_text, 1, Qt::AlignLeft);
|
||||
|
||||
connect(this, &QPushButton::clicked, [this, parent]( ) {
|
||||
SelectHandler* sh = SelectHandler::GetInstance( );
|
||||
|
||||
sh->setSelected(this);
|
||||
emit SelectedChanged(this);
|
||||
});
|
||||
|
||||
// Little hacky but thats how home is the default
|
||||
if (text == "Home") {
|
||||
SelectHandler* sh = SelectHandler::GetInstance( );
|
||||
|
||||
sh->setSelected(this);
|
||||
emit SelectedChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
void PageNavigator::unselect( ) {
|
||||
setStyleSheet(R"(
|
||||
#PageNavigator{
|
||||
border: 4px solid #414141;
|
||||
border-radius: 6px;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
void PageNavigator::select( ) {
|
||||
setStyleSheet(R"(
|
||||
#PageNavigator{
|
||||
border: 4px solid )" + m_color + R"(;
|
||||
border-radius: 6px;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
QString PageNavigator::GetText( ) {
|
||||
return m_text->text( );
|
||||
}
|
||||
@@ -5,16 +5,25 @@
|
||||
#include <QLayout>
|
||||
#include <QFont>
|
||||
#include <QPushButton>
|
||||
#include <QColor>
|
||||
#include <QGraphicsColorizeEffect>
|
||||
|
||||
class PageNavigator :public QPushButton {
|
||||
Q_OBJECT
|
||||
private:
|
||||
QLabel* m_text;
|
||||
QLabel* m_icon;
|
||||
QString m_iconPath;
|
||||
QString m_color;
|
||||
|
||||
public:
|
||||
PageNavigator(QString text, QString icon, QWidget* parent = nullptr);
|
||||
PageNavigator(QString text, QString icon, QString color, QWidget* parent = nullptr);
|
||||
|
||||
void unselect( );
|
||||
void select( );
|
||||
|
||||
QString GetText( );
|
||||
|
||||
signals:
|
||||
void SelectedChanged(PageNavigator* pn);
|
||||
};
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include "PageNavigator.h"
|
||||
|
||||
/*
|
||||
@@ -40,7 +39,7 @@ void SelectHandler::setSelected(PageNavigator* newSelected) {
|
||||
|
||||
if (this->selected == nullptr) {
|
||||
this->selected = newSelected;
|
||||
newSelected->select( );
|
||||
selected->select( );
|
||||
return;
|
||||
}
|
||||
|
||||
47
src/core/SongHistory/SongHistory.hpp
Normal file
47
src/core/SongHistory/SongHistory.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
|
||||
template<typename T>
|
||||
class SongHistory {
|
||||
private:
|
||||
struct Node {
|
||||
T data;
|
||||
Node* next;
|
||||
};
|
||||
|
||||
Node* topNode = nullptr;
|
||||
|
||||
public:
|
||||
SongHistory( ) { }
|
||||
~SongHistory( ) {
|
||||
while (!isEmpty( ))
|
||||
pop( );
|
||||
}
|
||||
|
||||
void push(const T& value) {
|
||||
Node* newNode = new Node;
|
||||
newNode->data = value;
|
||||
newNode->next = topNode;
|
||||
topNode = newNode;
|
||||
}
|
||||
|
||||
void pop( ) {
|
||||
if (!isEmpty( )) {
|
||||
Node* tmp = topNode;
|
||||
topNode = topNode->next;
|
||||
delete tmp;
|
||||
}
|
||||
else
|
||||
std::cerr << "Stack empty, cannot pop" << std::endl;
|
||||
}
|
||||
|
||||
T top( ) {
|
||||
if (!isEmpty( ))
|
||||
return topNode->data;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool isEmpty( ) const { return topNode == nullptr; }
|
||||
};
|
||||
@@ -0,0 +1,186 @@
|
||||
#include "ConditionalCircularLinkedList.h"
|
||||
|
||||
ConditionalCircularLinkedList::ConditionalCircularLinkedList( ) { }
|
||||
|
||||
void ConditionalCircularLinkedList::Append(Song* song) {
|
||||
Node* newNode = new Node(song);
|
||||
if (head == nullptr) {
|
||||
head = newNode;
|
||||
|
||||
// Only link back when its supposed to
|
||||
if (isLinked)
|
||||
head->next = head;
|
||||
|
||||
current = head;
|
||||
}
|
||||
else {
|
||||
Node* tmp = head;
|
||||
|
||||
while (tmp->next != head)
|
||||
tmp = tmp->next;
|
||||
|
||||
tmp->next = newNode;
|
||||
|
||||
// Again make sure to only link when supposed to
|
||||
if (isLinked)
|
||||
newNode->next = head;
|
||||
}
|
||||
}
|
||||
|
||||
void ConditionalCircularLinkedList::SetListMode(bool isLooping) {
|
||||
if (head == nullptr) {
|
||||
std::cout << "WARN: List is empty, cannot set mode" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
Node* tmp = head;
|
||||
while (tmp->next != head)
|
||||
tmp = tmp->next;
|
||||
|
||||
if (!isLooping)
|
||||
tmp->next = nullptr;
|
||||
else
|
||||
tmp->next = head;
|
||||
}
|
||||
|
||||
void ConditionalCircularLinkedList::Clear( ) {
|
||||
while (head != nullptr) {
|
||||
Node* tmp = head;
|
||||
head = head->next;
|
||||
delete tmp;
|
||||
delete current;
|
||||
}
|
||||
}
|
||||
|
||||
void ConditionalCircularLinkedList::Advance( ) {
|
||||
if (current != nullptr)
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
Song* ConditionalCircularLinkedList::GetNext( ) {
|
||||
if (current != nullptr)
|
||||
return current->data;
|
||||
}
|
||||
|
||||
void ConditionalCircularLinkedList::AddSongBefore(Song* newSong, Song* addSongBefore) {
|
||||
if (head == nullptr) return;
|
||||
|
||||
Node* newNode = new Node(newSong);
|
||||
|
||||
Node* current = head;
|
||||
Node* prev = nullptr;
|
||||
|
||||
do {
|
||||
if (current->data == addSongBefore) {
|
||||
if (prev == nullptr) {
|
||||
newNode->next = head;
|
||||
head = newNode;
|
||||
|
||||
Node* lastNode = head;
|
||||
while (lastNode->next != head)
|
||||
lastNode = lastNode->next;
|
||||
|
||||
if (isLinked)
|
||||
lastNode->next = head;
|
||||
}
|
||||
else {
|
||||
prev->next = newNode;
|
||||
newNode->next = current;
|
||||
}
|
||||
return;
|
||||
}
|
||||
prev = current;
|
||||
current = current->next;
|
||||
|
||||
} while (current != head);
|
||||
}
|
||||
|
||||
void ConditionalCircularLinkedList::AddSongAfter(Song* newSong, Song* addSongAfter) {
|
||||
if (head == nullptr) return;
|
||||
|
||||
Node* newNode = new Node(newSong);
|
||||
|
||||
Node* current = head;
|
||||
|
||||
do {
|
||||
if (current->data == addSongAfter) {
|
||||
newNode->next = current->next;
|
||||
current->next = newNode;
|
||||
return;
|
||||
}
|
||||
current = current->next;
|
||||
} while (current != head);
|
||||
|
||||
}
|
||||
|
||||
Song* ConditionalCircularLinkedList::RemoveSong(Song* removeSong) {
|
||||
if (head == nullptr) return nullptr;
|
||||
|
||||
Node* current = head;
|
||||
Node* prev = nullptr;
|
||||
|
||||
do {
|
||||
if (current->data == removeSong) {
|
||||
if (prev == nullptr) {
|
||||
head = current->next;
|
||||
Node* lastNode = head;
|
||||
while (lastNode->next != current)
|
||||
lastNode = lastNode->next;
|
||||
|
||||
if (isLinked)
|
||||
lastNode->next = head;
|
||||
|
||||
Song* deletedSong = current->data;
|
||||
delete current;
|
||||
return deletedSong;
|
||||
}
|
||||
else {
|
||||
prev->next = current->next;
|
||||
|
||||
Song* deletedSong = current->data;
|
||||
delete current;
|
||||
return deletedSong;
|
||||
}
|
||||
}
|
||||
prev = current;
|
||||
current = current->next;
|
||||
} while (current != head);
|
||||
}
|
||||
|
||||
bool ConditionalCircularLinkedList::IsEmpty( ) {
|
||||
return current == nullptr;
|
||||
}
|
||||
|
||||
void ConditionalCircularLinkedList::Shuffle( ) {
|
||||
int cnt = 0;
|
||||
Node* tmp = head;
|
||||
|
||||
while (tmp != nullptr) {
|
||||
cnt++;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
Node** nodes = new Node * [cnt];
|
||||
|
||||
tmp = head;
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
nodes[i] = tmp;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
for (int i = cnt; i > 0; i--) {
|
||||
int j = rand( ) % (i + 1);
|
||||
|
||||
Node* tmp = nodes[i];
|
||||
nodes[i] = nodes[j];
|
||||
nodes[j] = tmp;
|
||||
}
|
||||
|
||||
head = nodes[0];
|
||||
for (int i = 0; i < cnt - 1; i++)
|
||||
nodes[i]->next = nodes[i + 1];
|
||||
|
||||
nodes[cnt - 1]->next = nullptr;
|
||||
|
||||
delete[] nodes;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "../../song/song.h"
|
||||
|
||||
class ConditionalCircularLinkedList {
|
||||
private:
|
||||
|
||||
struct Node {
|
||||
Node* next;
|
||||
Song* data;
|
||||
|
||||
Node(Song* song) : data(song), next(nullptr) { }
|
||||
};
|
||||
|
||||
Node* head;
|
||||
|
||||
// Variable to keep the current position that we seek
|
||||
Node* current;
|
||||
|
||||
// Variable to either link or unlink the list
|
||||
bool isLinked;
|
||||
public:
|
||||
ConditionalCircularLinkedList( );
|
||||
ConditionalCircularLinkedList(bool isLinked) : head(nullptr), isLinked(isLinked) { }
|
||||
|
||||
/**
|
||||
* @brief Append a new song to the queue
|
||||
*
|
||||
* @param song
|
||||
*/
|
||||
void Append(Song* song);
|
||||
|
||||
/**
|
||||
* @brief Clear the entire list so its brand spanking new.
|
||||
*
|
||||
*/
|
||||
void Clear( );
|
||||
|
||||
/**
|
||||
* @brief Depending on if the queue is supposed to be looping, this will link
|
||||
* up the end of the list, with its beginning to its a circular list.
|
||||
* If its not supposed to loop then we break the link and it will be a normal list.
|
||||
* @param isLooping Will set the list to circular or normal mode
|
||||
*/
|
||||
void SetListMode(bool isLooping);
|
||||
|
||||
/**
|
||||
* @brief Advance the circular list by one, this means setting the "current" pointer
|
||||
* to the next element
|
||||
*
|
||||
*/
|
||||
void Advance( );
|
||||
|
||||
/**
|
||||
* @brief Get the "current" pointer's data
|
||||
*
|
||||
* @return Song*
|
||||
*/
|
||||
Song* GetNext( );
|
||||
|
||||
void AddSongBefore(Song* newSong, Song* addSongBefore);
|
||||
|
||||
void AddSongAfter(Song* newSong, Song* addSongAfter);
|
||||
|
||||
Song* RemoveSong(Song* removeSong);
|
||||
|
||||
bool IsEmpty( );
|
||||
|
||||
void Shuffle( );
|
||||
};
|
||||
94
src/core/SongQueue/SongQueue.cpp
Normal file
94
src/core/SongQueue/SongQueue.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#include "SongQueue.h"
|
||||
|
||||
SongQueue::SongQueue( ) {
|
||||
queue = new ConditionalCircularLinkedList( );
|
||||
|
||||
// Its never going to be linked, I'm just too lazy to make a new implementation thats almost the same
|
||||
priorityQueue = new ConditionalCircularLinkedList(false);
|
||||
}
|
||||
|
||||
SongQueue::~SongQueue( ) { }
|
||||
|
||||
void SongQueue::PopulateQueue(const std::list<Song*>& songList) {
|
||||
for (Song* song : songList) {
|
||||
queue->Append(song);
|
||||
}
|
||||
}
|
||||
|
||||
void SongQueue::Next( ) {
|
||||
if (priorityQueue->IsEmpty( )) {
|
||||
topSong = queue->GetNext( );
|
||||
queue->Advance( );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
topSong = priorityQueue->GetNext( );
|
||||
priorityQueue->Advance( );
|
||||
}
|
||||
|
||||
void SongQueue::JumpToSong(Song* song, bool fromPrioQueue) {
|
||||
if (fromPrioQueue) {
|
||||
if (priorityQueue->IsEmpty( ))
|
||||
return;
|
||||
|
||||
while (priorityQueue->GetNext( ) != song) {
|
||||
priorityQueue->Advance( );
|
||||
topSong = song;
|
||||
}
|
||||
}
|
||||
|
||||
if (queue->IsEmpty( ))
|
||||
return;
|
||||
|
||||
while (queue->GetNext( ) != song) {
|
||||
queue->Advance( );
|
||||
topSong = song;
|
||||
}
|
||||
}
|
||||
|
||||
void SongQueue::AddToPriorityQueue(Song* song) {
|
||||
priorityQueue->Append(song);
|
||||
}
|
||||
|
||||
bool SongQueue::IsEmpty( ) {
|
||||
return queue->IsEmpty( ) && priorityQueue->IsEmpty( );
|
||||
}
|
||||
|
||||
Song* SongQueue::Top( ) { return topSong; }
|
||||
|
||||
void SongQueue::SetTop(Song* song) { topSong = song; }
|
||||
|
||||
void SongQueue::RemoveSongFromPriorityQueue(Song* song) {
|
||||
if (priorityQueue->IsEmpty( ))
|
||||
return;
|
||||
|
||||
priorityQueue->RemoveSong(song);
|
||||
}
|
||||
|
||||
void SongQueue::MoveSongInPriorityQueue(Song* songToMove, Song* otherSong, bool beforeElseAfter) {
|
||||
if (priorityQueue->IsEmpty( ))
|
||||
return;
|
||||
|
||||
if (beforeElseAfter)
|
||||
priorityQueue->AddSongBefore(songToMove, otherSong);
|
||||
else
|
||||
priorityQueue->AddSongAfter(songToMove, otherSong);
|
||||
}
|
||||
|
||||
void SongQueue::ShufflePlaylist( ) {
|
||||
//First backup the original list state
|
||||
queue_original = new ConditionalCircularLinkedList(queue);
|
||||
|
||||
queue->Shuffle( );
|
||||
}
|
||||
|
||||
void SongQueue::RestorePlaylist( ) {
|
||||
if (queue_original == nullptr) return;
|
||||
|
||||
queue = new ConditionalCircularLinkedList(queue_original);
|
||||
}
|
||||
|
||||
void SongQueue::LinkQueue(bool link) {
|
||||
queue->SetListMode(link);
|
||||
}
|
||||
61
src/core/SongQueue/SongQueue.h
Normal file
61
src/core/SongQueue/SongQueue.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
#include "../song/song.h"
|
||||
#include "ConditionalCircularLinkedList/ConditionalCircularLinkedList.h"
|
||||
|
||||
class SongQueue {
|
||||
private:
|
||||
|
||||
// The currently playing song
|
||||
Song* topSong;
|
||||
|
||||
//Regular song queue, can be unlinked for non looping playlists
|
||||
ConditionalCircularLinkedList* queue;
|
||||
//Copy of queue to faster restore when unshuffling
|
||||
ConditionalCircularLinkedList* queue_original;
|
||||
|
||||
//The name is confusing, but its because the queue itself has priority over the normal one
|
||||
ConditionalCircularLinkedList* priorityQueue;
|
||||
|
||||
void setQueue( );
|
||||
public:
|
||||
SongQueue( );
|
||||
~SongQueue( );
|
||||
|
||||
void PopulateQueue(const std::list<Song*>& songlist);
|
||||
|
||||
/**
|
||||
* @brief Will put the next song from the correct sublist as the topSong.
|
||||
* This will also remove the song from the queue as its not needed anymore.
|
||||
*
|
||||
*/
|
||||
void Next( );
|
||||
|
||||
/**
|
||||
* @brief Will put the given song from the priority or normal queue as the top song and remove it
|
||||
* from the list
|
||||
*
|
||||
* @param song
|
||||
*/
|
||||
void JumpToSong(Song* song, bool fromPrioQueue);
|
||||
|
||||
void AddToPriorityQueue(Song* song);
|
||||
|
||||
bool IsEmpty( );
|
||||
|
||||
Song* Top( );
|
||||
|
||||
void SetTop(Song* song);
|
||||
|
||||
void RemoveSongFromPriorityQueue(Song* song);
|
||||
|
||||
void MoveSongInPriorityQueue(Song* songToMove, Song* otherSong, bool beforeElseAfter);
|
||||
|
||||
void ShufflePlaylist( );
|
||||
void RestorePlaylist( );
|
||||
|
||||
void LinkQueue(bool link);
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "audio.h"
|
||||
|
||||
Audio::Audio(const std::string path) :path(path) {
|
||||
Audio::Audio( ) {
|
||||
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
|
||||
std::cerr << "SDL initialization failed: " << SDL_GetError( ) << std::endl;
|
||||
return;
|
||||
@@ -11,14 +11,6 @@ Audio::Audio(const std::string path) :path(path) {
|
||||
SDL_Quit( );
|
||||
return;
|
||||
}
|
||||
|
||||
music = Mix_LoadMUS(path.c_str( ));
|
||||
if (!music) {
|
||||
std::cerr << "Failed to load MP3 file: " << Mix_GetError( ) << std::endl;
|
||||
Mix_CloseAudio( );
|
||||
SDL_Quit( );
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
Audio::~Audio( ) {
|
||||
@@ -34,6 +26,22 @@ void Audio::StartMusic( ) {
|
||||
}
|
||||
}
|
||||
|
||||
void Audio::StopMusic( ) {
|
||||
Mix_HaltMusic( );
|
||||
}
|
||||
|
||||
void Audio::PlaySong(const std::string path) {
|
||||
this->path = path;
|
||||
|
||||
music = Mix_LoadMUS(path.c_str( ));
|
||||
if (!music) {
|
||||
std::cerr << "Failed to load MP3 file: " << Mix_GetError( ) << std::endl;
|
||||
Mix_CloseAudio( );
|
||||
SDL_Quit( );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Audio::PauseMusic( ) {
|
||||
if (Mix_PlayingMusic( ) == 1) {
|
||||
Mix_PauseMusic( );
|
||||
|
||||
@@ -14,16 +14,16 @@ extern "C" {
|
||||
|
||||
class Audio {
|
||||
public:
|
||||
static Audio& getInstance(const std::string path) {
|
||||
static Audio instance(path);
|
||||
static Audio& getInstance( ) {
|
||||
static Audio instance;
|
||||
return instance;
|
||||
}
|
||||
private:
|
||||
Audio(const std::string path);
|
||||
Audio( );
|
||||
|
||||
const std::string path;
|
||||
const std::string artist;
|
||||
const std::string album;
|
||||
std::string path;
|
||||
std::string artist;
|
||||
std::string album;
|
||||
|
||||
Mix_Music* music;
|
||||
|
||||
@@ -43,6 +43,9 @@ public:
|
||||
|
||||
QPixmap GetAlbumCover( );
|
||||
|
||||
void PlaySong(const std::string path);
|
||||
|
||||
void StopMusic( );
|
||||
void StartMusic( );
|
||||
void PauseMusic( );
|
||||
void ResumeMusic( );
|
||||
|
||||
36
src/core/song/song.cpp
Normal file
36
src/core/song/song.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include "song.h"
|
||||
|
||||
Song::Song(
|
||||
std::string title,
|
||||
std::string album,
|
||||
std::string artist,
|
||||
std::string codec,
|
||||
std::string comment,
|
||||
std::string copyright,
|
||||
std::string publisher,
|
||||
std::string genre,
|
||||
std::string encoded_by,
|
||||
std::string date,
|
||||
std::string language,
|
||||
std::string albumCoverPath,
|
||||
std::string path,
|
||||
int length,
|
||||
std::string discoveredPath
|
||||
) : title(title),
|
||||
album(album),
|
||||
artist(artist),
|
||||
codec(codec),
|
||||
comment(comment),
|
||||
copyright(copyright),
|
||||
publisher(publisher),
|
||||
genre(genre),
|
||||
encoded_by(encoded_by),
|
||||
date(date),
|
||||
language(language),
|
||||
albumCoverPath(albumCoverPath),
|
||||
path(path),
|
||||
length(length) {
|
||||
|
||||
}
|
||||
|
||||
Song::~Song( ) { }
|
||||
54
src/core/song/song.h
Normal file
54
src/core/song/song.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
class Song {
|
||||
private:
|
||||
// Song information
|
||||
const std::string& title;
|
||||
const std::string& album;
|
||||
const std::string& artist;
|
||||
const std::string& codec;
|
||||
const std::string& comment;
|
||||
const std::string& copyright;
|
||||
const std::string& publisher;
|
||||
const std::string& genre;
|
||||
const std::string& encoded_by;
|
||||
const std::string& date;
|
||||
const std::string& language;
|
||||
const std::string& albumCoverPath;
|
||||
const std::string& path;
|
||||
const int& length;
|
||||
|
||||
// Our own Metadata
|
||||
bool favorite = false;
|
||||
int playCount = 0;
|
||||
std::string discovered;
|
||||
|
||||
public:
|
||||
Song(
|
||||
std::string title,
|
||||
std::string album,
|
||||
std::string artist,
|
||||
std::string codec,
|
||||
std::string comment,
|
||||
std::string copyright,
|
||||
std::string publisher,
|
||||
std::string genre,
|
||||
std::string encoded_by,
|
||||
std::string date,
|
||||
std::string language,
|
||||
std::string albumCoverPath,
|
||||
std::string path,
|
||||
int length,
|
||||
std::string discoveredPath
|
||||
);
|
||||
~Song( );
|
||||
|
||||
void SetFavorite(bool fav) { favorite = fav; }
|
||||
|
||||
void IncrementPlayCount( ) { playCount++; }
|
||||
|
||||
std::string GetPath( ) { return path; };
|
||||
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "Public/MainWindow.h"
|
||||
#include "View/MainWindow.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <QApplication>
|
||||
|
||||
Reference in New Issue
Block a user