Part of a larger restructure, added MusicPlayer which is the main controller and a structure for the song queue
@@ -28,9 +28,9 @@ pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
|
|||||||
)
|
)
|
||||||
PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2)
|
PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2)
|
||||||
|
|
||||||
file(GLOB_RECURSE PROJECT_SOURCES ../src/*.cpp)
|
file(GLOB_RECURSE PROJECT_SOURCES src/*.cpp)
|
||||||
file(GLOB_RECURSE PROJECT_HEADERS ../src/*.h)
|
file(GLOB_RECURSE PROJECT_HEADERS src/*.h)
|
||||||
file(GLOB_RECURSE PROJECT_RESOURCES ../assets/resources.qrc)
|
file(GLOB_RECURSE PROJECT_RESOURCES assets/resources.qrc)
|
||||||
|
|
||||||
add_executable(CryliaPlayer
|
add_executable(CryliaPlayer
|
||||||
${PROJECT_SOURCES}
|
${PROJECT_SOURCES}
|
||||||
@@ -61,4 +61,4 @@ set(DESKTOP_FILE ${CMAKE_CURRENT_BINARY_DIR}/CryliaPlayer.desktop)
|
|||||||
configure_file(${DESKTOP_FILE_IN} ${DESKTOP_FILE} @ONLY)
|
configure_file(${DESKTOP_FILE_IN} ${DESKTOP_FILE} @ONLY)
|
||||||
|
|
||||||
install(FILES ${DESKTOP_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
install(FILES ${DESKTOP_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
||||||
install(FILES ../assets/aqua.jpg DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons)
|
install(FILES assets/aqua.jpg DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons)
|
||||||
|
Before Width: | Height: | Size: 193 B After Width: | Height: | Size: 193 B |
1
assets/icons/folder-outline.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20,18H4V8H20M20,6H12L10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6Z" /></svg>
|
||||||
|
After Width: | Height: | Size: 185 B |
1
assets/icons/home-outline.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 5.69L17 10.19V18H15V12H9V18H7V10.19L12 5.69M12 3L2 12H5V20H11V14H13V20H19V12H22" /></svg>
|
||||||
|
After Width: | Height: | Size: 162 B |
|
Before Width: | Height: | Size: 336 B After Width: | Height: | Size: 336 B |
|
Before Width: | Height: | Size: 339 B After Width: | Height: | Size: 339 B |
|
Before Width: | Height: | Size: 109 B After Width: | Height: | Size: 109 B |
|
Before Width: | Height: | Size: 109 B After Width: | Height: | Size: 109 B |
1
assets/icons/playlist-edit.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6V8H14V6H3M3 10V12H14V10H3M20 10.1C19.9 10.1 19.7 10.2 19.6 10.3L18.6 11.3L20.7 13.4L21.7 12.4C21.9 12.2 21.9 11.8 21.7 11.6L20.4 10.3C20.3 10.2 20.2 10.1 20 10.1M18.1 11.9L12 17.9V20H14.1L20.2 13.9L18.1 11.9M3 14V16H10V14H3Z" /></svg>
|
||||||
|
After Width: | Height: | Size: 307 B |
1
assets/icons/playlist-music-outline.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15,6V8H3V6H15M15,10V12H3V10H15M3,16V14H11V16H3M17,6H22V8H19V17A3,3 0 0,1 16,20A3,3 0 0,1 13,17A3,3 0 0,1 16,14C16.35,14 16.69,14.07 17,14.18V6M16,16A1,1 0 0,0 15,17A1,1 0 0,0 16,18A1,1 0 0,0 17,17A1,1 0 0,0 16,16Z" /></svg>
|
||||||
|
After Width: | Height: | Size: 293 B |
1
assets/icons/playlist-plus.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 16H10V14H3M18 14V10H16V14H12V16H16V20H18V16H22V14M14 6H3V8H14M14 10H3V12H14V10Z" /></svg>
|
||||||
|
After Width: | Height: | Size: 161 B |
|
Before Width: | Height: | Size: 332 B After Width: | Height: | Size: 332 B |
|
Before Width: | Height: | Size: 388 B After Width: | Height: | Size: 388 B |
|
Before Width: | Height: | Size: 460 B After Width: | Height: | Size: 460 B |
|
Before Width: | Height: | Size: 360 B After Width: | Height: | Size: 360 B |
|
Before Width: | Height: | Size: 535 B After Width: | Height: | Size: 535 B |
|
Before Width: | Height: | Size: 346 B After Width: | Height: | Size: 346 B |
|
Before Width: | Height: | Size: 412 B After Width: | Height: | Size: 412 B |
|
Before Width: | Height: | Size: 457 B After Width: | Height: | Size: 457 B |
|
Before Width: | Height: | Size: 712 B After Width: | Height: | Size: 712 B |
@@ -1,20 +1,6 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file>aqua.jpg</file>
|
<file>aqua.jpg</file>
|
||||||
<file>icons/songControl/shuffle.svg</file>
|
<file>icons/</file>
|
||||||
<file>icons/songControl/prevSong.svg</file>
|
|
||||||
<file>icons/songControl/nextSong.svg</file>
|
|
||||||
<file>icons/songControl/play.svg</file>
|
|
||||||
<file>icons/songControl/pause.svg</file>
|
|
||||||
<file>icons/songControl/songRepeat.svg</file>
|
|
||||||
<file>icons/songControl/repeat-once.svg</file>
|
|
||||||
<file>icons/songControl/volume-high.svg</file>
|
|
||||||
<file>icons/songControl/volume-low.svg</file>
|
|
||||||
<file>icons/songControl/volume-mute.svg</file>
|
|
||||||
<file>icons/songControl/volume-off.svg</file>
|
|
||||||
<file>icons/songControl/volume-medium.svg</file>
|
|
||||||
<file>icons/songControl/arrow-expand.svg</file>
|
|
||||||
<file>icons/home.svg</file>
|
|
||||||
<file>icons/songControl/magnify.svg</file>
|
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 <QPixmap>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#include "Modules/FloatingControls/FloatingControls.h"
|
#include "MainWidget.h"
|
||||||
#include "Layouts/QOverlayout.h"
|
|
||||||
#include "Modules/PageNavigator/pages.h"
|
|
||||||
#include "Pages/Playlist/PlaylistPage.h"
|
|
||||||
#include "Modules/PlaylistNavigator/PlaylistWidget.h"
|
|
||||||
|
|
||||||
class MainWindow : public QMainWindow {
|
class MainWindow : public QMainWindow {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MainWindow(QWidget* parent = nullptr);
|
MainWindow(QWidget* parent = nullptr);
|
||||||
MainWindow(std::filesystem::path path, QWidget* parent = nullptr);
|
MainWindow(std::filesystem::path path, QWidget* parent = nullptr);
|
||||||
~MainWindow( );
|
~MainWindow( );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// In case the program gets started with a song as an argument
|
MainWidget* mainWidget;
|
||||||
std::filesystem::path path;
|
|
||||||
|
|
||||||
void setupMainWindow( );
|
void setupMainWindow( );
|
||||||
};
|
};
|
||||||
@@ -20,27 +20,6 @@ enum Repeat : short {
|
|||||||
NONE
|
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") {
|
static QPushButton* makeSongControlButton(QString name, QSize size = QSize(36, 36), QString color = "#D7D7D7") {
|
||||||
QPushButton* button = new QPushButton( );
|
QPushButton* button = new QPushButton( );
|
||||||
button->setObjectName(name);
|
button->setObjectName(name);
|
||||||
@@ -50,7 +29,7 @@ static QPushButton* makeSongControlButton(QString name, QSize size = QSize(36, 3
|
|||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
button->setIcon(RenderSvg(":/icons/songControl/" + name + ".svg"));
|
button->setIcon(RenderSvg(":/icons/" + name + ".svg", 36, 36));
|
||||||
button->setIconSize(size);
|
button->setIconSize(size);
|
||||||
button->setCursor(Qt::PointingHandCursor);
|
button->setCursor(Qt::PointingHandCursor);
|
||||||
QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( );
|
QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( );
|
||||||
@@ -70,7 +49,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path)
|
|||||||
songRepeat(NONE),
|
songRepeat(NONE),
|
||||||
artist("Artist"),
|
artist("Artist"),
|
||||||
songName("Song"),
|
songName("Song"),
|
||||||
song(Audio::getInstance(path)) {
|
song(Audio::getInstance( )) {
|
||||||
this->setFixedHeight(100);
|
this->setFixedHeight(100);
|
||||||
this->setObjectName("main");
|
this->setObjectName("main");
|
||||||
this->setStyleSheet(R"(
|
this->setStyleSheet(R"(
|
||||||
@@ -145,7 +124,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path)
|
|||||||
QHBoxLayout* songControlsLayout = new QHBoxLayout( );
|
QHBoxLayout* songControlsLayout = new QHBoxLayout( );
|
||||||
songControlsLayout->setAlignment(Qt::AlignCenter | Qt::AlignBottom);
|
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";
|
QString col = "#D7D7D7";
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
if (buttonNames[i] == "shuffle" || buttonNames[i] == "songRepeat")
|
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]( ) {
|
QObject::connect(pb, &QPushButton::clicked, [pb, this]( ) {
|
||||||
if (!song.IsMusicPlaying( )) {
|
if (!song.IsMusicPlaying( )) {
|
||||||
song.StartMusic( );
|
song.StartMusic( );
|
||||||
pb->setIcon(RenderSvg(":/icons/songControl/pause.svg"));
|
pb->setIcon(RenderSvg(":/icons/pause.svg", 36, 36));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (GetPlayPause( )) {
|
if (GetPlayPause( )) {
|
||||||
song.ResumeMusic( );
|
song.ResumeMusic( );
|
||||||
pb->setIcon(RenderSvg(":/icons/songControl/pause.svg"));
|
pb->setIcon(RenderSvg(":/icons/pause.svg", 36, 36));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
song.PauseMusic( );
|
song.PauseMusic( );
|
||||||
pb->setIcon(RenderSvg(":/icons/songControl/play.svg"));
|
pb->setIcon(RenderSvg(":/icons/play.svg", 36, 36));
|
||||||
}
|
}
|
||||||
togglePlayPause( );
|
togglePlayPause( );
|
||||||
});
|
});
|
||||||
@@ -279,7 +258,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path)
|
|||||||
QLabel* volumeIcon = new QLabel( );
|
QLabel* volumeIcon = new QLabel( );
|
||||||
volumeIcon->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
volumeIcon->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||||
volumeIcon->setObjectName("volumeIcon");
|
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( );
|
QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( );
|
||||||
colorize->setColor(QColor("#78AB70"));
|
colorize->setColor(QColor("#78AB70"));
|
||||||
colorize->setStrength(1);
|
colorize->setStrength(1);
|
||||||
@@ -344,7 +323,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path)
|
|||||||
QLabel* FullscreenLabel = new QLabel( );
|
QLabel* FullscreenLabel = new QLabel( );
|
||||||
FullscreenLabel->setFixedSize(36, 24);
|
FullscreenLabel->setFixedSize(36, 24);
|
||||||
FullscreenLabel->setObjectName("fullscreenLabel");
|
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( );
|
QVBoxLayout* FullscreenLayout = new QVBoxLayout( );
|
||||||
FullscreenLayout->setAlignment(Qt::AlignCenter);
|
FullscreenLayout->setAlignment(Qt::AlignCenter);
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../../../core/audio/audio.h"
|
#include "../../../core/audio/audio.h"
|
||||||
|
#include "../../Tools/SvgToPixmap.hpp"
|
||||||
|
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QSlider>
|
#include <QSlider>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <QStackedLayout>
|
||||||
|
|
||||||
enum Repeat : short;
|
enum Repeat : short;
|
||||||
|
|
||||||
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
@@ -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"(
|
this->setStyleSheet(R"(
|
||||||
background-color: #282828;
|
background-color: #282828;
|
||||||
@@ -14,4 +14,4 @@ PlaylistWidget::PlaylistWidget(QWidget* parent) : QFrame(parent) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PlaylistWidget::~PlaylistWidget( ) { }
|
PlaylistNavModule::~PlaylistNavModule( ) { }
|
||||||
@@ -4,13 +4,13 @@
|
|||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QLayout>
|
#include <QLayout>
|
||||||
|
|
||||||
class PlaylistWidget : public QFrame {
|
class PlaylistNavModule : public QFrame {
|
||||||
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PlaylistWidget(QWidget* parent);
|
PlaylistNavModule(QWidget* parent);
|
||||||
~PlaylistWidget( );
|
~PlaylistNavModule( );
|
||||||
};
|
};
|
||||||
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
@@ -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
@@ -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 <QWidget>
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
|
#include "../../Tools/SvgToPixmap.hpp"
|
||||||
|
|
||||||
class PlaylistPage : public QFrame {
|
class PlaylistPage : public QFrame {
|
||||||
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private:
|
private:
|
||||||
public:
|
public:
|
||||||
PlaylistPage(QWidget* parent);
|
PlaylistPage(QWidget* parent = nullptr);
|
||||||
~PlaylistPage( );
|
~PlaylistPage( );
|
||||||
};
|
};
|
||||||
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
@@ -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
@@ -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
@@ -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
@@ -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 <QLayout>
|
||||||
#include <QFont>
|
#include <QFont>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QColor>
|
||||||
|
#include <QGraphicsColorizeEffect>
|
||||||
|
|
||||||
class PageNavigator :public QPushButton {
|
class PageNavigator :public QPushButton {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
QLabel* m_text;
|
QLabel* m_text;
|
||||||
QLabel* m_icon;
|
QLabel* m_icon;
|
||||||
|
QString m_iconPath;
|
||||||
|
QString m_color;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PageNavigator(QString text, QString icon, QWidget* parent = nullptr);
|
PageNavigator(QString text, QString icon, QString color, QWidget* parent = nullptr);
|
||||||
|
|
||||||
void unselect( );
|
void unselect( );
|
||||||
void select( );
|
void select( );
|
||||||
|
|
||||||
|
QString GetText( );
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void SelectedChanged(PageNavigator* pn);
|
||||||
};
|
};
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
#include "PageNavigator.h"
|
#include "PageNavigator.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -40,7 +39,7 @@ void SelectHandler::setSelected(PageNavigator* newSelected) {
|
|||||||
|
|
||||||
if (this->selected == nullptr) {
|
if (this->selected == nullptr) {
|
||||||
this->selected = newSelected;
|
this->selected = newSelected;
|
||||||
newSelected->select( );
|
selected->select( );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
@@ -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
@@ -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"
|
#include "audio.h"
|
||||||
|
|
||||||
Audio::Audio(const std::string path) :path(path) {
|
Audio::Audio( ) {
|
||||||
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
|
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
|
||||||
std::cerr << "SDL initialization failed: " << SDL_GetError( ) << std::endl;
|
std::cerr << "SDL initialization failed: " << SDL_GetError( ) << std::endl;
|
||||||
return;
|
return;
|
||||||
@@ -11,14 +11,6 @@ Audio::Audio(const std::string path) :path(path) {
|
|||||||
SDL_Quit( );
|
SDL_Quit( );
|
||||||
return;
|
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( ) {
|
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( ) {
|
void Audio::PauseMusic( ) {
|
||||||
if (Mix_PlayingMusic( ) == 1) {
|
if (Mix_PlayingMusic( ) == 1) {
|
||||||
Mix_PauseMusic( );
|
Mix_PauseMusic( );
|
||||||
|
|||||||
@@ -14,16 +14,16 @@ extern "C" {
|
|||||||
|
|
||||||
class Audio {
|
class Audio {
|
||||||
public:
|
public:
|
||||||
static Audio& getInstance(const std::string path) {
|
static Audio& getInstance( ) {
|
||||||
static Audio instance(path);
|
static Audio instance;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
Audio(const std::string path);
|
Audio( );
|
||||||
|
|
||||||
const std::string path;
|
std::string path;
|
||||||
const std::string artist;
|
std::string artist;
|
||||||
const std::string album;
|
std::string album;
|
||||||
|
|
||||||
Mix_Music* music;
|
Mix_Music* music;
|
||||||
|
|
||||||
@@ -43,6 +43,9 @@ public:
|
|||||||
|
|
||||||
QPixmap GetAlbumCover( );
|
QPixmap GetAlbumCover( );
|
||||||
|
|
||||||
|
void PlaySong(const std::string path);
|
||||||
|
|
||||||
|
void StopMusic( );
|
||||||
void StartMusic( );
|
void StartMusic( );
|
||||||
void PauseMusic( );
|
void PauseMusic( );
|
||||||
void ResumeMusic( );
|
void ResumeMusic( );
|
||||||
|
|||||||
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
@@ -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 <filesystem>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|||||||