clean structure
This commit is contained in:
+23
-19
@@ -26,20 +26,21 @@ pkg_check_modules(FFTW REQUIRED IMPORTED_TARGET fftw3)
|
||||
# sources
|
||||
set(SOURCES
|
||||
src/main.cpp
|
||||
src/MetadataReader.cpp
|
||||
src/Config.cpp
|
||||
src/MusicLibrary.cpp
|
||||
src/CoverArtWidget.cpp
|
||||
src/SpectrogramWidget.cpp
|
||||
src/GradientDialog.cpp
|
||||
src/EqualizerWidget.cpp
|
||||
src/TrackDelegate.cpp
|
||||
src/MainWindow.cpp
|
||||
src/config/Config.cpp
|
||||
|
||||
src/gui/CoverArtWidget.cpp
|
||||
src/gui/SpectrogramWidget.cpp
|
||||
src/gui/GradientDialog.cpp
|
||||
src/gui/EqualizerWidget.cpp
|
||||
src/gui/TrackDelegate.cpp
|
||||
src/gui/MainWindow.cpp
|
||||
|
||||
# engine
|
||||
src/engine/AudioEngine.cpp
|
||||
src/engine/EqProcessor.cpp
|
||||
src/engine/SpectrumAnalyzer.cpp
|
||||
src/engine/MusicLibrary.cpp
|
||||
src/engine/MetadataReader.cpp
|
||||
|
||||
# ffmpeg
|
||||
src/engine/ffmpeg/FormatContext.cpp
|
||||
@@ -55,22 +56,23 @@ set(SOURCES
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
src/Track.h
|
||||
src/MetadataReader.h
|
||||
src/Config.h
|
||||
src/MusicLibrary.h
|
||||
src/CoverArtWidget.h
|
||||
src/SpectrogramWidget.h
|
||||
src/GradientDialog.h
|
||||
src/EqualizerWidget.h
|
||||
src/TrackDelegate.h
|
||||
src/MainWindow.h
|
||||
src/config/Config.h
|
||||
|
||||
src/gui/CoverArtWidget.h
|
||||
src/gui/SpectrogramWidget.h
|
||||
src/gui/GradientDialog.h
|
||||
src/gui/EqualizerWidget.h
|
||||
src/gui/TrackDelegate.h
|
||||
src/gui/MainWindow.h
|
||||
|
||||
# engine
|
||||
src/engine/AudioEngine.h
|
||||
src/engine/EqProcessor.h
|
||||
src/engine/SpectrumAnalyzer.h
|
||||
src/engine/AudioBuffer.h
|
||||
src/engine/Track.h
|
||||
src/engine/MetadataReader.h
|
||||
src/engine/MusicLibrary.h
|
||||
|
||||
# ffmpeg wrapper
|
||||
src/engine/ffmpeg/FormatContext.h
|
||||
@@ -97,9 +99,11 @@ add_executable(SubWave ${SOURCES} ${HEADERS} ${RESOURCES})
|
||||
# headers
|
||||
target_include_directories(SubWave PRIVATE
|
||||
src
|
||||
src/config
|
||||
src/engine
|
||||
src/engine/ffmpeg
|
||||
src/playlists
|
||||
src/gui
|
||||
)
|
||||
|
||||
# link to qt and ffmpeg and fftw
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
#include "Track.h"
|
||||
|
||||
class MetadataReader {
|
||||
public:
|
||||
static void populate(Track &track);
|
||||
};
|
||||
@@ -27,7 +27,7 @@ void AudioEngine::setVolume(float v) {
|
||||
if (m_sink) m_sink->setVolume(m_volume);
|
||||
}
|
||||
|
||||
void AudioEngine::play(const Track &track) {
|
||||
void AudioEngine::play(const engine::Track &track) {
|
||||
stop();
|
||||
m_stopReq = false;
|
||||
m_pauseReq = false;
|
||||
@@ -197,3 +197,4 @@ void AudioEngine::playbackLoop() {
|
||||
if (natural)
|
||||
emit trackEnded();
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
int sampleRate() const;
|
||||
|
||||
void setVolume(float v);
|
||||
void play(const Track &track);
|
||||
void play(const engine::Track &track);
|
||||
void togglePause();
|
||||
void stop();
|
||||
void seekFraction(double fraction);
|
||||
@@ -68,7 +68,7 @@ private:
|
||||
QMutex m_pauseMtx;
|
||||
QWaitCondition m_pauseCv;
|
||||
|
||||
Track m_track;
|
||||
engine::Track m_track;
|
||||
engine::EqProcessor m_eq;
|
||||
|
||||
float m_eqGainDb[EQ_BANDS] {};
|
||||
|
||||
@@ -5,7 +5,9 @@ extern "C" {
|
||||
#include <libavutil/dict.h>
|
||||
}
|
||||
|
||||
void MetadataReader::populate(Track &track) {
|
||||
namespace engine {
|
||||
|
||||
void MetadataReader::populate(engine::Track &track) {
|
||||
AVFormatContext *fmt = nullptr;
|
||||
if (avformat_open_input(&fmt, track.filePath.toUtf8().constData(),
|
||||
nullptr, nullptr) < 0) return;
|
||||
@@ -74,4 +76,5 @@ void MetadataReader::populate(Track &track) {
|
||||
}
|
||||
|
||||
avformat_close_input(&fmt);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "Track.h"
|
||||
|
||||
namespace engine {
|
||||
|
||||
class MetadataReader {
|
||||
public:
|
||||
static void populate(engine::Track &track);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -3,9 +3,11 @@
|
||||
#include <QDirIterator>
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace engine {
|
||||
|
||||
MusicLibrary::MusicLibrary(QObject *parent) : QObject(parent) {}
|
||||
|
||||
const QList<Track> &MusicLibrary::tracks() const { return m_tracks; }
|
||||
const QList<engine::Track> &MusicLibrary::tracks() const { return m_tracks; }
|
||||
const QString &MusicLibrary::rootPath() const { return m_root; }
|
||||
|
||||
void MusicLibrary::setRootPath(const QString &path) { m_root = path; }
|
||||
@@ -27,7 +29,7 @@ void MusicLibrary::scan() {
|
||||
|
||||
while (it.hasNext() && !QThread::currentThread()->isInterruptionRequested()) {
|
||||
QString path = it.next();
|
||||
Track t;
|
||||
engine::Track t;
|
||||
t.filePath = path;
|
||||
QString ext = QFileInfo(path).suffix().toLower();
|
||||
t.format = ext.toUpper();
|
||||
@@ -48,7 +50,7 @@ void MusicLibrary::scan() {
|
||||
|
||||
void MusicLibrary::sortByArtistTitle() {
|
||||
QMutexLocker lk(&m_mtx);
|
||||
std::sort(m_tracks.begin(), m_tracks.end(), [](const Track &a, const Track &b){
|
||||
std::sort(m_tracks.begin(), m_tracks.end(), [](const engine::Track &a, const engine::Track &b){
|
||||
int c = a.artist.compare(b.artist, Qt::CaseInsensitive);
|
||||
return c != 0 ? c < 0 : a.title.compare(b.title, Qt::CaseInsensitive) < 0;
|
||||
});
|
||||
@@ -56,4 +58,6 @@ void MusicLibrary::sortByArtistTitle() {
|
||||
|
||||
void MusicLibrary::shutdown() {
|
||||
if (m_scanThread) { m_scanThread->requestInterruption(); m_scanThread->wait(); }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <QMutex>
|
||||
#include "Track.h"
|
||||
|
||||
namespace engine {
|
||||
|
||||
class MusicLibrary : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -12,7 +14,7 @@ public:
|
||||
{ "mp3", "flac", "wav", "ogg", "aac", "m4a", "opus", "wma" };
|
||||
|
||||
explicit MusicLibrary(QObject *parent = nullptr);
|
||||
const QList<Track> &tracks() const;
|
||||
const QList<engine::Track> &tracks() const;
|
||||
const QString &rootPath() const;
|
||||
void setRootPath(const QString &path);
|
||||
void scan();
|
||||
@@ -21,12 +23,14 @@ public:
|
||||
|
||||
signals:
|
||||
void scanStarted();
|
||||
void trackFound(const Track &track);
|
||||
void trackFound(const engine::Track &track);
|
||||
void scanComplete(int count);
|
||||
|
||||
private:
|
||||
QString m_root;
|
||||
QList<Track> m_tracks;
|
||||
QList<engine::Track> m_tracks;
|
||||
QThread *m_scanThread { nullptr };
|
||||
QMutex m_mtx;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <QImage>
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace engine {
|
||||
|
||||
struct Track {
|
||||
QString filePath;
|
||||
QString title;
|
||||
@@ -28,4 +30,6 @@ struct Track {
|
||||
QString toString() const {
|
||||
return artist + " \u2014 " + title;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@ CoverArtWidget::CoverArtWidget(QWidget *parent) : QWidget(parent) {
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
}
|
||||
|
||||
void CoverArtWidget::setTrack(const Track *t) {
|
||||
void CoverArtWidget::setTrack(const engine::Track *t) {
|
||||
m_cover = (t && !t->coverArt.isNull()) ? t->coverArt : QImage{};
|
||||
m_title = t ? t->displayTitle() : "No track";
|
||||
m_artist = t ? t->artist : QString{};
|
||||
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
#include <QWidget>
|
||||
#include <QImage>
|
||||
#include "Track.h"
|
||||
#include "engine/Track.h"
|
||||
|
||||
class CoverArtWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CoverArtWidget(QWidget *parent = nullptr);
|
||||
void setTrack(const Track *t);
|
||||
void setTrack(const engine::Track *t);
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
private:
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "MainWindow.h"
|
||||
#include "AudioEngine.h"
|
||||
#include "MusicLibrary.h"
|
||||
#include "engine/MusicLibrary.h"
|
||||
#include "PlaylistModel.h"
|
||||
#include "TrackDelegate.h"
|
||||
#include "CoverArtWidget.h"
|
||||
@@ -31,7 +31,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
setMinimumSize(700, 760);
|
||||
|
||||
m_engine = new AudioEngine(this);
|
||||
m_library = new MusicLibrary(this);
|
||||
m_library = new engine::MusicLibrary(this);
|
||||
m_model = new PlaylistModel(this);
|
||||
m_library->setRootPath(Config::loadMusicRoot());
|
||||
|
||||
@@ -258,7 +258,7 @@ void MainWindow::wireSignals()
|
||||
connect(m_engine, &AudioEngine::durationKnown,
|
||||
this, [this](qint64 secs){
|
||||
if (m_currentIndex >= 0) {
|
||||
Track *t = m_model->trackAt(m_currentIndex);
|
||||
engine::Track *t = m_model->trackAt(m_currentIndex);
|
||||
if (t && t->durationSecs == 0) {
|
||||
t->durationSecs = secs;
|
||||
m_model->refreshRow(m_currentIndex);
|
||||
@@ -267,15 +267,15 @@ void MainWindow::wireSignals()
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
// Library scanning
|
||||
connect(m_library, &MusicLibrary::scanStarted, this, [this]{
|
||||
connect(m_library, &engine::MusicLibrary::scanStarted, this, [this]{
|
||||
m_model->setTracks({});
|
||||
m_lblStatus->setText("Scanning...");
|
||||
});
|
||||
connect(m_library, &MusicLibrary::trackFound, this, [this](const Track &t){
|
||||
connect(m_library, &engine::MusicLibrary::trackFound, this, [this](const engine::Track &t){
|
||||
m_model->appendTrack(t);
|
||||
m_lblStatus->setText(QString("%1 tracks found").arg(m_model->rowCount({})));
|
||||
}, Qt::QueuedConnection);
|
||||
connect(m_library, &MusicLibrary::scanComplete, this, [this](int n){
|
||||
connect(m_library, &engine::MusicLibrary::scanComplete, this, [this](int n){
|
||||
m_model->setTracks(m_library->tracks()); // sorted version
|
||||
m_lblStatus->setText(QString("%1 tracks.").arg(n));
|
||||
}, Qt::QueuedConnection);
|
||||
@@ -290,7 +290,7 @@ void MainWindow::reloadLibrary()
|
||||
|
||||
void MainWindow::playTrack(int index)
|
||||
{
|
||||
Track *t = m_model->trackAt(index);
|
||||
engine::Track *t = m_model->trackAt(index);
|
||||
if (!t) return;
|
||||
m_currentIndex = index;
|
||||
m_model->setCurrentIndex(index);
|
||||
@@ -351,15 +351,14 @@ void MainWindow::onUiTimer()
|
||||
qint64 posF = m_engine->positionFrames();
|
||||
qint64 totF = m_engine->totalFrames();
|
||||
qint64 posSec = qint64(posF / sr);
|
||||
|
||||
engine::Track *currentTrack = (m_currentIndex >= 0) ? m_model->trackAt(m_currentIndex) : nullptr;
|
||||
qint64 totSec = totF > 0 ? qint64(totF / sr)
|
||||
: (m_currentIndex >= 0
|
||||
? (m_model->trackAt(m_currentIndex)
|
||||
? m_model->trackAt(m_currentIndex)->durationSecs : 0)
|
||||
: 0);
|
||||
: (currentTrack ? currentTrack->durationSecs : 0);
|
||||
|
||||
// Write back duration if we now know it
|
||||
if (totF > 0 && m_currentIndex >= 0) {
|
||||
Track *t = m_model->trackAt(m_currentIndex);
|
||||
engine::Track *t = m_model->trackAt(m_currentIndex);
|
||||
if (t && t->durationSecs == 0) {
|
||||
t->durationSecs = totSec;
|
||||
m_model->refreshRow(m_currentIndex);
|
||||
@@ -9,10 +9,13 @@
|
||||
#include <QTimer>
|
||||
#include <QTabWidget>
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout> // needed for buildTransportRow() return type
|
||||
#include <QHBoxLayout>
|
||||
|
||||
// Forward declarations
|
||||
class AudioEngine;
|
||||
class MusicLibrary;
|
||||
namespace engine {
|
||||
class MusicLibrary;
|
||||
}
|
||||
class PlaylistModel;
|
||||
class CoverArtWidget;
|
||||
class SpectrogramWidget;
|
||||
@@ -50,9 +53,9 @@ private:
|
||||
void loadPlaylistIntoModel(const QString &playlistName);
|
||||
|
||||
// Core
|
||||
AudioEngine *m_engine;
|
||||
MusicLibrary *m_library;
|
||||
PlaylistModel *m_model;
|
||||
AudioEngine *m_engine;
|
||||
engine::MusicLibrary *m_library;
|
||||
PlaylistModel *m_model;
|
||||
|
||||
// Transport – plain ASCII labels now
|
||||
QLabel *m_lblTitle = new QLabel("No track selected");
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "SpectrogramWidget.h"
|
||||
#include "GradientDialog.h"
|
||||
#include <QTimer>
|
||||
#include <QSurfaceFormat>
|
||||
#include <QFile>
|
||||
#include <QMouseEvent>
|
||||
@@ -27,10 +28,15 @@ SpectrogramWidget::SpectrogramWidget(QWidget *parent)
|
||||
setMinimumSize(400, 200);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
|
||||
m_barHeights .resize(BAR_COUNT);
|
||||
m_barHeights.resize(BAR_COUNT);
|
||||
m_barPeaksVec.resize(BAR_COUNT);
|
||||
|
||||
loadBarColors();
|
||||
loadBarColors();
|
||||
|
||||
auto *timer = new QTimer(this);
|
||||
connect(timer, &QTimer::timeout,
|
||||
this, QOverload<>::of(&SpectrogramWidget::update));
|
||||
timer->start(16);
|
||||
}
|
||||
|
||||
SpectrogramWidget::~SpectrogramWidget()
|
||||
@@ -287,6 +293,4 @@ void SpectrogramWidget::paintGL()
|
||||
glBindVertexArray(0);
|
||||
m_barsProg.release();
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
@@ -77,7 +77,7 @@ void PlaylistCreatorDialog::onAddFiles()
|
||||
|
||||
// Check if already in playlist
|
||||
bool alreadyAdded = false;
|
||||
for (const Track &t : m_playlist.tracks) {
|
||||
for (const engine::Track &t : m_playlist.tracks) {
|
||||
if (t.filePath == filePath) {
|
||||
alreadyAdded = true;
|
||||
break;
|
||||
@@ -85,7 +85,7 @@ void PlaylistCreatorDialog::onAddFiles()
|
||||
}
|
||||
|
||||
if (!alreadyAdded) {
|
||||
Track track;
|
||||
engine::Track track;
|
||||
track.filePath = filePath;
|
||||
|
||||
// Set default metadata
|
||||
@@ -96,7 +96,7 @@ void PlaylistCreatorDialog::onAddFiles()
|
||||
track.album = "Unknown Album";
|
||||
|
||||
// Extract actual metadata and cover art
|
||||
MetadataReader::populate(track);
|
||||
engine::MetadataReader::populate(track);
|
||||
|
||||
m_playlist.tracks.append(track);
|
||||
}
|
||||
@@ -145,7 +145,7 @@ void PlaylistCreatorDialog::updateTrackList()
|
||||
{
|
||||
m_trackList->clear();
|
||||
|
||||
for (const Track &track : m_playlist.tracks) {
|
||||
for (const engine::Track &track : m_playlist.tracks) {
|
||||
QString display = track.displayTitle();
|
||||
if (!track.artist.isEmpty()) {
|
||||
display = track.artist + " - " + display;
|
||||
|
||||
@@ -111,7 +111,7 @@ QStringList PlaylistManager::listPlaylists()
|
||||
return result;
|
||||
}
|
||||
|
||||
void PlaylistManager::addTrackToPlaylist(Playlist &playlist, const Track &track)
|
||||
void PlaylistManager::addTrackToPlaylist(Playlist &playlist, const engine::Track &track)
|
||||
{
|
||||
playlist.tracks.append(track);
|
||||
}
|
||||
@@ -144,7 +144,7 @@ PlaylistManager::Playlist PlaylistManager::parsePlaylistJson(const QString &json
|
||||
for (int i = 0; i < tracksArray.size(); ++i) {
|
||||
QJsonObject trackObj = tracksArray[i].toObject();
|
||||
|
||||
Track track;
|
||||
engine::Track track;
|
||||
track.filePath = trackObj["filePath"].toString();
|
||||
track.title = trackObj["title"].toString();
|
||||
track.artist = trackObj["artist"].toString();
|
||||
@@ -157,7 +157,7 @@ PlaylistManager::Playlist PlaylistManager::parsePlaylistJson(const QString &json
|
||||
if (!track.filePath.isEmpty()) {
|
||||
// Re-extract metadata and cover art from the file
|
||||
// in case it has changed or cover art wasn't saved
|
||||
MetadataReader::populate(track);
|
||||
engine::MetadataReader::populate(track);
|
||||
playlist.tracks.append(track);
|
||||
}
|
||||
}
|
||||
@@ -171,7 +171,7 @@ QString PlaylistManager::playlistToJson(const Playlist &playlist)
|
||||
QJsonObject root;
|
||||
QJsonArray tracksArray;
|
||||
|
||||
for (const Track &track : playlist.tracks) {
|
||||
for (const engine::Track &track : playlist.tracks) {
|
||||
QJsonObject trackObj;
|
||||
trackObj["filePath"] = track.filePath;
|
||||
trackObj["title"] = track.title;
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include "Track.h"
|
||||
#include "engine/Track.h"
|
||||
|
||||
class PlaylistManager {
|
||||
public:
|
||||
struct Playlist {
|
||||
QString name;
|
||||
QList<Track> tracks;
|
||||
QList<engine::Track> tracks;
|
||||
QString filePath;
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
static QStringList listPlaylists();
|
||||
|
||||
// Track management
|
||||
static void addTrackToPlaylist(Playlist &playlist, const Track &track);
|
||||
static void addTrackToPlaylist(Playlist &playlist, const engine::Track &track);
|
||||
static void removeTrackFromPlaylist(Playlist &playlist, int index);
|
||||
static void clearPlaylist(Playlist &playlist);
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
PlaylistModel::PlaylistModel(QObject *parent)
|
||||
: QAbstractListModel(parent) {}
|
||||
|
||||
void PlaylistModel::setTracks(const QList<Track> &tracks) {
|
||||
void PlaylistModel::setTracks(const QList<engine::Track> &tracks) {
|
||||
beginResetModel();
|
||||
m_tracks = tracks;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void PlaylistModel::appendTrack(const Track &t) {
|
||||
void PlaylistModel::appendTrack(const engine::Track &t) {
|
||||
beginInsertRows({}, m_tracks.size(), m_tracks.size());
|
||||
m_tracks.append(t);
|
||||
endInsertRows();
|
||||
@@ -27,11 +27,17 @@ void PlaylistModel::refreshRow(int idx) {
|
||||
emit dataChanged(index(idx), index(idx));
|
||||
}
|
||||
|
||||
Track *PlaylistModel::trackAt(int idx) {
|
||||
engine::Track *PlaylistModel::trackAt(int idx) {
|
||||
if (idx < 0 || idx >= m_tracks.size()) return nullptr;
|
||||
return &m_tracks[idx];
|
||||
}
|
||||
|
||||
const engine::Track &PlaylistModel::trackAt(int idx) const {
|
||||
static const engine::Track s_invalid;
|
||||
if (idx < 0 || idx >= m_tracks.size()) return s_invalid;
|
||||
return m_tracks[idx];
|
||||
}
|
||||
|
||||
int PlaylistModel::rowCount(const QModelIndex &) const {
|
||||
return m_tracks.size();
|
||||
}
|
||||
@@ -39,7 +45,7 @@ int PlaylistModel::rowCount(const QModelIndex &) const {
|
||||
QVariant PlaylistModel::data(const QModelIndex &idx, int role) const {
|
||||
if (!idx.isValid() || idx.row() >= m_tracks.size())
|
||||
return {};
|
||||
const Track &t = m_tracks[idx.row()];
|
||||
const engine::Track &t = m_tracks[idx.row()];
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return t.displayTitle();
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
#pragma once
|
||||
#include <QAbstractListModel>
|
||||
#include <QList>
|
||||
#include "Track.h"
|
||||
#include "engine/Track.h"
|
||||
|
||||
class PlaylistModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PlaylistModel(QObject *parent=nullptr);
|
||||
void setTracks(const QList<Track> &tracks);
|
||||
void appendTrack(const Track &t);
|
||||
void setTracks(const QList<engine::Track> &tracks);
|
||||
void appendTrack(const engine::Track &t);
|
||||
void setCurrentIndex(int idx);
|
||||
void refreshRow(int idx);
|
||||
Track *trackAt(int idx);
|
||||
engine::Track *trackAt(int idx);
|
||||
const engine::Track &trackAt(int idx) const;
|
||||
int rowCount(const QModelIndex &) const override;
|
||||
QVariant data(const QModelIndex &idx, int role) const override;
|
||||
int currentIndex() const;
|
||||
|
||||
private:
|
||||
QList<Track> m_tracks;
|
||||
QList<engine::Track> m_tracks;
|
||||
int m_current { -1 };
|
||||
};
|
||||
Reference in New Issue
Block a user