diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..714f541 --- /dev/null +++ b/.gitignore @@ -0,0 +1,59 @@ +# C++ objects and libs +*.slo +*.lo +*.o +*.a +*.la +*.lai +*.so +*.dll +*.dylib + +# Qt-es +object_script.*.Release +object_script.*.Debug +*_plugin_import.cpp +/.qmake.cache +/.qmake.stash +*.pro.user +*.pro.user.* +*.qbs.user +*.qbs.user.* +*.moc +moc_*.cpp +moc_*.h +qrc_*.cpp +ui_*.h +*.qmlc +*.jsc +Makefile* +*build-* +/build +/app_dir +/release +/debug + +# Qt unit tests +target_wrapper.* + +# QtCreator +*.autosave + +# QtCreator Qml +*.qmlproject.user +*.qmlproject.user.* + +# QtCreator CMake +CMakeLists.txt.user* + +# QtCreator 4.8< compilation database +compile_commands.json + +# QtCreator local machine specific files for imported projects +*creator.user* + +# VSCode +/.vscode + +# Build folder +/build diff --git a/JustAudio.pro b/JustAudio.pro index 4473c71..78d4c48 100644 --- a/JustAudio.pro +++ b/JustAudio.pro @@ -1,43 +1,44 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2016-10-01T14:15:33 -# -# This file is part of JustAudio. -# -# JustAudio is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# JustAudio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with BashWire under the GPL.txt file. If not, see -# . -# -#------------------------------------------------- - -QT += core gui -QT += multimedia -QT += svg - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -TARGET = JustAudio -TEMPLATE = app - -SOURCES += main.cpp \ - aud_file.cpp \ - core.cpp - -HEADERS += \ - aud_file.h \ - core.h - -RESOURCES += \ - res.qrc - -RC_FILE = logo.rc +#------------------------------------------------- +# +# Project created by QtCreator 2016-10-01T14:15:33 +# +# This file is part of JustAudio. +# +# JustAudio is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# JustAudio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BashWire under the GPL.txt file. If not, see +# . +# +#------------------------------------------------- + +QT += core gui +QT += multimedia +QT += svg + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = JustAudio +TEMPLATE = app + +SOURCES += src/main.cpp \ + src/svg_icon.cpp \ + src/core.cpp \ + src/gui.cpp + +HEADERS += src/svg_icon.h \ + src/core.h \ + src/gui.h + +RESOURCES += \ + res.qrc + +RC_FILE = logo.rc diff --git a/README.md b/README.md index 36ad5d0..ebd7d63 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -# What is JustAudio? # - -JustAudio is a simplified audio player designed to be used only for playing music files on the local filesystem and that's it. it doesn't read ID3 data, manage your music collection or stream anything. this app is good for users that already have their music files organized to their liking in the local file system and doesn't want the extra fluff that must media players currently have today. - -### How do I get set up? ### - -This application was built using the [QT](https://www.qt.io/) API. To compile or modify this application, just download and install the QT API, there's usually no need for additional APIs or libraries (depends on the compiler you chose for QT). Versions 4.8 and up are recommended. - -### Who do I talk to? ### - +# What is JustAudio? # + +JustAudio is a simplified audio player designed to be used only for playing music files on the local filesystem and that's it. it doesn't read ID3 data, manage your music collection or stream anything. this app is good for users that already have their music files organized to their liking in the local file system and doesn't want the extra fluff that must media players currently have today. + +### How do I get set up? ### + +This application was built using the [QT](https://www.qt.io/) API. To compile or modify this application, just download and install the QT API, there's usually no need for additional APIs or libraries (depends on the compiler you chose for QT). Versions 4.8 and up are recommended. + +### Who do I talk to? ### + If you have any questions or wish to contribute to the project, please contact the owner of this project at msoneal0(at)gmail.com. \ No newline at end of file diff --git a/bmp/handle.png~ b/bmp/handle.png~ new file mode 100644 index 0000000..662472c Binary files /dev/null and b/bmp/handle.png~ differ diff --git a/bmp/levels.bmp b/bmp/levels.bmp new file mode 100644 index 0000000..24e05db Binary files /dev/null and b/bmp/levels.bmp differ diff --git a/bmp/logo.bmp b/bmp/logo.bmp new file mode 100644 index 0000000..d3b4b73 Binary files /dev/null and b/bmp/logo.bmp differ diff --git a/png/logo.png b/bmp/logo.png~ similarity index 100% rename from png/logo.png rename to bmp/logo.png~ diff --git a/bmp/mute_active.bmp b/bmp/mute_active.bmp new file mode 100644 index 0000000..39432ce Binary files /dev/null and b/bmp/mute_active.bmp differ diff --git a/bmp/mute_active.png~ b/bmp/mute_active.png~ new file mode 100644 index 0000000..eb23082 Binary files /dev/null and b/bmp/mute_active.png~ differ diff --git a/bmp/mute_inactive.bmp b/bmp/mute_inactive.bmp new file mode 100644 index 0000000..1fce29b Binary files /dev/null and b/bmp/mute_inactive.bmp differ diff --git a/bmp/mute_inactive.png~ b/bmp/mute_inactive.png~ new file mode 100644 index 0000000..d2bb23a Binary files /dev/null and b/bmp/mute_inactive.png~ differ diff --git a/bmp/next.bmp b/bmp/next.bmp new file mode 100644 index 0000000..302cce1 Binary files /dev/null and b/bmp/next.bmp differ diff --git a/bmp/open.bmp b/bmp/open.bmp new file mode 100644 index 0000000..a86fe69 Binary files /dev/null and b/bmp/open.bmp differ diff --git a/bmp/open.png~ b/bmp/open.png~ new file mode 100644 index 0000000..a460077 Binary files /dev/null and b/bmp/open.png~ differ diff --git a/bmp/pause_active.bmp b/bmp/pause_active.bmp new file mode 100644 index 0000000..7af0390 Binary files /dev/null and b/bmp/pause_active.bmp differ diff --git a/bmp/pause_active.png~ b/bmp/pause_active.png~ new file mode 100644 index 0000000..7f27ca7 Binary files /dev/null and b/bmp/pause_active.png~ differ diff --git a/bmp/pause_inactive.bmp b/bmp/pause_inactive.bmp new file mode 100644 index 0000000..f8d6606 Binary files /dev/null and b/bmp/pause_inactive.bmp differ diff --git a/bmp/pause_inactive.png~ b/bmp/pause_inactive.png~ new file mode 100644 index 0000000..7aaea4d Binary files /dev/null and b/bmp/pause_inactive.png~ differ diff --git a/bmp/play_active.bmp b/bmp/play_active.bmp new file mode 100644 index 0000000..fa2ffa8 Binary files /dev/null and b/bmp/play_active.bmp differ diff --git a/bmp/play_active.png~ b/bmp/play_active.png~ new file mode 100644 index 0000000..2ff43f4 Binary files /dev/null and b/bmp/play_active.png~ differ diff --git a/bmp/play_inactive.bmp b/bmp/play_inactive.bmp new file mode 100644 index 0000000..ef91b07 Binary files /dev/null and b/bmp/play_inactive.bmp differ diff --git a/bmp/play_inactive.png~ b/bmp/play_inactive.png~ new file mode 100644 index 0000000..17f052a Binary files /dev/null and b/bmp/play_inactive.png~ differ diff --git a/bmp/playlist_active.bmp b/bmp/playlist_active.bmp new file mode 100644 index 0000000..b588806 Binary files /dev/null and b/bmp/playlist_active.bmp differ diff --git a/bmp/playlist_active.png~ b/bmp/playlist_active.png~ new file mode 100644 index 0000000..f8fb05b Binary files /dev/null and b/bmp/playlist_active.png~ differ diff --git a/bmp/playlist_inactive.bmp b/bmp/playlist_inactive.bmp new file mode 100644 index 0000000..aa60059 Binary files /dev/null and b/bmp/playlist_inactive.bmp differ diff --git a/bmp/playlist_inactive.png~ b/bmp/playlist_inactive.png~ new file mode 100644 index 0000000..d13d525 Binary files /dev/null and b/bmp/playlist_inactive.png~ differ diff --git a/bmp/prev.bmp b/bmp/prev.bmp new file mode 100644 index 0000000..65bea2f Binary files /dev/null and b/bmp/prev.bmp differ diff --git a/bmp/prev_active.png~ b/bmp/prev_active.png~ new file mode 100644 index 0000000..382ea51 Binary files /dev/null and b/bmp/prev_active.png~ differ diff --git a/bmp/stop.bmp b/bmp/stop.bmp new file mode 100644 index 0000000..03c9278 Binary files /dev/null and b/bmp/stop.bmp differ diff --git a/core.cpp b/core.cpp deleted file mode 100644 index e043cb7..0000000 --- a/core.cpp +++ /dev/null @@ -1,450 +0,0 @@ -#include "core.h" - -// This file is part of JustAudio. - -// JustAudio is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// JustAudio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with BashWire under the GPL.txt file. If not, see -// . - -Core::Core(QObject *parent) : QObject(parent) -{ - // the Core class acts as a non-gui centralized class that house the majority - // of all functions the application needs to operate. - - nextCheck = new QCheckBox(tr("Play files in directory")); - muteCheck = new QCheckBox(tr("Mute")); - volumeSlider = new QSlider(Qt::Horizontal); - currentFile = new QLabel(tr("Ready")); - audFile = new AudFile(this); - sysTray = 0; - - // QMediaPlayer volume range 0-100. - - volumeSlider->setMinimum(0); - volumeSlider->setMaximum(100); - volumeSlider->setTracking(true); - currentFile->setWordWrap(true); - - QFile file(CONFIG_FILE, this); - - bool ok = false; - - if (file.open(QFile::ReadOnly)) - { - // the CONFIG_FILE is formated in csv so all data is seperated by a ',' - // the data will simply not load if the strings are not in exactly the - // same order as it was saved. - // data formats: - // VOLUME = numeric string - // PLAY_DIR_CHECK = string ("Y" or "N") - // MUTE = string ("Y" or "N") - - QByteArray confData = file.readAll(); - QList split = confData.split(','); - - if (split.size() == 3) - { - int volume = split[VOLUME].toInt(&ok); - - if (ok) - { - volumeSlider->setValue(volume); - - emit setVolume(volume); - - if (split[PLAY_DIR_CHECK] == "Y") nextCheck->setChecked(true); - else nextCheck->setChecked(false); - - if (split[MUTE] == "Y") muteCheck->setChecked(true); - else muteCheck->setChecked(false); - - } - } - } - - if (!ok) - { - // set default values on failure to read the CONFIG_FILE. - - emit setVolume(50); - - volumeSlider->setValue(50); - nextCheck->setChecked(false); - muteCheck->setChecked(false); - } - - file.close(); - - // it's very important that the player stops playback before closing the application - // or it will cause a crash. - - connect(audFile, SIGNAL(endOfPlayback()), this, SLOT(playBackFinished())); - connect(QApplication::instance(), SIGNAL(aboutToQuit()), this, SIGNAL(stop())); -} - -Core::~Core() -{ - audFile->close(); - - QFile file(CONFIG_FILE, this); - - if (file.open(QFile::WriteOnly | QFile::Truncate)) - { - // CONFIG_FILE format: - // [volume],[play_dir_check],[mute] - - // data formats: - // VOLUME = numeric string - // PLAY_DIR_CHECK = string ("Y" or "N") - // MUTE = string ("Y" or "N") - - file.write(QByteArray::number(volumeSlider->value())); - file.write(","); - - if (nextCheck->isChecked()) file.write("Y"); - else file.write("N"); - - file.write(","); - - if (muteCheck->isChecked()) file.write("Y"); - else file.write("N"); - } - - file.close(); -} - -void Core::setFileWatcher(QFileSystemWatcher *watcher) -{ - connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(processfileChanged(QString))); -} - -void Core::setPlayer(QMediaPlayer *player) -{ - // the Core class does not run funtions directly on the QMediaPlayer - // class that lives in the main function so everything it needs to - // do are connected via slots and signals. - - connect(this, SIGNAL(start()), player, SLOT(play())); - connect(this, SIGNAL(pause()), player, SLOT(pause())); - connect(this, SIGNAL(stop()), player, SLOT(stop())); - connect(this, SIGNAL(setMedia(QMediaContent,QIODevice*)), player, SLOT(setMedia(QMediaContent,QIODevice*))); - connect(this, SIGNAL(setVolume(int)), player, SLOT(setVolume(int))); - connect(this, SIGNAL(muteState(bool)), player, SLOT(setMuted(bool))); - connect(player, SIGNAL(stateChanged(QMediaPlayer::State)), this, SLOT(stateChanged(QMediaPlayer::State))); -} - -void Core::setTrayIcon(QSystemTrayIcon *tray) -{ - // must user interaction will be on the system tray icon for this app. - // this funtion sets up the context menu so the user can have access - // to controls like play, pause, next, previous, etc... - - QMenu *contextMenu = new QMenu(); - QWidget *volumeWidget = new QWidget(); - QHBoxLayout *volumeLayout = new QHBoxLayout(volumeWidget); - QWidgetAction *nextCheckAction = new QWidgetAction(this); - QWidgetAction *muteAction = new QWidgetAction(this); - QWidgetAction *volumeAction = new QWidgetAction(this); - QWidgetAction *fileNameAction = new QWidgetAction(this); - QToolButton *volUpIcon = new QToolButton(); - QToolButton *volDownIcon = new QToolButton(); - - fileNameAction->setDefaultWidget(currentFile); - contextMenu->addAction(fileNameAction); - contextMenu->addSeparator(); - - playAction = contextMenu->addAction(QIcon(":/png/play"), tr("Play"), this, SIGNAL(start())); - pauseAction = contextMenu->addAction(QIcon(":/png/pause"), tr("Pause"), this, SIGNAL(pause())); - stopAction = contextMenu->addAction(QIcon(":/png/stop"), tr("Stop"), this, SIGNAL(stop())); - sysTray = tray; - - volUpIcon->setIcon(QIcon(":/png/volume_up")); - volDownIcon->setIcon(QIcon(":/png/volume_down")); - volumeLayout->addWidget(volDownIcon); - volumeLayout->addWidget(volumeSlider); - volumeLayout->addWidget(volUpIcon); - playAction->setEnabled(false); // play, pause, stop, previous and next are disabled initially. - pauseAction->setEnabled(false); // this will change when an audio file is opened - stopAction->setEnabled(false); // (see stateChanged()) - volumeAction->setDefaultWidget(volumeWidget); - nextCheckAction->setDefaultWidget(nextCheck); - muteAction->setDefaultWidget(muteCheck); - contextMenu->addAction(QIcon(":/png/open"), tr("Open"), this, SLOT(openDialog())); - - nextAction = contextMenu->addAction(QIcon(":/png/next"), tr("Next"), this, SLOT(nextFile())); - prevAction = contextMenu->addAction(QIcon(":/png/prev"), tr("Previous"), this, SLOT(prevFile())); - - nextAction->setEnabled(false); - prevAction->setEnabled(false); - contextMenu->addSeparator(); - contextMenu->addAction(nextCheckAction); - contextMenu->addAction(muteAction); - contextMenu->addSeparator(); - contextMenu->addAction(volumeAction); - contextMenu->addSeparator(); - contextMenu->addAction(tr("License"), this, SLOT(showLicense())); - contextMenu->addAction(tr("Exit"), QApplication::instance(), SLOT(quit())); - tray->setContextMenu(contextMenu); - - connect(tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayClicked(QSystemTrayIcon::ActivationReason))); - connect(muteCheck, SIGNAL(clicked(bool)), this, SIGNAL(muteState(bool))); - connect(volumeSlider, SIGNAL(valueChanged(int)), this, SIGNAL(setVolume(int))); - connect(volUpIcon, SIGNAL(clicked()), this, SLOT(volumeUp())); - connect(volDownIcon, SIGNAL(clicked()), this, SLOT(volumeDown())); - connect(pauseAction, SIGNAL(triggered()), audFile, SLOT(userInterupt())); - connect(stopAction, SIGNAL(triggered()), audFile, SLOT(userInterupt())); - connect(playAction, SIGNAL(triggered()), audFile, SLOT(userResume())); -} - -void Core::processfileChanged(const QString &path) -{ - Q_UNUSED(path); - - QFile file(PROCESS_FILE, this); - - if (file.open(QFile::ReadOnly)) - { - // expected data from the PROCESS_FILE should just be a directory path - // string to the audio file to be opened. play() will call out an error - // if it fails to open this file. - - play(file.readAll().trimmed()); - } - - file.close(); -} - -void Core::play(const QString &path) -{ - emit stop(); - - if (audFile->openFile(path)) - { - QFileInfo info(path); - - currentFile->setText(info.fileName()); - - if (sysTray) - { - sysTray->setToolTip(QApplication::applicationName() + " " + QApplication::applicationVersion() + " - " + info.fileName()); - } - - emit setMedia(0, audFile); - emit start(); - } - else - { - QMessageBox box; - - box.setText(tr("Failed to open file: ") + path); - box.setDetailedText(audFile->errorString()); - box.exec(); - } -} - -void Core::nextFile() -{ - fileDir('+'); -} - -void Core::prevFile() -{ - fileDir('-'); -} - -void Core::fileDir(char direction) -{ - // using the current file as a reference, this function will first find out the - // directory the file lives in and then use that directory to list all files within - // it. then using the current file as a reference again, it trys to find it in the - // list of files and then use that file position to find out the next or previous - // file in the directory to play. - - // if the reference file no longer exist then it will attempt to play 1st file in the - // directory. if the directory no longer exist then nothing happens. - - QFileInfo info(audFile->fileName()); - QDir dir(info.path()); - - QStringList list = dir.entryList(audExtensions(), QDir::Files | QDir::Readable, QDir::Name | QDir::IgnoreCase); - int pos = list.indexOf(info.fileName()); - - if (!list.isEmpty()) - { - if (direction == '+') pos++; - else if (direction == '-') pos--; - - if (pos < 0) pos = 0; - - if (pos < list.size()) - { - play(info.path() + QDir::separator() + list[pos]); - } - } -} - -void Core::openDialog() -{ - QFileDialog fileDialog; - QString filterString = tr("Audio Files ("); - QStringList list = audExtensions(); - - for (int i = 0; i < list.size(); ++i) - { - filterString.append(list[i] + " "); - } - - filterString = filterString.trimmed(); - - filterString.append(")"); - - fileDialog.setFileMode(QFileDialog::ExistingFile); - fileDialog.setNameFilter(filterString); - fileDialog.setDirectory(QDir::homePath()); - - if (fileDialog.exec()) - { - play(fileDialog.selectedFiles()[0]); - } -} - -void Core::playBackFinished() -{ - if (nextCheck->isChecked()) nextFile(); -} - -void Core::stateChanged(QMediaPlayer::State state) -{ - mediaState = state; - - switch(state) - { - case QMediaPlayer::PlayingState: - { - playAction->setEnabled(false); - pauseAction->setEnabled(true); - stopAction->setEnabled(true); - prevAction->setEnabled(true); - nextAction->setEnabled(true); - - break; - } - case QMediaPlayer::StoppedState: - { - playAction->setEnabled(true); - pauseAction->setEnabled(false); - stopAction->setEnabled(false); - - break; - } - case QMediaPlayer::PausedState: - { - playAction->setEnabled(true); - pauseAction->setEnabled(false); - stopAction->setEnabled(true); - - break; - } - } -} - -void Core::trayClicked(QSystemTrayIcon::ActivationReason reason) -{ - if (reason == QSystemTrayIcon::DoubleClick) - { - nextAction->trigger(); - } - else if (reason == QSystemTrayIcon::Trigger) - { - if (mediaState == QMediaPlayer::PlayingState) - { - pauseAction->trigger(); - } - else if ((mediaState == QMediaPlayer::PausedState) || (mediaState == QMediaPlayer::StoppedState)) - { - playAction->trigger(); - } - } -} - -void Core::volumeDown() -{ - volumeSlider->setValue(volumeSlider->value() - 4); -} - -void Core::volumeUp() -{ - volumeSlider->setValue(volumeSlider->value() + 4); -} - -void Core::showLicense() -{ - QDialog dialog; - QFile file(":/gpl", this); - - file.open(QFile::ReadOnly); - - QPlainTextEdit *text = new QPlainTextEdit(file.readAll()); - QVBoxLayout *layout = new QVBoxLayout(&dialog); - QRect rect = QApplication::desktop()->screenGeometry(); - - layout->addWidget(text); - text->setReadOnly(true); - text->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); - - file.close(); - dialog.setMinimumWidth(rect.width() / 4); - dialog.setMinimumHeight(rect.height() - (rect.height() / 6)); - dialog.exec(); -} - -QStringList Core::audExtensions() -{ - QStringList ret; - - // the media plugins are not checked for file format support. this is just an arbitrary list - // of audio file extentions that are used when filtering for files to play. if a file fails - // to play, the application will remain in silence or move on to the next file if nextCheck - // is enabled. - - ret.append("*.mp3"); - ret.append("*.ogg"); - ret.append("*.flac"); - ret.append("*.wav"); - ret.append("*.au"); - ret.append("*.aif"); - ret.append("*.mid"); - ret.append("*.rmi"); - ret.append("*.m4a"); - ret.append("*.aiff"); - ret.append("*.ape"); - ret.append("*.wv"); - ret.append("*.3gp"); - ret.append("*.aa"); - ret.append("*.aac"); - ret.append("*.aax"); - ret.append("*.act"); - ret.append("*.amr"); - ret.append("*.au"); - ret.append("*.awb"); - ret.append("*.dct"); - ret.append("*.gsm"); - ret.append("*.m4b"); - ret.append("*.oga"); - ret.append("*.mogg"); - ret.append("*.ra"); - ret.append("*.rm"); - ret.append("*.raw"); - - return ret; -} diff --git a/logo.rc b/logo.rc index 48a36e0..b63382e 100644 --- a/logo.rc +++ b/logo.rc @@ -1 +1 @@ -IDI_ICON1 ICON DISCARDABLE "logo.ico" +IDI_ICON1 ICON DISCARDABLE "logo.ico" diff --git a/png/menu.png b/png/menu.png deleted file mode 100644 index 25d3bac..0000000 Binary files a/png/menu.png and /dev/null differ diff --git a/png/next.png b/png/next.png deleted file mode 100644 index d78a45d..0000000 Binary files a/png/next.png and /dev/null differ diff --git a/png/open.png b/png/open.png deleted file mode 100644 index 4aa449b..0000000 Binary files a/png/open.png and /dev/null differ diff --git a/png/pause.png b/png/pause.png deleted file mode 100644 index 403bf06..0000000 Binary files a/png/pause.png and /dev/null differ diff --git a/png/play.png b/png/play.png deleted file mode 100644 index 1a9b4e2..0000000 Binary files a/png/play.png and /dev/null differ diff --git a/png/prev.png b/png/prev.png deleted file mode 100644 index f6247d1..0000000 Binary files a/png/prev.png and /dev/null differ diff --git a/png/stop.png b/png/stop.png deleted file mode 100644 index 39e1498..0000000 Binary files a/png/stop.png and /dev/null differ diff --git a/png/volume_down.png b/png/volume_down.png deleted file mode 100644 index 27b8b41..0000000 Binary files a/png/volume_down.png and /dev/null differ diff --git a/png/volume_up.png b/png/volume_up.png deleted file mode 100644 index e74cb61..0000000 Binary files a/png/volume_up.png and /dev/null differ diff --git a/res.qrc b/res.qrc index f8a9965..05bf6a8 100644 --- a/res.qrc +++ b/res.qrc @@ -1,17 +1,18 @@ - - - png/logo.png - png/open.png - png/pause.png - png/play.png - png/menu.png - png/next.png - png/prev.png - png/stop.png - png/volume_up.png - png/volume_down.png - - - GPL.txt - - + + + svg/levels.svg + svg/logo.svg + svg/mute_active.svg + svg/mute_inactive.svg + svg/next.svg + svg/open.svg + svg/pause_active.svg + svg/pause_inactive.svg + svg/play_active.svg + svg/play_inactive.svg + svg/playlist_active.svg + svg/playlist_inactive.svg + svg/prev.svg + svg/stop.svg + + diff --git a/GPL.txt b/src/GPL.txt similarity index 100% rename from GPL.txt rename to src/GPL.txt diff --git a/aud_file.cpp b/src/aud_file.cpp similarity index 98% rename from aud_file.cpp rename to src/aud_file.cpp index d53e4b7..f10ee85 100644 --- a/aud_file.cpp +++ b/src/aud_file.cpp @@ -30,7 +30,7 @@ AudFile::AudFile(QObject *parent) : QFile(parent) timer->setSingleShot(true); - connect(timer, SIGNAL(timeout()), this, SIGNAL(endOfPlayback())); + connect(timer, &QTimer::timeout, this, &AudFile::endOfPlayback); } AudFile::~AudFile() diff --git a/aud_file.h b/src/aud_file.h similarity index 100% rename from aud_file.h rename to src/aud_file.h diff --git a/src/core.cpp b/src/core.cpp new file mode 100644 index 0000000..a4b4bb4 --- /dev/null +++ b/src/core.cpp @@ -0,0 +1,365 @@ +#include "core.h" + +// This file is part of JustAudio. + +// JustAudio is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// JustAudio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with BashWire under the GPL.txt file. If not, see +// . + +Core::Core(QObject *parent, QStringList *filesup) : QObject(parent) +{ + // the Core class acts as a non-gui centralized class that house the majority + // of all functions the application needs to operate. + + exts = filesup; +} + +Core::~Core() +{ + // this simply writes the current state of volume, the dir check box and mute + // options to persistant storage so the application can reload the same state + // on startup. + + emit stop(); + + QFile file(CONFIG_FILE, this); + + if (file.open(QFile::WriteOnly | QFile::Truncate)) + { + // CONFIG_FILE format: + // [volume],[play_dir_check],[mute] + + // data formats: + // VOLUME = numeric string + // PLAY_DIR_CHECK = string ("Y" or "N") + // MUTE = string ("Y" or "N") + + file.write(QByteArray::number(volumeSlider->value())); + file.write(","); + + if (playDirAction->isChecked()) file.write("Y"); + else file.write("N"); + + file.write(","); + + if (muteAction->isChecked()) file.write("Y"); + else file.write("N"); + } + + file.close(); +} + +void Core::setFileWatcher(QFileSystemWatcher *watcher) +{ + connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(processfileChanged(QString))); +} + +void Core::setPlayer(QMediaPlayer *player) +{ + // the Core class does not run funtions directly on the QMediaPlayer + // class that lives in the main function so everything it needs to + // do are connected via slots and signals. + + mplayer = player; + + connect(this, &Core::start, mplayer, &QMediaPlayer::play); + connect(this, &Core::pause, mplayer, &QMediaPlayer::pause); + connect(this, &Core::stop, mplayer, &QMediaPlayer::stop); + connect(this, &Core::setFile, mplayer, &QMediaPlayer::setSource); + connect(this, &Core::setSeek, mplayer, &QMediaPlayer::setPosition); + + connect(mplayer, &QMediaPlayer::playbackStateChanged, this, &Core::stateChanged); + connect(mplayer, &QMediaPlayer::mediaStatusChanged, this, &Core::statusChanged); + connect(mplayer, &QMediaPlayer::positionChanged, this, &Core::setPosition); +} + +void Core::setAudioOutput(QAudioOutput *audoOut) +{ + // same as setPlayer() except this connects all slots/signals + // specific to QAudioOutput. + + if (audoOut != nullptr) + { + blockSignals(false); + + connect(this, &Core::setVol, audoOut, &QAudioOutput::setVolume); + connect(this, &Core::muteState, audoOut, &QAudioOutput::setMuted); + } + else + { + // audo playback won't be possible without a valid + // AudioOutput object so all core signals will be blocked + // to prevent undefined behaviour. + + blockSignals(true); + } +} + +void Core::updateSeekDisp() +{ + seekDisp->setText(QString::number(mplayer->position()) + "/" + QString::number(mplayer->duration())); +} + +void Core::setGuiActions(QAction *playAct, QAction *pauseAct, QAction *stopAct, QAction *nextAct, QAction *prevAct, QAction *muteAct, QAction *dir) +{ + // the core class will not interact directly with the GUI, instead all actions are + // abstracted via various QAction classes passed onto it from the main function. + + playAction = playAct; + pauseAction = pauseAct; + stopAction = stopAct; + nextAction = nextAct; + prevAction = prevAct; + muteAction = muteAct; + playDirAction = dir; + tracking = true; + + connect(playAction, &QAction::triggered, this, &Core::start); + connect(pauseAction, &QAction::triggered, this, &Core::pause); + connect(stopAction, &QAction::triggered, this, &Core::stop); + connect(nextAction, &QAction::triggered, this, &Core::nextFile); + connect(prevAction, &QAction::triggered, this, &Core::prevFile); + connect(muteAction, &QAction::triggered, this, &Core::muteState); + + playAction->setEnabled(false); // play, pause, stop, previous and next are disabled initially. + pauseAction->setEnabled(false); // this will change when an audio file is opened + stopAction->setEnabled(false); // (see stateChanged()) + nextAction->setEnabled(false); + prevAction->setEnabled(false); +} + +void Core::setGuiElements(QSlider *volSlider, QSlider *skSlider, QLabel *nameDisp, QLabel *seekLabel) +{ + volumeSlider = volSlider; + seekSlider = skSlider; + currentFile = nameDisp; + seekDisp = seekLabel; + + connect(seekSlider, &QSlider::sliderPressed, this, &Core::seekerPress); + connect(seekSlider, &QSlider::sliderReleased, this, &Core::seekerRelease); + connect(volumeSlider, &QSlider::valueChanged, this, &Core::setVolume); + connect(mplayer, &QMediaPlayer::durationChanged, this, &Core::setDuration); + + // QMediaPlayer volume range 0-100. + + seekSlider->setMinimum(0); + seekSlider->setMaximum(0); + volumeSlider->setMinimum(0); + volumeSlider->setMaximum(100); + currentFile->setWordWrap(true); + + QFile file(CONFIG_FILE, this); + + bool ok = false; + + if (file.open(QFile::ReadOnly)) + { + // the CONFIG_FILE is formated in csv so all data is seperated by a ',' + // the data will simply not load if the strings are not in exactly the + // same order as it was saved. + // data formats: + // VOLUME = numeric string + // PLAY_DIR_CHECK = string ("Y" or "N") + // MUTE = string ("Y" or "N") + + auto confData = file.readAll(); + auto params = confData.split(','); + + if (params.size() == 3) + { + int volume = params[VOLUME].toInt(&ok); + + if (ok) + { + volumeSlider->setValue(volume); + + setVolume(volume); + + if (params[PLAY_DIR_CHECK] == "Y") emit playDirAction->triggered(true); + else emit playDirAction->triggered(false); + + if (params[MUTE] == "Y") emit muteAction->triggered(true); + else emit muteAction->triggered(false); + } + } + } + + if (!ok) + { + // set default values on failure to read the CONFIG_FILE. + + setVolume(50); + + emit playDirAction->triggered(false); + emit muteAction->triggered(false); + + volumeSlider->setValue(50); + } + + file.close(); +} + +void Core::processfileChanged(const QString &path) +{ + Q_UNUSED(path); + + QFile file(PROCESS_FILE, this); + + if (file.open(QFile::ReadOnly)) + { + // expected data from the PROCESS_FILE should just be a directory path + // string to the audio file to be opened. play() will call out an error + // if it fails to open this file. + + play(file.readAll().trimmed()); + } + + file.close(); +} + +void Core::seekerPress() +{ + tracking = false; +} + +void Core::seekerRelease() +{ + emit setSeek(seekSlider->value()); + + tracking = true; +} + +void Core::setDuration(int dur) +{ + seekSlider->setMaximum(dur); + + updateSeekDisp(); +} + +void Core::setPosition(int pos) +{ + if (tracking) seekSlider->setValue(pos); + + updateSeekDisp(); +} + +void Core::setVolume(int intValue) +{ + emit setVol(static_cast(intValue) / static_cast(volumeSlider->maximum()) * static_cast(1)); +} + +void Core::play(const QString &path) +{ + emit stop(); + + currentFile->setText(QFileInfo(path).fileName()); + + emit setFile(QUrl::fromLocalFile(path)); + emit start(); +} + +void Core::nextFile() +{ + fileDir('+'); +} + +void Core::prevFile() +{ + fileDir('-'); +} + +void Core::fileDir(char direction) +{ + // using the current file as a reference, this function will first find out the + // directory the file lives in and then use that directory to list all files within + // it. then using the current file as a reference again, it trys to find it in the + // list of files and then use that file position to find out the next or previous + // file in the directory to play. + + // if the reference file no longer exist then it will attempt to play 1st file in the + // directory. if the directory no longer exist then nothing happens. + + QFileInfo info(mplayer->source().path()); + QDir dir(info.path()); + + auto list = dir.entryList(*exts, QDir::Files | QDir::Readable, QDir::Name | QDir::IgnoreCase); + auto pos = list.indexOf(info.fileName()); + + if (!list.isEmpty()) + { + if (direction == '+') pos++; + else if (direction == '-') pos--; + + if (pos < 0) pos = 0; + + if (pos < list.size()) + { + play(info.path() + QDir::separator() + list[pos]); + } + } +} + +void Core::stateChanged(QMediaPlayer::PlaybackState state) +{ + switch(state) + { + case QMediaPlayer::PlayingState: + { + playAction->setEnabled(false); + pauseAction->setEnabled(true); + stopAction->setEnabled(true); + prevAction->setEnabled(true); + nextAction->setEnabled(true); + + break; + } + case QMediaPlayer::StoppedState: + { + playAction->setEnabled(true); + pauseAction->setEnabled(false); + stopAction->setEnabled(false); + + break; + } + case QMediaPlayer::PausedState: + { + playAction->setEnabled(true); + pauseAction->setEnabled(false); + stopAction->setEnabled(true); + + break; + } + } +} + +void Core::statusChanged(QMediaPlayer::MediaStatus state) +{ + if (state == QMediaPlayer::EndOfMedia) + { + if (playDirAction->isChecked()) nextFile(); + } +} + +void Core::volumeDown() +{ + volumeSlider->setValue(volumeSlider->value() - 5); + + setVolume(volumeSlider->value()); +} + +void Core::volumeUp() +{ + volumeSlider->setValue(volumeSlider->value() + 5); + + setVolume(volumeSlider->value()); +} diff --git a/core.h b/src/core.h similarity index 58% rename from core.h rename to src/core.h index 1ec62a3..ce6f7df 100644 --- a/core.h +++ b/src/core.h @@ -19,32 +19,22 @@ #include #include -#include +#include #include #include +#include #include #include #include -#include #include -#include -#include #include #include -#include #include #include -#include #include -#include #include -#include -#include -#include -#include -#include -#include #include +#include #include "aud_file.h" @@ -65,43 +55,49 @@ private: MUTE }; - AudFile *audFile; - QAction *playAction; - QAction *pauseAction; - QAction *stopAction; - QAction *nextAction; - QAction *prevAction; - QCheckBox *nextCheck; - QCheckBox *muteCheck; - QSlider *volumeSlider; - QLabel *currentFile; - QSystemTrayIcon *sysTray; - int mediaState; + QMediaPlayer *mplayer; + QAction *playAction; + QAction *pauseAction; + QAction *stopAction; + QAction *nextAction; + QAction *prevAction; + QAction *muteAction; + QAction *playDirAction; + QSlider *volumeSlider; + QSlider *seekSlider; + QLabel *currentFile; + QLabel *seekDisp; + QStringList *exts; + bool tracking; - void fileDir(char direction); - QStringList audExtensions(); + void updateSeekDisp(); + void fileDir(char direction); private slots: - void trayClicked(QSystemTrayIcon::ActivationReason reason); - void stateChanged(QMediaPlayer::State state); + void statusChanged(QMediaPlayer::MediaStatus state); + void stateChanged(QMediaPlayer::PlaybackState state); void processfileChanged(const QString &path); + void setDuration(int dur); + void setPosition(int pos); + void setVolume(int lvl); void nextFile(); void prevFile(); - void playBackFinished(); - void openDialog(); void volumeUp(); void volumeDown(); - void showLicense(); + void seekerPress(); + void seekerRelease(); public: - void setTrayIcon(QSystemTrayIcon *tray); void setPlayer(QMediaPlayer *player); + void setAudioOutput(QAudioOutput *audoOut); void setFileWatcher(QFileSystemWatcher *watcher); + void setGuiActions(QAction *playAct, QAction *pauseAct, QAction *stopAct, QAction *nextAct, QAction *prevAct, QAction *muteAct, QAction *dir); + void setGuiElements(QSlider *volSlider, QSlider *skSlider, QLabel *nameDisp, QLabel *seekLabel); void play(const QString &path); - Core(QObject *parent = 0); + Core(QObject *parent, QStringList *filesup); ~Core(); signals: @@ -109,8 +105,9 @@ signals: void start(); void pause(); void stop(); - void setMedia(const QMediaContent &media, QIODevice *stream); - void setVolume(int value); + void setSeek(qint64 pos); + void setFile(const QUrl &url); + void setVol(float value); void muteState(bool state); }; diff --git a/src/gui.cpp b/src/gui.cpp new file mode 100644 index 0000000..d103773 --- /dev/null +++ b/src/gui.cpp @@ -0,0 +1,159 @@ +#include "gui.h" + +// This file is part of JustAudio. + +// JustAudio is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// JustAudio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with BashWire under the GPL.txt file. If not, see +// . + +GUI::GUI(QApplication *app, QStringList *filesup, QWidget *parent): QMainWindow(parent) +{ + Q_UNUSED(app); + + exts = filesup; + + setup(); +} + +void GUI::openDialog() +{ + QFileDialog fileDialog; + QString filterString = tr("Audio Files ("); + + for (int i = 0; i < exts->size(); ++i) + { + filterString.append(exts->value(i) + " "); + } + + filterString = filterString.trimmed(); + + filterString.append(")"); + + fileDialog.setFileMode(QFileDialog::ExistingFile); + fileDialog.setNameFilter(filterString); + fileDialog.setDirectory(QDir::homePath()); + + if (fileDialog.exec()) + { + emit openFile(fileDialog.selectedFiles()[0]); + } +} + +void GUI::setup() +{ + auto mainWidget = new QWidget(this); + auto mainLayout = new QVBoxLayout(mainWidget); + + auto seekWidget = new QWidget(this); + auto seekLayout = new QHBoxLayout(seekWidget); + + auto contWidget = new QWidget(this); + auto contLayout = new QHBoxLayout(contWidget); + + auto voluWidget = new QWidget(this); + auto voluLayout = new QVBoxLayout(voluWidget); + + auto volWidActi = new QWidgetAction(this); + auto volumeMenu = new QMenu(this); + + seeker = new QSlider(this); + volSlide = new QSlider(this); + seekLabel = new QLabel(this); + fileDisp = new QLabel(this); + + playBtn = new SVGIcon("play", tr("Play"), true, this); + pauseBtn = new SVGIcon("pause", tr("Pause"), true, this); + stopBtn = new SVGIcon("stop", tr("Stop"), false, this); + prevBtn = new SVGIcon("prev", tr("Previous file in dir"), false, this); + nextBtn = new SVGIcon("next", tr("Next file in dir"), false, this); + openBtn = new SVGIcon("open", tr("Open"), false, this); + muteBtn = new SVGIcon("mute", tr("Mute"), true, this); + dirBtn = new SVGIcon("playlist", tr("Play files in dir"), true, this); + lvlsBtn = new SVGIcon("levels", tr("Volume level"), false, this); + + auto fnt = seekLabel->font(); + + fnt.setPointSize(5); + + fileDisp->setWordWrap(true); + fileDisp->setFixedWidth(288); + seeker->setOrientation(Qt::Horizontal); + seeker->setFixedWidth(288); + seekLabel->setFont(fnt); + volSlide->setOrientation(Qt::Vertical); + lvlsBtn->setMenu(volumeMenu); + + seekLayout->addWidget(seeker); + seekLayout->addWidget(seekLabel); + + voluLayout->addWidget(new QLabel("+", this)); + voluLayout->addWidget(volSlide); + voluLayout->addWidget(new QLabel("-", this)); + + volWidActi->setDefaultWidget(voluWidget); + volumeMenu->addAction(volWidActi); + + contLayout->addWidget(playBtn); + contLayout->addWidget(pauseBtn); + contLayout->addWidget(stopBtn); + contLayout->addWidget(prevBtn); + contLayout->addWidget(nextBtn); + contLayout->addWidget(dirBtn); + contLayout->addWidget(openBtn); + contLayout->addWidget(muteBtn); + contLayout->addWidget(lvlsBtn); + + mainLayout->addWidget(fileDisp, 0, Qt::AlignHCenter); + mainLayout->addWidget(seekWidget, 0, Qt::AlignHCenter); + mainLayout->addWidget(contWidget, 0, Qt::AlignHCenter); + + connect(openBtn->defaultAction(), &QAction::triggered, this, &GUI::openDialog); + connect(dirBtn->defaultAction(), &QAction::triggered, nextBtn, &QToolButton::setEnabled); + connect(dirBtn->defaultAction(), &QAction::triggered, prevBtn, &QToolButton::setEnabled); + + setCentralWidget(mainWidget); +} + +QLabel *GUI::seekDisp() {return seekLabel;} +QLabel *GUI::fileName() {return fileDisp;} +QSlider *GUI::seek() {return seeker;} +QSlider *GUI::volume() {return volSlide;} +QAction *GUI::play() {return playBtn->defaultAction();} +QAction *GUI::pause() {return pauseBtn->defaultAction();} +QAction *GUI::stop() {return stopBtn->defaultAction();} +QAction *GUI::prev() {return prevBtn->defaultAction();} +QAction *GUI::next() {return nextBtn->defaultAction();} +QAction *GUI::mute() {return muteBtn->defaultAction();} +QAction *GUI::dir() {return nextBtn->defaultAction();} + +void GUI::showLicense() +{ + QDialog dialog; + QFile file(":/gpl", this); + + file.open(QFile::ReadOnly); + + QPlainTextEdit *text = new QPlainTextEdit(file.readAll()); + QVBoxLayout *layout = new QVBoxLayout(&dialog); + QRect rect = QApplication::primaryScreen()->geometry(); + + layout->addWidget(text); + text->setReadOnly(true); + text->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + + file.close(); + dialog.setMinimumWidth(rect.width() / 4); + dialog.setMinimumHeight(rect.height() - (rect.height() / 6)); + dialog.exec(); +} + diff --git a/src/gui.h b/src/gui.h new file mode 100644 index 0000000..0ca0507 --- /dev/null +++ b/src/gui.h @@ -0,0 +1,92 @@ +#ifndef GUI_H +#define GUI_H + +// This file is part of JustAudio. + +// JustAudio is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// JustAudio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with BashWire under the GPL.txt file. If not, see +// . + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "svg_icon.h" + +class GUI : public QMainWindow +{ + Q_OBJECT + +private slots: + + void openDialog(); + void showLicense(); + +private: + + QStringList *exts; + QLabel *fileDisp; + QLabel *seekLabel; + QSlider *seeker; + QSlider *volSlide; + QMenu *volumeMenu; + SVGIcon *playBtn; + SVGIcon *pauseBtn; + SVGIcon *stopBtn; + SVGIcon *prevBtn; + SVGIcon *nextBtn; + SVGIcon *muteBtn; + SVGIcon *openBtn; + SVGIcon *dirBtn; + SVGIcon *lvlsBtn; + + void setup(); + +public: + + explicit GUI(QApplication *app, QStringList *filesup, QWidget *parent = nullptr); + + QAction *play(); + QAction *pause(); + QAction *stop(); + QAction *next(); + QAction *prev(); + QAction *mute(); + QAction *dir(); + QSlider *volume(); + QSlider *seek(); + QLabel *fileName(); + QLabel *seekDisp(); + +signals: + + void openFile(const QString &path); +}; + +#endif // GUI_H diff --git a/main.cpp b/src/main.cpp similarity index 62% rename from main.cpp rename to src/main.cpp index 18785b3..2de0490 100644 --- a/main.cpp +++ b/src/main.cpp @@ -10,6 +10,7 @@ #include "aud_file.h" #include "core.h" +#include "gui.h" // This file is part of JustAudio. @@ -27,13 +28,53 @@ // along with BashWire under the GPL.txt file. If not, see // . +QStringList audExtensions() +{ + QStringList ret; + + // the media plugins are not checked for file format support. this is just an arbitrary list + // of audio file extentions that are used when filtering for files to play. if a file fails + // to play, the application will remain in silence or move on to the next file if nextCheck + // is enabled. + + ret.append("*.mp3"); + ret.append("*.ogg"); + ret.append("*.flac"); + ret.append("*.wav"); + ret.append("*.au"); + ret.append("*.aif"); + ret.append("*.mid"); + ret.append("*.rmi"); + ret.append("*.m4a"); + ret.append("*.aiff"); + ret.append("*.ape"); + ret.append("*.wv"); + ret.append("*.3gp"); + ret.append("*.aa"); + ret.append("*.aac"); + ret.append("*.aax"); + ret.append("*.act"); + ret.append("*.amr"); + ret.append("*.au"); + ret.append("*.awb"); + ret.append("*.dct"); + ret.append("*.gsm"); + ret.append("*.m4b"); + ret.append("*.oga"); + ret.append("*.mogg"); + ret.append("*.ra"); + ret.append("*.rm"); + ret.append("*.raw"); + + return ret; +} + int main(int argc, char *argv[]) { QApplication app(argc, argv); app.setApplicationName("JustAudio"); app.setApplicationVersion("1.0.0"); - app.setQuitOnLastWindowClosed(false); QString path = QDir::homePath() + QDir::separator(); @@ -71,25 +112,33 @@ int main(int argc, char *argv[]) // QSharedMemory::create() returns false if that is the case and true if not. // if an instance of the app is already runnning, the requested file path to playback // is written to PROCESS_FILE, that modification to the file is picked up by - // QFileSystemWatcher and then read by the currently running instance and starts + // QFileSystemWatcher will then read by the currently running instance and starts // playback of the file path written to PROCESS_FILE. QSharedMemory sharedMem(app.applicationName(), &app); - if (sharedMem.create(SEGMENT_SIZE)) + if (true)//sharedMem.create(SEGMENT_SIZE)) { - QFileSystemWatcher processFileWatcher(&app); - QSystemTrayIcon trayIcon(&app); - QMediaPlayer player(&app); - Core core(&app); + auto exts = audExtensions(); + QFileSystemWatcher processFileWatcher(&app); + GUI gui(&app, &exts); + QMediaPlayer player(&app); + QAudioOutput audio(&app); + Core core(&app, &exts); + + player.setAudioOutput(&audio); core.setFileWatcher(&processFileWatcher); core.setPlayer(&player); - core.setTrayIcon(&trayIcon); + core.setAudioOutput(&audio); + core.setGuiActions(gui.play(), gui.pause(), gui.stop(), gui.next(), gui.prev(), gui.mute(), gui.dir()); + core.setGuiElements(gui.volume(), gui.seek(), gui.fileName(), gui.seekDisp()); + processFileWatcher.addPath(PROCESS_FILE); - trayIcon.setToolTip(app.applicationName() + " " + app.applicationVersion()); - trayIcon.setIcon(QIcon(":/png/logo")); - trayIcon.show(); + + QObject::connect(&gui, &GUI::openFile, &core, &Core::play); + + gui.show(); if (app.arguments().size() > 1) { diff --git a/src/svg_icon.cpp b/src/svg_icon.cpp new file mode 100644 index 0000000..bc4adfc --- /dev/null +++ b/src/svg_icon.cpp @@ -0,0 +1,126 @@ +#include "svg_icon.h" + +// This file is part of JustAudio. + +// JustAudio is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// JustAudio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with BashWire under the GPL.txt file. If not, see +// . + +SVGIcon::SVGIcon(const QString &name, const QString &desc, bool toggle, QWidget *parent) : QToolButton(parent) +{ + auto action = new QAction(this); + + setObjectName(name); + setMinimumHeight(32); + setMinimumWidth(32); + setToolTip(desc); + setToolButtonStyle(Qt::ToolButtonIconOnly); + setPopupMode(QToolButton::InstantPopup); + setCursor(Qt::PointingHandCursor); + + action->setCheckable(toggle); + + connect(action, &QAction::enabledChanged, this, &SVGIcon::enabledChanged); + connect(action, &QAction::triggered, this, &SVGIcon::clickedInternal); + + setDefaultAction(action); + setActiveAppearance(); +} + +void SVGIcon::setInactiveAppearance() +{ + loadSvgFile(":/svg/" + objectName() + "_inactive.svg"); +} + +void SVGIcon::setActiveAppearance() +{ + if (defaultAction()->isCheckable()) + { + loadSvgFile(":/svg/" + objectName() + "_active.svg"); + } + else + { + loadSvgFile(":/svg/" + objectName() + ".svg"); + } +} + +void SVGIcon::enabledChanged(bool state) +{ + if (defaultAction()->isCheckable()) + { + if (state) setActiveAppearance(); + else setInactiveAppearance(); + } + else + { + setHidden(!state); + } +} + +void SVGIcon::clickedInternal() +{ + if (defaultAction()->isCheckable()) + { + if (defaultAction()->isChecked()) setActiveAppearance(); + else setInactiveAppearance(); + } +} + +void SVGIcon::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + + QSvgRenderer svg(localData, this); + + svg.render(&painter); +} + +void SVGIcon::loadSvgFile(const QString &path) +{ + fileCopy(path); + update(); +} + +void SVGIcon::fileCopy(const QString &path) +{ + QFile file(path, this); + + if (file.open(QFile::ReadOnly)) + { + auto data = file.readAll(); + + QXmlStreamReader xml(data); + + while (!xml.atEnd()) + { + xml.readNext(); + + if (xml.hasError()) break; + } + + if (xml.hasError()) + { + qDebug() << tr("Invalid svg image (xml parse error)"); + } + else + { + localData = data; + } + } + else + { + qDebug() << tr("Unable to read file: ") + path; + } + + file.close(); +} diff --git a/src/svg_icon.h b/src/svg_icon.h new file mode 100644 index 0000000..38196ad --- /dev/null +++ b/src/svg_icon.h @@ -0,0 +1,54 @@ +#ifndef ICON_H +#define ICON_H + +// This file is part of JustAudio. + +// JustAudio is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// JustAudio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with BashWire under the GPL.txt file. If not, see +// . + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SVGIcon : public QToolButton +{ + Q_OBJECT + +private slots: + + void enabledChanged(bool state); + void clickedInternal(); + +private: + + QByteArray localData; + + void setInactiveAppearance(); + void setActiveAppearance(); + void loadSvgFile(const QString &path); + void paintEvent(QPaintEvent *); + void fileCopy(const QString &path); + +public: + + explicit SVGIcon(const QString &name, const QString &desc, bool toggle, QWidget *parent = 0); +}; + +#endif // ICON_H diff --git a/svg/levels.svg b/svg/levels.svg new file mode 100644 index 0000000..bc7e346 --- /dev/null +++ b/svg/levels.svg @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/svg/logo.svg b/svg/logo.svg new file mode 100644 index 0000000..69a7218 --- /dev/null +++ b/svg/logo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/svg/mute_active.svg b/svg/mute_active.svg new file mode 100644 index 0000000..ba58d51 --- /dev/null +++ b/svg/mute_active.svg @@ -0,0 +1,458 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/svg/mute_inactive.svg b/svg/mute_inactive.svg new file mode 100644 index 0000000..d8ae54a --- /dev/null +++ b/svg/mute_inactive.svg @@ -0,0 +1,435 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/svg/next.svg b/svg/next.svg new file mode 100644 index 0000000..f99b255 --- /dev/null +++ b/svg/next.svg @@ -0,0 +1,330 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/svg/open.svg b/svg/open.svg new file mode 100644 index 0000000..a1901ff --- /dev/null +++ b/svg/open.svg @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/svg/pause_active.svg b/svg/pause_active.svg new file mode 100644 index 0000000..82b5bc3 --- /dev/null +++ b/svg/pause_active.svg @@ -0,0 +1,250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/svg/pause_inactive.svg b/svg/pause_inactive.svg new file mode 100644 index 0000000..1cde1b9 --- /dev/null +++ b/svg/pause_inactive.svg @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/svg/play_active.svg b/svg/play_active.svg new file mode 100644 index 0000000..6927296 --- /dev/null +++ b/svg/play_active.svg @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/svg/play_inactive.svg b/svg/play_inactive.svg new file mode 100644 index 0000000..dd0725b --- /dev/null +++ b/svg/play_inactive.svg @@ -0,0 +1,345 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/svg/playlist_active.svg b/svg/playlist_active.svg new file mode 100644 index 0000000..add08f8 --- /dev/null +++ b/svg/playlist_active.svg @@ -0,0 +1,720 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/svg/playlist_inactive.svg b/svg/playlist_inactive.svg new file mode 100644 index 0000000..0acf2c2 --- /dev/null +++ b/svg/playlist_inactive.svg @@ -0,0 +1,655 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/svg/prev.svg b/svg/prev.svg new file mode 100644 index 0000000..801f6b3 --- /dev/null +++ b/svg/prev.svg @@ -0,0 +1,338 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/svg/stop.svg b/svg/stop.svg new file mode 100644 index 0000000..d740ca2 --- /dev/null +++ b/svg/stop.svg @@ -0,0 +1,207 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file