Reformat
This commit is contained in:
parent
10769eef09
commit
58e8345542
20 changed files with 2063 additions and 1901 deletions
|
|
@ -55,3 +55,13 @@ target_include_directories(${PROJECT_NAME} PRIVATE
|
|||
)
|
||||
|
||||
# Note: acestep.cpp binaries (ace-qwen3, dit-vae) and models should be provided at runtime
|
||||
|
||||
# Install targets
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION bin)
|
||||
|
||||
# Install .desktop file
|
||||
install(FILES aceradio.desktop DESTINATION share/applications)
|
||||
|
||||
# Install icon files
|
||||
install(FILES res/xyz.uvos.aceradio.png DESTINATION share/icons/hicolor/256x256/apps RENAME xyz.uvos.aceradio.png)
|
||||
install(FILES res/xyz.uvos.aceradio.svg DESTINATION share/icons/hicolor/scalable/apps RENAME xyz.uvos.aceradio.svg)
|
||||
|
|
|
|||
|
|
@ -11,44 +11,46 @@
|
|||
#include <cstdint>
|
||||
|
||||
AceStepWorker::AceStepWorker(QObject *parent)
|
||||
: QObject(parent),
|
||||
currentWorker(nullptr)
|
||||
: QObject(parent),
|
||||
currentWorker(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
AceStepWorker::~AceStepWorker()
|
||||
{
|
||||
cancelGeneration();
|
||||
cancelGeneration();
|
||||
}
|
||||
|
||||
void AceStepWorker::generateSong(const SongItem& song, const QString &jsonTemplate,
|
||||
const QString &aceStepPath, const QString &qwen3ModelPath,
|
||||
const QString &textEncoderModelPath, const QString &ditModelPath,
|
||||
const QString &vaeModelPath)
|
||||
const QString &aceStepPath, const QString &qwen3ModelPath,
|
||||
const QString &textEncoderModelPath, const QString &ditModelPath,
|
||||
const QString &vaeModelPath)
|
||||
{
|
||||
// Cancel any ongoing generation
|
||||
cancelGeneration();
|
||||
// Cancel any ongoing generation
|
||||
cancelGeneration();
|
||||
|
||||
// Create worker and start it
|
||||
currentWorker = new Worker(this, song, jsonTemplate, aceStepPath, qwen3ModelPath,
|
||||
textEncoderModelPath, ditModelPath, vaeModelPath);
|
||||
// Create worker and start it
|
||||
currentWorker = new Worker(this, song, jsonTemplate, aceStepPath, qwen3ModelPath,
|
||||
textEncoderModelPath, ditModelPath, vaeModelPath);
|
||||
currentWorker->setAutoDelete(true);
|
||||
QThreadPool::globalInstance()->start(currentWorker);
|
||||
QThreadPool::globalInstance()->start(currentWorker);
|
||||
}
|
||||
|
||||
void AceStepWorker::cancelGeneration()
|
||||
{
|
||||
currentWorker = nullptr;
|
||||
currentWorker = nullptr;
|
||||
}
|
||||
|
||||
bool AceStepWorker::songGenerateing(SongItem* song)
|
||||
{
|
||||
workerMutex.lock();
|
||||
if(!currentWorker) {
|
||||
if(!currentWorker)
|
||||
{
|
||||
workerMutex.unlock();
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
SongItem workerSong = currentWorker->getSong();
|
||||
workerMutex.unlock();
|
||||
if(song)
|
||||
|
|
@ -60,186 +62,209 @@ bool AceStepWorker::songGenerateing(SongItem* song)
|
|||
// Worker implementation
|
||||
void AceStepWorker::Worker::run()
|
||||
{
|
||||
uint64_t uid = QRandomGenerator::global()->generate();
|
||||
// Create temporary JSON file for the request
|
||||
QString tempDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
|
||||
QString requestFile = tempDir + "/request_" + QString::number(uid) + ".json";
|
||||
uint64_t uid = QRandomGenerator::global()->generate();
|
||||
// Create temporary JSON file for the request
|
||||
QString tempDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
|
||||
QString requestFile = tempDir + "/request_" + QString::number(uid) + ".json";
|
||||
|
||||
// Parse and modify the template
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument templateDoc = QJsonDocument::fromJson(jsonTemplate.toUtf8(), &parseError);
|
||||
if (!templateDoc.isObject()) {
|
||||
emit parent->generationError("Invalid JSON template: " + QString(parseError.errorString()));
|
||||
return;
|
||||
}
|
||||
// Parse and modify the template
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument templateDoc = QJsonDocument::fromJson(jsonTemplate.toUtf8(), &parseError);
|
||||
if (!templateDoc.isObject())
|
||||
{
|
||||
emit parent->generationError("Invalid JSON template: " + QString(parseError.errorString()));
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject requestObj = templateDoc.object();
|
||||
QJsonObject requestObj = templateDoc.object();
|
||||
requestObj["caption"] = song.caption;
|
||||
|
||||
if (!song.lyrics.isEmpty()) {
|
||||
if (!song.lyrics.isEmpty())
|
||||
{
|
||||
requestObj["lyrics"] = song.lyrics;
|
||||
} else {
|
||||
// Remove lyrics field if empty to let the LLM generate them
|
||||
requestObj.remove("lyrics");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove lyrics field if empty to let the LLM generate them
|
||||
requestObj.remove("lyrics");
|
||||
}
|
||||
|
||||
// Apply vocal language override if set
|
||||
if (!song.vocalLanguage.isEmpty()) {
|
||||
requestObj["vocal_language"] = song.vocalLanguage;
|
||||
}
|
||||
// Apply vocal language override if set
|
||||
if (!song.vocalLanguage.isEmpty())
|
||||
{
|
||||
requestObj["vocal_language"] = song.vocalLanguage;
|
||||
}
|
||||
|
||||
// Write the request file
|
||||
QFile requestFileHandle(requestFile);
|
||||
if (!requestFileHandle.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
emit parent->generationError("Failed to create request file: " + requestFileHandle.errorString());
|
||||
return;
|
||||
}
|
||||
// Write the request file
|
||||
QFile requestFileHandle(requestFile);
|
||||
if (!requestFileHandle.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
{
|
||||
emit parent->generationError("Failed to create request file: " + requestFileHandle.errorString());
|
||||
return;
|
||||
}
|
||||
|
||||
requestFileHandle.write(QJsonDocument(requestObj).toJson(QJsonDocument::Indented));
|
||||
requestFileHandle.close();
|
||||
requestFileHandle.write(QJsonDocument(requestObj).toJson(QJsonDocument::Indented));
|
||||
requestFileHandle.close();
|
||||
|
||||
// Use provided paths for acestep.cpp binaries
|
||||
QString qwen3Binary = this->aceStepPath + "/ace-qwen3";
|
||||
QString ditVaeBinary = this->aceStepPath + "/dit-vae";
|
||||
// Use provided paths for acestep.cpp binaries
|
||||
QString qwen3Binary = this->aceStepPath + "/ace-qwen3";
|
||||
QString ditVaeBinary = this->aceStepPath + "/dit-vae";
|
||||
|
||||
// Check if binaries exist
|
||||
QFileInfo qwen3Info(qwen3Binary);
|
||||
QFileInfo ditVaeInfo(ditVaeBinary);
|
||||
// Check if binaries exist
|
||||
QFileInfo qwen3Info(qwen3Binary);
|
||||
QFileInfo ditVaeInfo(ditVaeBinary);
|
||||
|
||||
if (!qwen3Info.exists() || !qwen3Info.isExecutable()) {
|
||||
emit parent->generationError("ace-qwen3 binary not found at: " + qwen3Binary);
|
||||
return;
|
||||
}
|
||||
if (!qwen3Info.exists() || !qwen3Info.isExecutable())
|
||||
{
|
||||
emit parent->generationError("ace-qwen3 binary not found at: " + qwen3Binary);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ditVaeInfo.exists() || !ditVaeInfo.isExecutable()) {
|
||||
emit parent->generationError("dit-vae binary not found at: " + ditVaeBinary);
|
||||
return;
|
||||
}
|
||||
if (!ditVaeInfo.exists() || !ditVaeInfo.isExecutable())
|
||||
{
|
||||
emit parent->generationError("dit-vae binary not found at: " + ditVaeBinary);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use provided model paths
|
||||
QString qwen3Model = this->qwen3ModelPath;
|
||||
QString textEncoderModel = this->textEncoderModelPath;
|
||||
QString ditModel = this->ditModelPath;
|
||||
QString vaeModel = this->vaeModelPath;
|
||||
// Use provided model paths
|
||||
QString qwen3Model = this->qwen3ModelPath;
|
||||
QString textEncoderModel = this->textEncoderModelPath;
|
||||
QString ditModel = this->ditModelPath;
|
||||
QString vaeModel = this->vaeModelPath;
|
||||
|
||||
if (!QFileInfo::exists(qwen3Model)) {
|
||||
emit parent->generationError("Qwen3 model not found: " + qwen3Model);
|
||||
return;
|
||||
}
|
||||
if (!QFileInfo::exists(qwen3Model))
|
||||
{
|
||||
emit parent->generationError("Qwen3 model not found: " + qwen3Model);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!QFileInfo::exists(textEncoderModel)) {
|
||||
emit parent->generationError("Text encoder model not found: " + textEncoderModel);
|
||||
return;
|
||||
}
|
||||
if (!QFileInfo::exists(textEncoderModel))
|
||||
{
|
||||
emit parent->generationError("Text encoder model not found: " + textEncoderModel);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!QFileInfo::exists(ditModel)) {
|
||||
emit parent->generationError("DiT model not found: " + ditModel);
|
||||
return;
|
||||
}
|
||||
if (!QFileInfo::exists(ditModel))
|
||||
{
|
||||
emit parent->generationError("DiT model not found: " + ditModel);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!QFileInfo::exists(vaeModel)) {
|
||||
emit parent->generationError("VAE model not found: " + vaeModel);
|
||||
return;
|
||||
}
|
||||
if (!QFileInfo::exists(vaeModel))
|
||||
{
|
||||
emit parent->generationError("VAE model not found: " + vaeModel);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 1: Run ace-qwen3 to generate lyrics and audio codes
|
||||
QProcess qwen3Process;
|
||||
QStringList qwen3Args;
|
||||
qwen3Args << "--request" << requestFile;
|
||||
qwen3Args << "--model" << qwen3Model;
|
||||
// Step 1: Run ace-qwen3 to generate lyrics and audio codes
|
||||
QProcess qwen3Process;
|
||||
QStringList qwen3Args;
|
||||
qwen3Args << "--request" << requestFile;
|
||||
qwen3Args << "--model" << qwen3Model;
|
||||
|
||||
emit parent->progressUpdate(20);
|
||||
emit parent->progressUpdate(20);
|
||||
|
||||
qwen3Process.start(qwen3Binary, qwen3Args);
|
||||
if (!qwen3Process.waitForStarted()) {
|
||||
emit parent->generationError("Failed to start ace-qwen3: " + qwen3Process.errorString());
|
||||
return;
|
||||
}
|
||||
qwen3Process.start(qwen3Binary, qwen3Args);
|
||||
if (!qwen3Process.waitForStarted())
|
||||
{
|
||||
emit parent->generationError("Failed to start ace-qwen3: " + qwen3Process.errorString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!qwen3Process.waitForFinished(60000)) { // 60 second timeout
|
||||
qwen3Process.terminate();
|
||||
qwen3Process.waitForFinished(5000);
|
||||
emit parent->generationError("ace-qwen3 timed out after 60 seconds");
|
||||
return;
|
||||
}
|
||||
if (!qwen3Process.waitForFinished(60000)) // 60 second timeout
|
||||
{
|
||||
qwen3Process.terminate();
|
||||
qwen3Process.waitForFinished(5000);
|
||||
emit parent->generationError("ace-qwen3 timed out after 60 seconds");
|
||||
return;
|
||||
}
|
||||
|
||||
int exitCode = qwen3Process.exitCode();
|
||||
if (exitCode != 0) {
|
||||
QString errorOutput = qwen3Process.readAllStandardError();
|
||||
emit parent->generationError("ace-qwen3 exited with code " + QString::number(exitCode) + ": " + errorOutput);
|
||||
return;
|
||||
}
|
||||
int exitCode = qwen3Process.exitCode();
|
||||
if (exitCode != 0)
|
||||
{
|
||||
QString errorOutput = qwen3Process.readAllStandardError();
|
||||
emit parent->generationError("ace-qwen3 exited with code " + QString::number(exitCode) + ": " + errorOutput);
|
||||
return;
|
||||
}
|
||||
|
||||
QString requestLmOutputFile = tempDir + "/request_" + QString::number(uid) + "0.json";
|
||||
if (!QFileInfo::exists(requestLmOutputFile)) {
|
||||
emit parent->generationError("ace-qwen3 failed to create enhaced request file "+requestLmOutputFile);
|
||||
return;
|
||||
}
|
||||
QString requestLmOutputFile = tempDir + "/request_" + QString::number(uid) + "0.json";
|
||||
if (!QFileInfo::exists(requestLmOutputFile))
|
||||
{
|
||||
emit parent->generationError("ace-qwen3 failed to create enhaced request file "+requestLmOutputFile);
|
||||
return;
|
||||
}
|
||||
|
||||
// Load lyrics from the enhanced request file
|
||||
QFile lmOutputFile(requestLmOutputFile);
|
||||
if (lmOutputFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QJsonParseError parseError;
|
||||
song.json = lmOutputFile.readAll();
|
||||
QJsonDocument doc = QJsonDocument::fromJson(song.json.toUtf8(), &parseError);
|
||||
lmOutputFile.close();
|
||||
// Load lyrics from the enhanced request file
|
||||
QFile lmOutputFile(requestLmOutputFile);
|
||||
if (lmOutputFile.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
QJsonParseError parseError;
|
||||
song.json = lmOutputFile.readAll();
|
||||
QJsonDocument doc = QJsonDocument::fromJson(song.json.toUtf8(), &parseError);
|
||||
lmOutputFile.close();
|
||||
|
||||
if (doc.isObject() && !parseError.error) {
|
||||
QJsonObject obj = doc.object();
|
||||
if (obj.contains("lyrics") && obj["lyrics"].isString()) {
|
||||
song.lyrics = obj["lyrics"].toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (doc.isObject() && !parseError.error)
|
||||
{
|
||||
QJsonObject obj = doc.object();
|
||||
if (obj.contains("lyrics") && obj["lyrics"].isString())
|
||||
{
|
||||
song.lyrics = obj["lyrics"].toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit parent->progressUpdate(50);
|
||||
emit parent->progressUpdate(50);
|
||||
|
||||
// Step 2: Run dit-vae to generate audio
|
||||
QProcess ditVaeProcess;
|
||||
QStringList ditVaeArgs;
|
||||
ditVaeArgs << "--request" << requestLmOutputFile;
|
||||
ditVaeArgs << "--text-encoder" << textEncoderModel;
|
||||
ditVaeArgs << "--dit" << ditModel;
|
||||
ditVaeArgs << "--vae" << vaeModel;
|
||||
// Step 2: Run dit-vae to generate audio
|
||||
QProcess ditVaeProcess;
|
||||
QStringList ditVaeArgs;
|
||||
ditVaeArgs << "--request" << requestLmOutputFile;
|
||||
ditVaeArgs << "--text-encoder" << textEncoderModel;
|
||||
ditVaeArgs << "--dit" << ditModel;
|
||||
ditVaeArgs << "--vae" << vaeModel;
|
||||
|
||||
emit parent->progressUpdate(60);
|
||||
emit parent->progressUpdate(60);
|
||||
|
||||
ditVaeProcess.start(ditVaeBinary, ditVaeArgs);
|
||||
if (!ditVaeProcess.waitForStarted()) {
|
||||
emit parent->generationError("Failed to start dit-vae: " + ditVaeProcess.errorString());
|
||||
return;
|
||||
}
|
||||
ditVaeProcess.start(ditVaeBinary, ditVaeArgs);
|
||||
if (!ditVaeProcess.waitForStarted())
|
||||
{
|
||||
emit parent->generationError("Failed to start dit-vae: " + ditVaeProcess.errorString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ditVaeProcess.waitForFinished(120000)) { // 2 minute timeout
|
||||
ditVaeProcess.terminate();
|
||||
ditVaeProcess.waitForFinished(5000);
|
||||
emit parent->generationError("dit-vae timed out after 2 minutes");
|
||||
return;
|
||||
}
|
||||
if (!ditVaeProcess.waitForFinished(120000)) // 2 minute timeout
|
||||
{
|
||||
ditVaeProcess.terminate();
|
||||
ditVaeProcess.waitForFinished(5000);
|
||||
emit parent->generationError("dit-vae timed out after 2 minutes");
|
||||
return;
|
||||
}
|
||||
|
||||
exitCode = ditVaeProcess.exitCode();
|
||||
if (exitCode != 0) {
|
||||
QString errorOutput = ditVaeProcess.readAllStandardError();
|
||||
emit parent->generationError("dit-vae exited with code " + QString::number(exitCode) + ": " + errorOutput);
|
||||
return;
|
||||
}
|
||||
exitCode = ditVaeProcess.exitCode();
|
||||
if (exitCode != 0)
|
||||
{
|
||||
QString errorOutput = ditVaeProcess.readAllStandardError();
|
||||
emit parent->generationError("dit-vae exited with code " + QString::number(exitCode) + ": " + errorOutput);
|
||||
return;
|
||||
}
|
||||
|
||||
emit parent->progressUpdate(90);
|
||||
emit parent->progressUpdate(90);
|
||||
|
||||
// Find the generated WAV file
|
||||
QString wavFile = QFileInfo(requestFile).absolutePath()+"/request_" + QString::number(uid) + "00.wav";
|
||||
if (!QFileInfo::exists(wavFile)) {
|
||||
emit parent->generationError("No WAV file generated at "+wavFile);
|
||||
return;
|
||||
}
|
||||
// Find the generated WAV file
|
||||
QString wavFile = QFileInfo(requestFile).absolutePath()+"/request_" + QString::number(uid) + "00.wav";
|
||||
if (!QFileInfo::exists(wavFile))
|
||||
{
|
||||
emit parent->generationError("No WAV file generated at "+wavFile);
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up temporary files
|
||||
QFile::remove(requestLmOutputFile);
|
||||
QFile::remove(requestFile);
|
||||
// Clean up temporary files
|
||||
QFile::remove(requestLmOutputFile);
|
||||
QFile::remove(requestFile);
|
||||
|
||||
emit parent->progressUpdate(100);
|
||||
song.file = wavFile;
|
||||
emit parent->songGenerated(song);
|
||||
emit parent->progressUpdate(100);
|
||||
song.file = wavFile;
|
||||
emit parent->songGenerated(song);
|
||||
parent->workerMutex.lock();
|
||||
parent->currentWorker = nullptr;
|
||||
parent->workerMutex.unlock();
|
||||
|
|
|
|||
|
|
@ -12,53 +12,54 @@
|
|||
|
||||
class AceStepWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AceStepWorker(QObject *parent = nullptr);
|
||||
~AceStepWorker();
|
||||
explicit AceStepWorker(QObject *parent = nullptr);
|
||||
~AceStepWorker();
|
||||
|
||||
void generateSong(const SongItem& song, const QString &jsonTemplate,
|
||||
const QString &aceStepPath, const QString &qwen3ModelPath,
|
||||
const QString &textEncoderModelPath, const QString &ditModelPath,
|
||||
const QString &vaeModelPath);
|
||||
void cancelGeneration();
|
||||
void generateSong(const SongItem& song, const QString &jsonTemplate,
|
||||
const QString &aceStepPath, const QString &qwen3ModelPath,
|
||||
const QString &textEncoderModelPath, const QString &ditModelPath,
|
||||
const QString &vaeModelPath);
|
||||
void cancelGeneration();
|
||||
bool songGenerateing(SongItem* song);
|
||||
|
||||
signals:
|
||||
void songGenerated(const SongItem& song);
|
||||
void generationFinished();
|
||||
void generationError(const QString &error);
|
||||
void songGenerated(const SongItem& song);
|
||||
void generationFinished();
|
||||
void generationError(const QString &error);
|
||||
void progressUpdate(int percent);
|
||||
|
||||
private:
|
||||
class Worker : public QRunnable {
|
||||
public:
|
||||
Worker(AceStepWorker *parent, const SongItem& song, const QString &jsonTemplate,
|
||||
const QString &aceStepPath, const QString &qwen3ModelPath,
|
||||
const QString &textEncoderModelPath, const QString &ditModelPath,
|
||||
const QString &vaeModelPath)
|
||||
: parent(parent), song(song), jsonTemplate(jsonTemplate),
|
||||
aceStepPath(aceStepPath), qwen3ModelPath(qwen3ModelPath),
|
||||
textEncoderModelPath(textEncoderModelPath), ditModelPath(ditModelPath),
|
||||
vaeModelPath(vaeModelPath) {}
|
||||
class Worker : public QRunnable
|
||||
{
|
||||
public:
|
||||
Worker(AceStepWorker *parent, const SongItem& song, const QString &jsonTemplate,
|
||||
const QString &aceStepPath, const QString &qwen3ModelPath,
|
||||
const QString &textEncoderModelPath, const QString &ditModelPath,
|
||||
const QString &vaeModelPath)
|
||||
: parent(parent), song(song), jsonTemplate(jsonTemplate),
|
||||
aceStepPath(aceStepPath), qwen3ModelPath(qwen3ModelPath),
|
||||
textEncoderModelPath(textEncoderModelPath), ditModelPath(ditModelPath),
|
||||
vaeModelPath(vaeModelPath) {}
|
||||
|
||||
void run() override;
|
||||
void run() override;
|
||||
|
||||
const SongItem& getSong();
|
||||
|
||||
private:
|
||||
AceStepWorker *parent;
|
||||
SongItem song;
|
||||
QString jsonTemplate;
|
||||
QString aceStepPath;
|
||||
QString qwen3ModelPath;
|
||||
QString textEncoderModelPath;
|
||||
QString ditModelPath;
|
||||
QString vaeModelPath;
|
||||
};
|
||||
private:
|
||||
AceStepWorker *parent;
|
||||
SongItem song;
|
||||
QString jsonTemplate;
|
||||
QString aceStepPath;
|
||||
QString qwen3ModelPath;
|
||||
QString textEncoderModelPath;
|
||||
QString ditModelPath;
|
||||
QString vaeModelPath;
|
||||
};
|
||||
|
||||
QMutex workerMutex;
|
||||
Worker *currentWorker;
|
||||
Worker *currentWorker;
|
||||
};
|
||||
|
||||
#endif // ACESTEPWORKER_H
|
||||
|
|
|
|||
|
|
@ -6,113 +6,120 @@
|
|||
#include <QJsonParseError>
|
||||
|
||||
AdvancedSettingsDialog::AdvancedSettingsDialog(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
ui(new Ui::AdvancedSettingsDialog)
|
||||
: QDialog(parent),
|
||||
ui(new Ui::AdvancedSettingsDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
AdvancedSettingsDialog::~AdvancedSettingsDialog()
|
||||
{
|
||||
delete ui;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
QString AdvancedSettingsDialog::getJsonTemplate() const
|
||||
{
|
||||
return ui->jsonTemplateEdit->toPlainText();
|
||||
return ui->jsonTemplateEdit->toPlainText();
|
||||
}
|
||||
|
||||
QString AdvancedSettingsDialog::getAceStepPath() const
|
||||
{
|
||||
return ui->aceStepPathEdit->text();
|
||||
return ui->aceStepPathEdit->text();
|
||||
}
|
||||
|
||||
QString AdvancedSettingsDialog::getQwen3ModelPath() const
|
||||
{
|
||||
return ui->qwen3ModelEdit->text();
|
||||
return ui->qwen3ModelEdit->text();
|
||||
}
|
||||
|
||||
QString AdvancedSettingsDialog::getTextEncoderModelPath() const
|
||||
{
|
||||
return ui->textEncoderEdit->text();
|
||||
return ui->textEncoderEdit->text();
|
||||
}
|
||||
|
||||
QString AdvancedSettingsDialog::getDiTModelPath() const
|
||||
{
|
||||
return ui->ditModelEdit->text();
|
||||
return ui->ditModelEdit->text();
|
||||
}
|
||||
|
||||
QString AdvancedSettingsDialog::getVAEModelPath() const
|
||||
{
|
||||
return ui->vaeModelEdit->text();
|
||||
return ui->vaeModelEdit->text();
|
||||
}
|
||||
|
||||
void AdvancedSettingsDialog::setJsonTemplate(const QString &templateStr)
|
||||
{
|
||||
ui->jsonTemplateEdit->setPlainText(templateStr);
|
||||
ui->jsonTemplateEdit->setPlainText(templateStr);
|
||||
}
|
||||
|
||||
void AdvancedSettingsDialog::setAceStepPath(const QString &path)
|
||||
{
|
||||
ui->aceStepPathEdit->setText(path);
|
||||
ui->aceStepPathEdit->setText(path);
|
||||
}
|
||||
|
||||
void AdvancedSettingsDialog::setQwen3ModelPath(const QString &path)
|
||||
{
|
||||
ui->qwen3ModelEdit->setText(path);
|
||||
ui->qwen3ModelEdit->setText(path);
|
||||
}
|
||||
|
||||
void AdvancedSettingsDialog::setTextEncoderModelPath(const QString &path)
|
||||
{
|
||||
ui->textEncoderEdit->setText(path);
|
||||
ui->textEncoderEdit->setText(path);
|
||||
}
|
||||
|
||||
void AdvancedSettingsDialog::setDiTModelPath(const QString &path)
|
||||
{
|
||||
ui->ditModelEdit->setText(path);
|
||||
ui->ditModelEdit->setText(path);
|
||||
}
|
||||
|
||||
void AdvancedSettingsDialog::setVAEModelPath(const QString &path)
|
||||
{
|
||||
ui->vaeModelEdit->setText(path);
|
||||
ui->vaeModelEdit->setText(path);
|
||||
}
|
||||
|
||||
void AdvancedSettingsDialog::on_aceStepBrowseButton_clicked()
|
||||
{
|
||||
QString dir = QFileDialog::getExistingDirectory(this, "Select AceStep Build Directory", ui->aceStepPathEdit->text());
|
||||
if (!dir.isEmpty()) {
|
||||
ui->aceStepPathEdit->setText(dir);
|
||||
}
|
||||
QString dir = QFileDialog::getExistingDirectory(this, "Select AceStep Build Directory", ui->aceStepPathEdit->text());
|
||||
if (!dir.isEmpty())
|
||||
{
|
||||
ui->aceStepPathEdit->setText(dir);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvancedSettingsDialog::on_qwen3BrowseButton_clicked()
|
||||
{
|
||||
QString file = QFileDialog::getOpenFileName(this, "Select Qwen3 Model", ui->qwen3ModelEdit->text(), "GGUF Files (*.gguf)");
|
||||
if (!file.isEmpty()) {
|
||||
ui->qwen3ModelEdit->setText(file);
|
||||
}
|
||||
QString file = QFileDialog::getOpenFileName(this, "Select Qwen3 Model", ui->qwen3ModelEdit->text(),
|
||||
"GGUF Files (*.gguf)");
|
||||
if (!file.isEmpty())
|
||||
{
|
||||
ui->qwen3ModelEdit->setText(file);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvancedSettingsDialog::on_textEncoderBrowseButton_clicked()
|
||||
{
|
||||
QString file = QFileDialog::getOpenFileName(this, "Select Text Encoder Model", ui->textEncoderEdit->text(), "GGUF Files (*.gguf)");
|
||||
if (!file.isEmpty()) {
|
||||
ui->textEncoderEdit->setText(file);
|
||||
}
|
||||
QString file = QFileDialog::getOpenFileName(this, "Select Text Encoder Model", ui->textEncoderEdit->text(),
|
||||
"GGUF Files (*.gguf)");
|
||||
if (!file.isEmpty())
|
||||
{
|
||||
ui->textEncoderEdit->setText(file);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvancedSettingsDialog::on_ditBrowseButton_clicked()
|
||||
{
|
||||
QString file = QFileDialog::getOpenFileName(this, "Select DiT Model", ui->ditModelEdit->text(), "GGUF Files (*.gguf)");
|
||||
if (!file.isEmpty()) {
|
||||
ui->ditModelEdit->setText(file);
|
||||
}
|
||||
QString file = QFileDialog::getOpenFileName(this, "Select DiT Model", ui->ditModelEdit->text(), "GGUF Files (*.gguf)");
|
||||
if (!file.isEmpty())
|
||||
{
|
||||
ui->ditModelEdit->setText(file);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvancedSettingsDialog::on_vaeBrowseButton_clicked()
|
||||
{
|
||||
QString file = QFileDialog::getOpenFileName(this, "Select VAE Model", ui->vaeModelEdit->text(), "GGUF Files (*.gguf)");
|
||||
if (!file.isEmpty()) {
|
||||
ui->vaeModelEdit->setText(file);
|
||||
}
|
||||
QString file = QFileDialog::getOpenFileName(this, "Select VAE Model", ui->vaeModelEdit->text(), "GGUF Files (*.gguf)");
|
||||
if (!file.isEmpty())
|
||||
{
|
||||
ui->vaeModelEdit->setText(file);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,43 +4,44 @@
|
|||
#include <QDialog>
|
||||
#include <QString>
|
||||
|
||||
namespace Ui {
|
||||
namespace Ui
|
||||
{
|
||||
class AdvancedSettingsDialog;
|
||||
}
|
||||
|
||||
class AdvancedSettingsDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AdvancedSettingsDialog(QWidget *parent = nullptr);
|
||||
~AdvancedSettingsDialog();
|
||||
explicit AdvancedSettingsDialog(QWidget *parent = nullptr);
|
||||
~AdvancedSettingsDialog();
|
||||
|
||||
// Getters for settings
|
||||
QString getJsonTemplate() const;
|
||||
QString getAceStepPath() const;
|
||||
QString getQwen3ModelPath() const;
|
||||
QString getTextEncoderModelPath() const;
|
||||
QString getDiTModelPath() const;
|
||||
QString getVAEModelPath() const;
|
||||
// Getters for settings
|
||||
QString getJsonTemplate() const;
|
||||
QString getAceStepPath() const;
|
||||
QString getQwen3ModelPath() const;
|
||||
QString getTextEncoderModelPath() const;
|
||||
QString getDiTModelPath() const;
|
||||
QString getVAEModelPath() const;
|
||||
|
||||
// Setters for settings
|
||||
void setJsonTemplate(const QString &templateStr);
|
||||
void setAceStepPath(const QString &path);
|
||||
void setQwen3ModelPath(const QString &path);
|
||||
void setTextEncoderModelPath(const QString &path);
|
||||
void setDiTModelPath(const QString &path);
|
||||
void setVAEModelPath(const QString &path);
|
||||
// Setters for settings
|
||||
void setJsonTemplate(const QString &templateStr);
|
||||
void setAceStepPath(const QString &path);
|
||||
void setQwen3ModelPath(const QString &path);
|
||||
void setTextEncoderModelPath(const QString &path);
|
||||
void setDiTModelPath(const QString &path);
|
||||
void setVAEModelPath(const QString &path);
|
||||
|
||||
private slots:
|
||||
void on_aceStepBrowseButton_clicked();
|
||||
void on_qwen3BrowseButton_clicked();
|
||||
void on_textEncoderBrowseButton_clicked();
|
||||
void on_ditBrowseButton_clicked();
|
||||
void on_vaeBrowseButton_clicked();
|
||||
void on_aceStepBrowseButton_clicked();
|
||||
void on_qwen3BrowseButton_clicked();
|
||||
void on_textEncoderBrowseButton_clicked();
|
||||
void on_ditBrowseButton_clicked();
|
||||
void on_vaeBrowseButton_clicked();
|
||||
|
||||
private:
|
||||
Ui::AdvancedSettingsDialog *ui;
|
||||
Ui::AdvancedSettingsDialog *ui;
|
||||
};
|
||||
|
||||
#endif // ADVANCEDSETTINGSDIALOG_H
|
||||
|
|
@ -1,203 +1,203 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AdvancedSettingsDialog</class>
|
||||
<widget class="QDialog" name="AdvancedSettingsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>450</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Advanced Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="jsonTab">
|
||||
<attribute name="title">
|
||||
<string>JSON Template</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="jsonLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="jsonLabel">
|
||||
<property name="text">
|
||||
<string>JSON Template for AceStep generation:</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="jsonTemplateEdit"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="pathsTab">
|
||||
<attribute name="title">
|
||||
<string>Model Paths</string>
|
||||
</attribute>
|
||||
<layout class="QFormLayout" name="pathsLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::FieldGrowthPolicy::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="aceStepLabel">
|
||||
<property name="text">
|
||||
<string>AceStep Path:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="aceStepLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="aceStepPathEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="aceStepBrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="qwen3Label">
|
||||
<property name="text">
|
||||
<string>Qwen3 Model:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="qwen3Layout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="qwen3ModelEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="qwen3BrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="textEncoderLabel">
|
||||
<property name="text">
|
||||
<string>Text Encoder Model:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="textEncoderLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="textEncoderEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="textEncoderBrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="ditLabel">
|
||||
<property name="text">
|
||||
<string>DiT Model:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="ditLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="ditModelEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="ditBrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="vaeLabel">
|
||||
<property name="text">
|
||||
<string>VAE Model:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<layout class="QHBoxLayout" name="vaeLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="vaeModelEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="vaeBrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Save</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>AdvancedSettingsDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>AdvancedSettingsDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
<ui version="4.0">
|
||||
<class>AdvancedSettingsDialog</class>
|
||||
<widget class="QDialog" name="AdvancedSettingsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>450</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Advanced Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="jsonTab">
|
||||
<attribute name="title">
|
||||
<string>JSON Template</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="jsonLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="jsonLabel">
|
||||
<property name="text">
|
||||
<string>JSON Template for AceStep generation:</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="jsonTemplateEdit"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="pathsTab">
|
||||
<attribute name="title">
|
||||
<string>Model Paths</string>
|
||||
</attribute>
|
||||
<layout class="QFormLayout" name="pathsLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::FieldGrowthPolicy::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="aceStepLabel">
|
||||
<property name="text">
|
||||
<string>AceStep Path:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="aceStepLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="aceStepPathEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="aceStepBrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="qwen3Label">
|
||||
<property name="text">
|
||||
<string>Qwen3 Model:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="qwen3Layout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="qwen3ModelEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="qwen3BrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="textEncoderLabel">
|
||||
<property name="text">
|
||||
<string>Text Encoder Model:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="textEncoderLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="textEncoderEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="textEncoderBrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="ditLabel">
|
||||
<property name="text">
|
||||
<string>DiT Model:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="ditLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="ditModelEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="ditBrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="vaeLabel">
|
||||
<property name="text">
|
||||
<string>VAE Model:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<layout class="QHBoxLayout" name="vaeLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="vaeModelEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="vaeBrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Save</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>AdvancedSettingsDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>AdvancedSettingsDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -2,113 +2,128 @@
|
|||
#include <QDebug>
|
||||
|
||||
AudioPlayer::AudioPlayer(QObject *parent)
|
||||
: QObject(parent),
|
||||
mediaPlayer(new QMediaPlayer(this)),
|
||||
audioOutput(new QAudioOutput(this)),
|
||||
positionTimer(new QTimer(this))
|
||||
: QObject(parent),
|
||||
mediaPlayer(new QMediaPlayer(this)),
|
||||
audioOutput(new QAudioOutput(this)),
|
||||
positionTimer(new QTimer(this))
|
||||
{
|
||||
// Set up audio output with default device
|
||||
mediaPlayer->setAudioOutput(audioOutput);
|
||||
// Set up audio output with default device
|
||||
mediaPlayer->setAudioOutput(audioOutput);
|
||||
|
||||
connect(mediaPlayer, &QMediaPlayer::playbackStateChanged,
|
||||
this, &AudioPlayer::handlePlaybackStateChanged);
|
||||
connect(mediaPlayer, &QMediaPlayer::mediaStatusChanged,
|
||||
this, &AudioPlayer::handleMediaStatusChanged);
|
||||
connect(mediaPlayer, &QMediaPlayer::playbackStateChanged,
|
||||
this, &AudioPlayer::handlePlaybackStateChanged);
|
||||
connect(mediaPlayer, &QMediaPlayer::mediaStatusChanged,
|
||||
this, &AudioPlayer::handleMediaStatusChanged);
|
||||
|
||||
// Set up position timer for updating playback position
|
||||
positionTimer->setInterval(500); // Update every 500ms
|
||||
connect(positionTimer, &QTimer::timeout, [this]() {
|
||||
if (isPlaying()) {
|
||||
emit positionChanged(mediaPlayer->position());
|
||||
}
|
||||
});
|
||||
// Set up position timer for updating playback position
|
||||
positionTimer->setInterval(500); // Update every 500ms
|
||||
connect(positionTimer, &QTimer::timeout, [this]()
|
||||
{
|
||||
if (isPlaying())
|
||||
{
|
||||
emit positionChanged(mediaPlayer->position());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AudioPlayer::~AudioPlayer()
|
||||
{
|
||||
stop();
|
||||
stop();
|
||||
}
|
||||
|
||||
void AudioPlayer::play(const QString &filePath)
|
||||
{
|
||||
if (isPlaying()) {
|
||||
stop();
|
||||
}
|
||||
if (isPlaying())
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
mediaPlayer->setSource(QUrl::fromLocalFile(filePath));
|
||||
mediaPlayer->play();
|
||||
mediaPlayer->setSource(QUrl::fromLocalFile(filePath));
|
||||
mediaPlayer->play();
|
||||
|
||||
// Start position timer
|
||||
positionTimer->start();
|
||||
// Start position timer
|
||||
positionTimer->start();
|
||||
}
|
||||
|
||||
void AudioPlayer::play()
|
||||
{
|
||||
if (!isPlaying()) {
|
||||
mediaPlayer->play();
|
||||
positionTimer->start();
|
||||
}
|
||||
if (!isPlaying())
|
||||
{
|
||||
mediaPlayer->play();
|
||||
positionTimer->start();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayer::pause()
|
||||
{
|
||||
if (isPlaying()) {
|
||||
mediaPlayer->pause();
|
||||
positionTimer->stop();
|
||||
}
|
||||
if (isPlaying())
|
||||
{
|
||||
mediaPlayer->pause();
|
||||
positionTimer->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayer::setPosition(int position)
|
||||
{
|
||||
mediaPlayer->setPosition(position);
|
||||
mediaPlayer->setPosition(position);
|
||||
}
|
||||
|
||||
void AudioPlayer::stop()
|
||||
{
|
||||
mediaPlayer->stop();
|
||||
positionTimer->stop();
|
||||
mediaPlayer->stop();
|
||||
positionTimer->stop();
|
||||
}
|
||||
|
||||
bool AudioPlayer::isPlaying() const
|
||||
{
|
||||
return mediaPlayer->playbackState() == QMediaPlayer::PlayingState;
|
||||
return mediaPlayer->playbackState() == QMediaPlayer::PlayingState;
|
||||
}
|
||||
|
||||
int AudioPlayer::duration() const
|
||||
{
|
||||
return mediaPlayer->duration();
|
||||
return mediaPlayer->duration();
|
||||
}
|
||||
|
||||
int AudioPlayer::position() const
|
||||
{
|
||||
return mediaPlayer->position();
|
||||
return mediaPlayer->position();
|
||||
}
|
||||
|
||||
void AudioPlayer::handlePlaybackStateChanged(QMediaPlayer::PlaybackState state)
|
||||
{
|
||||
if (state == QMediaPlayer::PlayingState) {
|
||||
emit playbackStarted();
|
||||
} else if (state == QMediaPlayer::StoppedState ||
|
||||
state == QMediaPlayer::PausedState) {
|
||||
// Check if we reached the end
|
||||
if (mediaPlayer->position() >= mediaPlayer->duration() - 100) {
|
||||
emit playbackFinished();
|
||||
}
|
||||
}
|
||||
if (state == QMediaPlayer::PlayingState)
|
||||
{
|
||||
emit playbackStarted();
|
||||
}
|
||||
else if (state == QMediaPlayer::StoppedState ||
|
||||
state == QMediaPlayer::PausedState)
|
||||
{
|
||||
// Check if we reached the end
|
||||
if (mediaPlayer->position() >= mediaPlayer->duration() - 100)
|
||||
{
|
||||
emit playbackFinished();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayer::handleMediaStatusChanged(QMediaPlayer::MediaStatus status)
|
||||
{
|
||||
if (status == QMediaPlayer::EndOfMedia) {
|
||||
emit playbackFinished();
|
||||
} else if (status == QMediaPlayer::LoadedMedia ||
|
||||
status == QMediaPlayer::BufferedMedia) {
|
||||
// Media loaded successfully, emit duration
|
||||
int duration = mediaPlayer->duration();
|
||||
if (duration > 0) {
|
||||
emit durationChanged(duration);
|
||||
}
|
||||
} else if (status == QMediaPlayer::InvalidMedia) {
|
||||
emit playbackError(mediaPlayer->errorString());
|
||||
}
|
||||
if (status == QMediaPlayer::EndOfMedia)
|
||||
{
|
||||
emit playbackFinished();
|
||||
}
|
||||
else if (status == QMediaPlayer::LoadedMedia ||
|
||||
status == QMediaPlayer::BufferedMedia)
|
||||
{
|
||||
// Media loaded successfully, emit duration
|
||||
int duration = mediaPlayer->duration();
|
||||
if (duration > 0)
|
||||
{
|
||||
emit durationChanged(duration);
|
||||
}
|
||||
}
|
||||
else if (status == QMediaPlayer::InvalidMedia)
|
||||
{
|
||||
emit playbackError(mediaPlayer->errorString());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,35 +12,35 @@
|
|||
|
||||
class AudioPlayer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AudioPlayer(QObject *parent = nullptr);
|
||||
~AudioPlayer();
|
||||
explicit AudioPlayer(QObject *parent = nullptr);
|
||||
~AudioPlayer();
|
||||
|
||||
void play(const QString &filePath);
|
||||
void play();
|
||||
void stop();
|
||||
void pause();
|
||||
void setPosition(int position);
|
||||
bool isPlaying() const;
|
||||
int duration() const;
|
||||
int position() const;
|
||||
void play(const QString &filePath);
|
||||
void play();
|
||||
void stop();
|
||||
void pause();
|
||||
void setPosition(int position);
|
||||
bool isPlaying() const;
|
||||
int duration() const;
|
||||
int position() const;
|
||||
|
||||
signals:
|
||||
void playbackStarted();
|
||||
void playbackFinished();
|
||||
void playbackError(const QString &error);
|
||||
void positionChanged(int position);
|
||||
void durationChanged(int duration);
|
||||
void playbackStarted();
|
||||
void playbackFinished();
|
||||
void playbackError(const QString &error);
|
||||
void positionChanged(int position);
|
||||
void durationChanged(int duration);
|
||||
|
||||
private slots:
|
||||
void handlePlaybackStateChanged(QMediaPlayer::PlaybackState state);
|
||||
void handleMediaStatusChanged(QMediaPlayer::MediaStatus status);
|
||||
void handlePlaybackStateChanged(QMediaPlayer::PlaybackState state);
|
||||
void handleMediaStatusChanged(QMediaPlayer::MediaStatus status);
|
||||
|
||||
private:
|
||||
QMediaPlayer *mediaPlayer;
|
||||
QAudioOutput *audioOutput;
|
||||
QTimer *positionTimer;
|
||||
QMediaPlayer *mediaPlayer;
|
||||
QAudioOutput *audioOutput;
|
||||
QTimer *positionTimer;
|
||||
};
|
||||
|
||||
#endif // AUDIOPLAYER_H
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
107
src/MainWindow.h
107
src/MainWindow.h
|
|
@ -17,90 +17,93 @@
|
|||
#include "AceStepWorker.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class MainWindow; }
|
||||
namespace Ui
|
||||
{
|
||||
class MainWindow;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
private slots:
|
||||
void on_playButton_clicked();
|
||||
void on_pauseButton_clicked();
|
||||
void on_skipButton_clicked();
|
||||
void on_stopButton_clicked();
|
||||
void on_shuffleButton_clicked();
|
||||
void on_positionSlider_sliderMoved(int position);
|
||||
void updatePosition(int position);
|
||||
void updateDuration(int duration);
|
||||
void on_addSongButton_clicked();
|
||||
void on_removeSongButton_clicked();
|
||||
void on_advancedSettingsButton_clicked();
|
||||
void on_playButton_clicked();
|
||||
void on_pauseButton_clicked();
|
||||
void on_skipButton_clicked();
|
||||
void on_stopButton_clicked();
|
||||
void on_shuffleButton_clicked();
|
||||
void on_positionSlider_sliderMoved(int position);
|
||||
void updatePosition(int position);
|
||||
void updateDuration(int duration);
|
||||
void on_addSongButton_clicked();
|
||||
void on_removeSongButton_clicked();
|
||||
void on_advancedSettingsButton_clicked();
|
||||
|
||||
void on_songListView_doubleClicked(const QModelIndex &index);
|
||||
void on_songListView_doubleClicked(const QModelIndex &index);
|
||||
|
||||
void songGenerated(const SongItem& song);
|
||||
void playNextSong();
|
||||
void playbackStarted();
|
||||
void playNextSong();
|
||||
void playbackStarted();
|
||||
void updatePlaybackStatus(bool playing);
|
||||
void generationError(const QString &error);
|
||||
void generationError(const QString &error);
|
||||
|
||||
void on_actionSavePlaylist();
|
||||
void on_actionLoadPlaylist();
|
||||
void on_actionAppendPlaylist();
|
||||
void on_actionSaveSong();
|
||||
void on_actionSavePlaylist();
|
||||
void on_actionLoadPlaylist();
|
||||
void on_actionAppendPlaylist();
|
||||
void on_actionSaveSong();
|
||||
|
||||
private:
|
||||
void startNextSongGeneration();
|
||||
void startNextSongGeneration();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
SongListModel *songModel;
|
||||
AudioPlayer *audioPlayer;
|
||||
AceStepWorker *aceStepWorker;
|
||||
QTimer *playbackTimer;
|
||||
Ui::MainWindow *ui;
|
||||
SongListModel *songModel;
|
||||
AudioPlayer *audioPlayer;
|
||||
AceStepWorker *aceStepWorker;
|
||||
QTimer *playbackTimer;
|
||||
|
||||
QString formatTime(int milliseconds);
|
||||
QString formatTime(int milliseconds);
|
||||
|
||||
SongItem currentSong;
|
||||
bool isPlaying;
|
||||
bool isPaused;
|
||||
bool shuffleMode;
|
||||
bool isGeneratingNext;
|
||||
QString jsonTemplate;
|
||||
bool isPlaying;
|
||||
bool isPaused;
|
||||
bool shuffleMode;
|
||||
bool isGeneratingNext;
|
||||
QString jsonTemplate;
|
||||
|
||||
// Path settings
|
||||
QString aceStepPath;
|
||||
QString qwen3ModelPath;
|
||||
QString textEncoderModelPath;
|
||||
QString ditModelPath;
|
||||
QString vaeModelPath;
|
||||
// Path settings
|
||||
QString aceStepPath;
|
||||
QString qwen3ModelPath;
|
||||
QString textEncoderModelPath;
|
||||
QString ditModelPath;
|
||||
QString vaeModelPath;
|
||||
|
||||
// Queue for generated songs
|
||||
// Queue for generated songs
|
||||
static constexpr int generationTresh = 2;
|
||||
QQueue<SongItem> generatedSongQueue;
|
||||
|
||||
private:
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
void loadPlaylist(const QString &filePath);
|
||||
void savePlaylist(const QString &filePath);
|
||||
void autoSavePlaylist();
|
||||
void autoLoadPlaylist();
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
void loadPlaylist(const QString &filePath);
|
||||
void savePlaylist(const QString &filePath);
|
||||
void autoSavePlaylist();
|
||||
void autoLoadPlaylist();
|
||||
|
||||
void playSong(const SongItem& song);
|
||||
|
||||
bool savePlaylistToJson(const QString &filePath, const QList<SongItem> &songs);
|
||||
bool loadPlaylistFromJson(const QString &filePath, QList<SongItem> &songs);
|
||||
bool savePlaylistToJson(const QString &filePath, const QList<SongItem> &songs);
|
||||
bool loadPlaylistFromJson(const QString &filePath, QList<SongItem> &songs);
|
||||
|
||||
void setupUI();
|
||||
void setupUI();
|
||||
void updateControls();
|
||||
void ensureSongsInQueue(bool enqeueCurrent = false);
|
||||
void flushGenerationQueue();
|
||||
void flushGenerationQueue();
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
|||
|
|
@ -1,359 +1,359 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Aceradio</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../res/resources.qrc">
|
||||
<normaloff>:/icons/xyz.uvos.aceradio.png</normaloff>:/icons/xyz.uvos.aceradio.png</iconset>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="mainTabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="songsTab">
|
||||
<attribute name="title">
|
||||
<string>Songs</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QTableView" name="songListView">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectionBehavior::SelectRows</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="infoTab">
|
||||
<attribute name="title">
|
||||
<string>Info</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="jsonTextEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="lyricsTab">
|
||||
<attribute name="title">
|
||||
<string>Lyrics</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QTextEdit" name="lyricsTextEdit">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="buttonLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addSongButton">
|
||||
<property name="text">
|
||||
<string>Add Song</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeSongButton">
|
||||
<property name="text">
|
||||
<string>Remove Song</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="nowPlayingLabel">
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LayoutDirection::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Now Playing:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="timeControlsLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="elapsedTimeLabel">
|
||||
<property name="text">
|
||||
<string>0:00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ClickableSlider" name="positionSlider" native="true">
|
||||
<property name="mouseTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="tabletTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="durationLabel">
|
||||
<property name="text">
|
||||
<string>0:00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="controlsFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="controlsLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="playButton">
|
||||
<property name="text">
|
||||
<string>Play</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-playback-start"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pauseButton">
|
||||
<property name="text">
|
||||
<string>Pause</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-playback-pause"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="skipButton">
|
||||
<property name="text">
|
||||
<string>Skip</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-skip-forward"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="stopButton">
|
||||
<property name="text">
|
||||
<string>Stop</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-playback-stop"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="shuffleButton">
|
||||
<property name="text">
|
||||
<string>Shuffle</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-playlist-shuffle"/>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="statusLayout">
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="statusLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>32</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionSaveSong"/>
|
||||
<addaction name="actionSavePlaylist"/>
|
||||
<addaction name="actionLoadPlaylist"/>
|
||||
<addaction name="actionAppendPlaylist"/>
|
||||
<addaction name="actionClearPlaylist"/>
|
||||
<addaction name="actionQuit"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuSettings">
|
||||
<property name="title">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<addaction name="actionAdvancedSettings"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuSettings"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<action name="actionSavePlaylist">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::DocumentSaveAs"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save Playlist</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+S</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLoadPlaylist">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::DocumentOpen"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Load Playlist...</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+O</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAdvancedSettings">
|
||||
<property name="text">
|
||||
<string>Ace Step</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionQuit">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::ApplicationExit"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Quit</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Q</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClearPlaylist">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::EditDelete"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear Playlist</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSaveSong">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::DocumentSaveAs"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save Song</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAppendPlaylist">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::DocumentOpen"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Append Playlist</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ClickableSlider</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>src/clickableslider.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../res/resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Aceradio</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../res/resources.qrc">
|
||||
<normaloff>:/icons/xyz.uvos.aceradio.png</normaloff>:/icons/xyz.uvos.aceradio.png</iconset>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="mainTabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="songsTab">
|
||||
<attribute name="title">
|
||||
<string>Songs</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QTableView" name="songListView">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectionBehavior::SelectRows</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="infoTab">
|
||||
<attribute name="title">
|
||||
<string>Info</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="jsonTextEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="lyricsTab">
|
||||
<attribute name="title">
|
||||
<string>Lyrics</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QTextEdit" name="lyricsTextEdit">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="buttonLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addSongButton">
|
||||
<property name="text">
|
||||
<string>Add Song</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeSongButton">
|
||||
<property name="text">
|
||||
<string>Remove Song</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="nowPlayingLabel">
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LayoutDirection::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Now Playing:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="timeControlsLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="elapsedTimeLabel">
|
||||
<property name="text">
|
||||
<string>0:00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ClickableSlider" name="positionSlider" native="true">
|
||||
<property name="mouseTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="tabletTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="durationLabel">
|
||||
<property name="text">
|
||||
<string>0:00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="controlsFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="controlsLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="playButton">
|
||||
<property name="text">
|
||||
<string>Play</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-playback-start"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pauseButton">
|
||||
<property name="text">
|
||||
<string>Pause</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-playback-pause"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="skipButton">
|
||||
<property name="text">
|
||||
<string>Skip</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-skip-forward"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="stopButton">
|
||||
<property name="text">
|
||||
<string>Stop</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-playback-stop"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="shuffleButton">
|
||||
<property name="text">
|
||||
<string>Shuffle</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-playlist-shuffle"/>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="statusLayout">
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="statusLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>32</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionSaveSong"/>
|
||||
<addaction name="actionSavePlaylist"/>
|
||||
<addaction name="actionLoadPlaylist"/>
|
||||
<addaction name="actionAppendPlaylist"/>
|
||||
<addaction name="actionClearPlaylist"/>
|
||||
<addaction name="actionQuit"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuSettings">
|
||||
<property name="title">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<addaction name="actionAdvancedSettings"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuSettings"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<action name="actionSavePlaylist">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::DocumentSaveAs"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save Playlist</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+S</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLoadPlaylist">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::DocumentOpen"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Load Playlist...</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+O</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAdvancedSettings">
|
||||
<property name="text">
|
||||
<string>Ace Step</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionQuit">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::ApplicationExit"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Quit</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Q</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClearPlaylist">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::EditDelete"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear Playlist</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSaveSong">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::DocumentSaveAs"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save Song</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAppendPlaylist">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::DocumentOpen"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Append Playlist</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ClickableSlider</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>src/clickableslider.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../res/resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -3,75 +3,82 @@
|
|||
#include <QMessageBox>
|
||||
|
||||
SongDialog::SongDialog(QWidget *parent, const QString &caption, const QString &lyrics, const QString &vocalLanguage)
|
||||
: QDialog(parent),
|
||||
ui(new Ui::SongDialog)
|
||||
: QDialog(parent),
|
||||
ui(new Ui::SongDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->setupUi(this);
|
||||
|
||||
// Set initial values if provided
|
||||
if (!caption.isEmpty()) {
|
||||
ui->captionEdit->setPlainText(caption);
|
||||
}
|
||||
if (!lyrics.isEmpty()) {
|
||||
ui->lyricsEdit->setPlainText(lyrics);
|
||||
}
|
||||
// Set initial values if provided
|
||||
if (!caption.isEmpty())
|
||||
{
|
||||
ui->captionEdit->setPlainText(caption);
|
||||
}
|
||||
if (!lyrics.isEmpty())
|
||||
{
|
||||
ui->lyricsEdit->setPlainText(lyrics);
|
||||
}
|
||||
|
||||
// Setup vocal language combo box
|
||||
ui->vocalLanguageCombo->addItem("--", ""); // Unset
|
||||
ui->vocalLanguageCombo->addItem("English (en)", "en");
|
||||
ui->vocalLanguageCombo->addItem("German (de)", "de");
|
||||
ui->vocalLanguageCombo->addItem("French (fr)", "fr");
|
||||
ui->vocalLanguageCombo->addItem("Spanish (es)", "es");
|
||||
ui->vocalLanguageCombo->addItem("Japanese (ja)", "ja");
|
||||
ui->vocalLanguageCombo->addItem("Chinese (zh)", "zh");
|
||||
ui->vocalLanguageCombo->addItem("Italian (it)", "it");
|
||||
ui->vocalLanguageCombo->addItem("Portuguese (pt)", "pt");
|
||||
ui->vocalLanguageCombo->addItem("Russian (ru)", "ru");
|
||||
// Setup vocal language combo box
|
||||
ui->vocalLanguageCombo->addItem("--", ""); // Unset
|
||||
ui->vocalLanguageCombo->addItem("English (en)", "en");
|
||||
ui->vocalLanguageCombo->addItem("German (de)", "de");
|
||||
ui->vocalLanguageCombo->addItem("French (fr)", "fr");
|
||||
ui->vocalLanguageCombo->addItem("Spanish (es)", "es");
|
||||
ui->vocalLanguageCombo->addItem("Japanese (ja)", "ja");
|
||||
ui->vocalLanguageCombo->addItem("Chinese (zh)", "zh");
|
||||
ui->vocalLanguageCombo->addItem("Italian (it)", "it");
|
||||
ui->vocalLanguageCombo->addItem("Portuguese (pt)", "pt");
|
||||
ui->vocalLanguageCombo->addItem("Russian (ru)", "ru");
|
||||
|
||||
// Set current language if provided
|
||||
if (!vocalLanguage.isEmpty()) {
|
||||
int index = ui->vocalLanguageCombo->findData(vocalLanguage);
|
||||
if (index >= 0) {
|
||||
ui->vocalLanguageCombo->setCurrentIndex(index);
|
||||
}
|
||||
} else {
|
||||
ui->vocalLanguageCombo->setCurrentIndex(0); // Default to unset
|
||||
}
|
||||
// Set current language if provided
|
||||
if (!vocalLanguage.isEmpty())
|
||||
{
|
||||
int index = ui->vocalLanguageCombo->findData(vocalLanguage);
|
||||
if (index >= 0)
|
||||
{
|
||||
ui->vocalLanguageCombo->setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->vocalLanguageCombo->setCurrentIndex(0); // Default to unset
|
||||
}
|
||||
}
|
||||
|
||||
SongDialog::~SongDialog()
|
||||
{
|
||||
delete ui;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
QString SongDialog::getCaption() const
|
||||
{
|
||||
return ui->captionEdit->toPlainText();
|
||||
return ui->captionEdit->toPlainText();
|
||||
}
|
||||
|
||||
QString SongDialog::getLyrics() const
|
||||
{
|
||||
return ui->lyricsEdit->toPlainText();
|
||||
return ui->lyricsEdit->toPlainText();
|
||||
}
|
||||
|
||||
QString SongDialog::getVocalLanguage() const
|
||||
{
|
||||
return ui->vocalLanguageCombo->currentData().toString();
|
||||
return ui->vocalLanguageCombo->currentData().toString();
|
||||
}
|
||||
|
||||
void SongDialog::on_okButton_clicked()
|
||||
{
|
||||
// Validate that caption is not empty
|
||||
QString caption = getCaption();
|
||||
if (caption.trimmed().isEmpty()) {
|
||||
QMessageBox::warning(this, "Invalid Input", "Caption cannot be empty.");
|
||||
return;
|
||||
}
|
||||
// Validate that caption is not empty
|
||||
QString caption = getCaption();
|
||||
if (caption.trimmed().isEmpty())
|
||||
{
|
||||
QMessageBox::warning(this, "Invalid Input", "Caption cannot be empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
accept();
|
||||
accept();
|
||||
}
|
||||
|
||||
void SongDialog::on_cancelButton_clicked()
|
||||
{
|
||||
reject();
|
||||
reject();
|
||||
}
|
||||
|
|
@ -4,28 +4,30 @@
|
|||
#include <QDialog>
|
||||
#include <QString>
|
||||
|
||||
namespace Ui {
|
||||
namespace Ui
|
||||
{
|
||||
class SongDialog;
|
||||
}
|
||||
|
||||
class SongDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SongDialog(QWidget *parent = nullptr, const QString &caption = "", const QString &lyrics = "", const QString &vocalLanguage = "");
|
||||
~SongDialog();
|
||||
explicit SongDialog(QWidget *parent = nullptr, const QString &caption = "", const QString &lyrics = "",
|
||||
const QString &vocalLanguage = "");
|
||||
~SongDialog();
|
||||
|
||||
QString getCaption() const;
|
||||
QString getLyrics() const;
|
||||
QString getVocalLanguage() const;
|
||||
QString getCaption() const;
|
||||
QString getLyrics() const;
|
||||
QString getVocalLanguage() const;
|
||||
|
||||
private slots:
|
||||
void on_okButton_clicked();
|
||||
void on_cancelButton_clicked();
|
||||
void on_okButton_clicked();
|
||||
void on_cancelButton_clicked();
|
||||
|
||||
private:
|
||||
Ui::SongDialog *ui;
|
||||
Ui::SongDialog *ui;
|
||||
};
|
||||
|
||||
#endif // SONGDIALOG_H
|
||||
|
|
@ -1,109 +1,109 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SongDialog</class>
|
||||
<widget class="QDialog" name="SongDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>500</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Song Details</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="captionLabel">
|
||||
<property name="text">
|
||||
<string>Caption:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="captionEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Enter song caption (e.g., "Upbeat pop rock anthem with driving electric guitars")</string>
|
||||
</property>
|
||||
<property name="maximumHeight">
|
||||
<number>80</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lyricsLabel">
|
||||
<property name="text">
|
||||
<string>Lyrics (optional):</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="lyricsEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Enter lyrics or leave empty for instrumental music</string>
|
||||
</property>
|
||||
<property name="minimumHeight">
|
||||
<number>150</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="vocalLanguageLabel">
|
||||
<property name="text">
|
||||
<string>Vocal Language:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="vocalLanguageCombo">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="buttonLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="okButton">
|
||||
<property name="text">
|
||||
<string>OK</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
<ui version="4.0">
|
||||
<class>SongDialog</class>
|
||||
<widget class="QDialog" name="SongDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>500</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Song Details</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="captionLabel">
|
||||
<property name="text">
|
||||
<string>Caption:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="captionEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Enter song caption (e.g., "Upbeat pop rock anthem with driving electric guitars")</string>
|
||||
</property>
|
||||
<property name="maximumHeight">
|
||||
<number>80</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lyricsLabel">
|
||||
<property name="text">
|
||||
<string>Lyrics (optional):</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="lyricsEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Enter lyrics or leave empty for instrumental music</string>
|
||||
</property>
|
||||
<property name="minimumHeight">
|
||||
<number>150</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="vocalLanguageLabel">
|
||||
<property name="text">
|
||||
<string>Vocal Language:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="vocalLanguageCombo">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="buttonLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="okButton">
|
||||
<property name="text">
|
||||
<string>OK</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -3,18 +3,20 @@
|
|||
#include <QRandomGenerator>
|
||||
#include <cstdint>
|
||||
|
||||
class SongItem {
|
||||
class SongItem
|
||||
{
|
||||
public:
|
||||
QString caption;
|
||||
QString lyrics;
|
||||
uint64_t uniqueId;
|
||||
QString file;
|
||||
QString vocalLanguage;
|
||||
QString json;
|
||||
QString caption;
|
||||
QString lyrics;
|
||||
uint64_t uniqueId;
|
||||
QString file;
|
||||
QString vocalLanguage;
|
||||
QString json;
|
||||
|
||||
inline SongItem(const QString &caption = "", const QString &lyrics = "")
|
||||
: caption(caption), lyrics(lyrics) {
|
||||
// Generate a unique ID using cryptographically secure random number
|
||||
uniqueId = QRandomGenerator::global()->generate64();
|
||||
}
|
||||
inline SongItem(const QString &caption = "", const QString &lyrics = "")
|
||||
: caption(caption), lyrics(lyrics)
|
||||
{
|
||||
// Generate a unique ID using cryptographically secure random number
|
||||
uniqueId = QRandomGenerator::global()->generate64();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,167 +7,179 @@
|
|||
#include <QUuid>
|
||||
|
||||
SongListModel::SongListModel(QObject *parent)
|
||||
: QAbstractTableModel(parent),
|
||||
m_playingIndex(-1)
|
||||
: QAbstractTableModel(parent),
|
||||
m_playingIndex(-1)
|
||||
{
|
||||
}
|
||||
|
||||
int SongListModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
return songList.size();
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
return songList.size();
|
||||
}
|
||||
|
||||
int SongListModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
// We have 3 columns: play indicator, song name, and vocal language (read-only)
|
||||
return 3;
|
||||
// We have 3 columns: play indicator, song name, and vocal language (read-only)
|
||||
return 3;
|
||||
}
|
||||
|
||||
QVariant SongListModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() >= songList.size())
|
||||
return QVariant();
|
||||
if (!index.isValid() || index.row() >= songList.size())
|
||||
return QVariant();
|
||||
|
||||
const SongItem &song = songList[index.row()];
|
||||
const SongItem &song = songList[index.row()];
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
// Column 0: Play indicator column
|
||||
if (index.column() == 0) {
|
||||
return index.row() == m_playingIndex ? "▶" : "";
|
||||
}
|
||||
// Column 1: Song name
|
||||
else if (index.column() == 1) {
|
||||
return song.caption;
|
||||
}
|
||||
// Column 2: Vocal language
|
||||
else if (index.column() == 2) {
|
||||
return !song.vocalLanguage.isEmpty() ? song.vocalLanguage : "--";
|
||||
}
|
||||
break;
|
||||
case Qt::FontRole:
|
||||
// Make play indicator bold and larger
|
||||
if (index.column() == 0 && index.row() == m_playingIndex) {
|
||||
QFont font = QApplication::font();
|
||||
font.setBold(true);
|
||||
return font;
|
||||
}
|
||||
break;
|
||||
case Qt::TextAlignmentRole:
|
||||
// Center align the play indicator
|
||||
if (index.column() == 0) {
|
||||
return Qt::AlignCenter;
|
||||
}
|
||||
break;
|
||||
case CaptionRole:
|
||||
return song.caption;
|
||||
case LyricsRole:
|
||||
return song.lyrics;
|
||||
case VocalLanguageRole:
|
||||
return song.vocalLanguage;
|
||||
case IsPlayingRole:
|
||||
return index.row() == m_playingIndex;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
// Column 0: Play indicator column
|
||||
if (index.column() == 0)
|
||||
{
|
||||
return index.row() == m_playingIndex ? "▶" : "";
|
||||
}
|
||||
// Column 1: Song name
|
||||
else if (index.column() == 1)
|
||||
{
|
||||
return song.caption;
|
||||
}
|
||||
// Column 2: Vocal language
|
||||
else if (index.column() == 2)
|
||||
{
|
||||
return !song.vocalLanguage.isEmpty() ? song.vocalLanguage : "--";
|
||||
}
|
||||
break;
|
||||
case Qt::FontRole:
|
||||
// Make play indicator bold and larger
|
||||
if (index.column() == 0 && index.row() == m_playingIndex)
|
||||
{
|
||||
QFont font = QApplication::font();
|
||||
font.setBold(true);
|
||||
return font;
|
||||
}
|
||||
break;
|
||||
case Qt::TextAlignmentRole:
|
||||
// Center align the play indicator
|
||||
if (index.column() == 0)
|
||||
{
|
||||
return Qt::AlignCenter;
|
||||
}
|
||||
break;
|
||||
case CaptionRole:
|
||||
return song.caption;
|
||||
case LyricsRole:
|
||||
return song.lyrics;
|
||||
case VocalLanguageRole:
|
||||
return song.vocalLanguage;
|
||||
case IsPlayingRole:
|
||||
return index.row() == m_playingIndex;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool SongListModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (!index.isValid() || index.row() >= songList.size())
|
||||
return false;
|
||||
if (!index.isValid() || index.row() >= songList.size())
|
||||
return false;
|
||||
|
||||
SongItem &song = songList[index.row()];
|
||||
SongItem &song = songList[index.row()];
|
||||
|
||||
switch (role) {
|
||||
case CaptionRole:
|
||||
song.caption = value.toString();
|
||||
break;
|
||||
case LyricsRole:
|
||||
song.lyrics = value.toString();
|
||||
break;
|
||||
case VocalLanguageRole:
|
||||
song.vocalLanguage = value.toString();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
switch (role)
|
||||
{
|
||||
case CaptionRole:
|
||||
song.caption = value.toString();
|
||||
break;
|
||||
case LyricsRole:
|
||||
song.lyrics = value.toString();
|
||||
break;
|
||||
case VocalLanguageRole:
|
||||
song.vocalLanguage = value.toString();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
emit dataChanged(index, index, {role});
|
||||
return true;
|
||||
emit dataChanged(index, index, {role});
|
||||
return true;
|
||||
}
|
||||
|
||||
Qt::ItemFlags SongListModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return Qt::NoItemFlags;
|
||||
if (!index.isValid())
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
// Remove ItemIsEditable to prevent inline editing and double-click issues
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
// Remove ItemIsEditable to prevent inline editing and double-click issues
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
|
||||
void SongListModel::addSong(const SongItem &song)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), songList.size(), songList.size());
|
||||
songList.append(song);
|
||||
endInsertRows();
|
||||
beginInsertRows(QModelIndex(), songList.size(), songList.size());
|
||||
songList.append(song);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void SongListModel::removeSong(int index)
|
||||
{
|
||||
if (index >= 0 && index < songList.size()) {
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
songList.removeAt(index);
|
||||
endRemoveRows();
|
||||
}
|
||||
if (index >= 0 && index < songList.size())
|
||||
{
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
songList.removeAt(index);
|
||||
endRemoveRows();
|
||||
}
|
||||
}
|
||||
|
||||
void SongListModel::clear()
|
||||
{
|
||||
beginRemoveRows(QModelIndex(), 0, songList.size()-1);
|
||||
songList.clear();
|
||||
endRemoveRows();
|
||||
beginRemoveRows(QModelIndex(), 0, songList.size()-1);
|
||||
songList.clear();
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
bool SongListModel::empty()
|
||||
{
|
||||
return songList.empty();
|
||||
return songList.empty();
|
||||
}
|
||||
|
||||
SongItem SongListModel::getSong(int index) const
|
||||
{
|
||||
if (index >= 0 && index < songList.size()) {
|
||||
return songList[index];
|
||||
}
|
||||
return SongItem();
|
||||
if (index >= 0 && index < songList.size())
|
||||
{
|
||||
return songList[index];
|
||||
}
|
||||
return SongItem();
|
||||
}
|
||||
|
||||
QVariant SongListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
|
||||
// Hide headers since we don't need column titles
|
||||
return QVariant();
|
||||
}
|
||||
return QAbstractTableModel::headerData(section, orientation, role);
|
||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
|
||||
{
|
||||
// Hide headers since we don't need column titles
|
||||
return QVariant();
|
||||
}
|
||||
return QAbstractTableModel::headerData(section, orientation, role);
|
||||
}
|
||||
|
||||
void SongListModel::setPlayingIndex(int index)
|
||||
{
|
||||
int oldPlayingIndex = m_playingIndex;
|
||||
m_playingIndex = index;
|
||||
int oldPlayingIndex = m_playingIndex;
|
||||
m_playingIndex = index;
|
||||
|
||||
// Update both the old and new playing indices to trigger UI updates
|
||||
if (oldPlayingIndex >= 0 && oldPlayingIndex < songList.size()) {
|
||||
emit dataChanged(this->index(oldPlayingIndex, 0), this->index(oldPlayingIndex, 0));
|
||||
}
|
||||
// Update both the old and new playing indices to trigger UI updates
|
||||
if (oldPlayingIndex >= 0 && oldPlayingIndex < songList.size())
|
||||
{
|
||||
emit dataChanged(this->index(oldPlayingIndex, 0), this->index(oldPlayingIndex, 0));
|
||||
}
|
||||
|
||||
if (index >= 0 && index < songList.size()) {
|
||||
emit dataChanged(this->index(index, 0), this->index(index, 0));
|
||||
}
|
||||
if (index >= 0 && index < songList.size())
|
||||
{
|
||||
emit dataChanged(this->index(index, 0), this->index(index, 0));
|
||||
}
|
||||
}
|
||||
|
||||
int SongListModel::songCount()
|
||||
|
|
@ -177,30 +189,34 @@ int SongListModel::songCount()
|
|||
|
||||
int SongListModel::findNextIndex(int currentIndex, bool shuffle) const
|
||||
{
|
||||
if (songList.isEmpty())
|
||||
return -1;
|
||||
if (songList.isEmpty())
|
||||
return -1;
|
||||
|
||||
if (shuffle) {
|
||||
// Simple random selection for shuffle mode
|
||||
QRandomGenerator generator;
|
||||
return generator.bounded(songList.size());
|
||||
}
|
||||
if (shuffle)
|
||||
{
|
||||
// Simple random selection for shuffle mode
|
||||
QRandomGenerator generator;
|
||||
return generator.bounded(songList.size());
|
||||
}
|
||||
|
||||
// Sequential playback
|
||||
int nextIndex = currentIndex + 1;
|
||||
if (nextIndex >= songList.size()) {
|
||||
nextIndex = 0; // Loop back to beginning
|
||||
}
|
||||
// Sequential playback
|
||||
int nextIndex = currentIndex + 1;
|
||||
if (nextIndex >= songList.size())
|
||||
{
|
||||
nextIndex = 0; // Loop back to beginning
|
||||
}
|
||||
|
||||
return nextIndex;
|
||||
return nextIndex;
|
||||
}
|
||||
|
||||
int SongListModel::findSongIndexById(uint64_t uniqueId) const
|
||||
{
|
||||
for (int i = 0; i < songList.size(); ++i) {
|
||||
if (songList[i].uniqueId == uniqueId) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1; // Song not found
|
||||
for (int i = 0; i < songList.size(); ++i)
|
||||
{
|
||||
if (songList[i].uniqueId == uniqueId)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1; // Song not found
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,47 +11,51 @@
|
|||
|
||||
class SongListModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
CaptionRole = Qt::UserRole + 1,
|
||||
LyricsRole = Qt::UserRole + 2,
|
||||
VocalLanguageRole = Qt::UserRole + 3,
|
||||
IsPlayingRole = Qt::UserRole + 4
|
||||
};
|
||||
enum Roles
|
||||
{
|
||||
CaptionRole = Qt::UserRole + 1,
|
||||
LyricsRole = Qt::UserRole + 2,
|
||||
VocalLanguageRole = Qt::UserRole + 3,
|
||||
IsPlayingRole = Qt::UserRole + 4
|
||||
};
|
||||
|
||||
explicit SongListModel(QObject *parent = nullptr);
|
||||
explicit SongListModel(QObject *parent = nullptr);
|
||||
|
||||
// Basic functionality:
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
// Basic functionality:
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
|
||||
// Editable:
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
// Editable:
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
|
||||
// Add/remove songs
|
||||
void addSong(const SongItem &song);
|
||||
void removeSong(int index);
|
||||
SongItem getSong(int index) const;
|
||||
int findNextIndex(int currentIndex, bool shuffle = false) const;
|
||||
void clear();
|
||||
// Add/remove songs
|
||||
void addSong(const SongItem &song);
|
||||
void removeSong(int index);
|
||||
SongItem getSong(int index) const;
|
||||
int findNextIndex(int currentIndex, bool shuffle = false) const;
|
||||
void clear();
|
||||
|
||||
// Playing indicator
|
||||
void setPlayingIndex(int index);
|
||||
int playingIndex() const { return m_playingIndex; }
|
||||
// Playing indicator
|
||||
void setPlayingIndex(int index);
|
||||
int playingIndex() const
|
||||
{
|
||||
return m_playingIndex;
|
||||
}
|
||||
|
||||
// Find song by unique ID
|
||||
int findSongIndexById(uint64_t uniqueId) const;
|
||||
int songCount();
|
||||
bool empty();
|
||||
// Find song by unique ID
|
||||
int findSongIndexById(uint64_t uniqueId) const;
|
||||
int songCount();
|
||||
bool empty();
|
||||
|
||||
private:
|
||||
QList<SongItem> songList;
|
||||
int m_playingIndex;
|
||||
QList<SongItem> songList;
|
||||
int m_playingIndex;
|
||||
};
|
||||
|
||||
#endif // SONGLISTMODEL_H
|
||||
|
|
|
|||
|
|
@ -2,59 +2,65 @@
|
|||
#include <QStyle>
|
||||
|
||||
ClickableSlider::ClickableSlider(QWidget *parent)
|
||||
: QSlider(Qt::Orientation::Horizontal, parent)
|
||||
: QSlider(Qt::Orientation::Horizontal, parent)
|
||||
{
|
||||
}
|
||||
|
||||
ClickableSlider::ClickableSlider(Qt::Orientation orientation, QWidget *parent)
|
||||
: QSlider(orientation, parent)
|
||||
: QSlider(orientation, parent)
|
||||
{
|
||||
}
|
||||
|
||||
void ClickableSlider::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
int val = pixelPosToRangeValue(event->pos());
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
int val = pixelPosToRangeValue(event->pos());
|
||||
|
||||
// Block signals temporarily to avoid infinite recursion
|
||||
blockSignals(true);
|
||||
setValue(val);
|
||||
blockSignals(false);
|
||||
// Block signals temporarily to avoid infinite recursion
|
||||
blockSignals(true);
|
||||
setValue(val);
|
||||
blockSignals(false);
|
||||
|
||||
// Emit both valueChanged and sliderMoved signals for compatibility
|
||||
emit valueChanged(val);
|
||||
emit sliderMoved(val);
|
||||
} else {
|
||||
// Call base class implementation for other buttons
|
||||
QSlider::mousePressEvent(event);
|
||||
}
|
||||
// Emit both valueChanged and sliderMoved signals for compatibility
|
||||
emit valueChanged(val);
|
||||
emit sliderMoved(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Call base class implementation for other buttons
|
||||
QSlider::mousePressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
int ClickableSlider::pixelPosToRangeValue(const QPoint &pos)
|
||||
{
|
||||
QStyleOptionSlider opt;
|
||||
initStyleOption(&opt);
|
||||
QStyleOptionSlider opt;
|
||||
initStyleOption(&opt);
|
||||
|
||||
QRect gr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this);
|
||||
QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
|
||||
QRect gr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this);
|
||||
QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
|
||||
|
||||
int sliderLength;
|
||||
int sliderMin;
|
||||
int sliderMax;
|
||||
int sliderLength;
|
||||
int sliderMin;
|
||||
int sliderMax;
|
||||
|
||||
if (orientation() == Qt::Horizontal) {
|
||||
sliderLength = sr.width();
|
||||
sliderMin = gr.x();
|
||||
sliderMax = gr.right() - sliderLength + 1;
|
||||
} else {
|
||||
sliderLength = sr.height();
|
||||
sliderMin = gr.y();
|
||||
sliderMax = gr.bottom() - sliderLength + 1;
|
||||
}
|
||||
if (orientation() == Qt::Horizontal)
|
||||
{
|
||||
sliderLength = sr.width();
|
||||
sliderMin = gr.x();
|
||||
sliderMax = gr.right() - sliderLength + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sliderLength = sr.height();
|
||||
sliderMin = gr.y();
|
||||
sliderMax = gr.bottom() - sliderLength + 1;
|
||||
}
|
||||
|
||||
QPoint pr = pos - sr.center() + sr.topLeft();
|
||||
int p = orientation() == Qt::Horizontal ? pr.x() : pr.y();
|
||||
QPoint pr = pos - sr.center() + sr.topLeft();
|
||||
int p = orientation() == Qt::Horizontal ? pr.x() : pr.y();
|
||||
|
||||
return QStyle::sliderValueFromPosition(minimum(), maximum(), p - sliderMin,
|
||||
sliderMax - sliderMin, opt.upsideDown);
|
||||
return QStyle::sliderValueFromPosition(minimum(), maximum(), p - sliderMin,
|
||||
sliderMax - sliderMin, opt.upsideDown);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,16 +7,16 @@
|
|||
|
||||
class ClickableSlider : public QSlider
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ClickableSlider(QWidget *parent = nullptr);
|
||||
explicit ClickableSlider(Qt::Orientation orientation, QWidget *parent = nullptr);
|
||||
explicit ClickableSlider(QWidget *parent = nullptr);
|
||||
explicit ClickableSlider(Qt::Orientation orientation, QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
int pixelPosToRangeValue(const QPoint &pos);
|
||||
int pixelPosToRangeValue(const QPoint &pos);
|
||||
};
|
||||
|
||||
#endif // CLICKABLESLIDER_H
|
||||
|
|
@ -5,10 +5,10 @@
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
QApplication app(argc, argv);
|
||||
|
||||
MainWindow window;
|
||||
window.show();
|
||||
MainWindow window;
|
||||
window.show();
|
||||
|
||||
return app.exec();
|
||||
return app.exec();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue