#include #include #include #include #include #include #include #include #include #include "qmpsettingswindow.hpp" #include "qmpdeviceprioritydialog.hpp" #include "ui_qmpsettingswindow.h" #include "qmpmainwindow.hpp" void qmpFluidForEachOpt(void* data,const char*,const char* option) { QComboBox *pcb=(QComboBox*)data; pcb->addItem(option); } qmpSettingsWindow::qmpSettingsWindow(qmpSettings *qmpsettings,QWidget *parent) : QDialog(parent), ui(new Ui::qmpSettingsWindow) { ui->setupUi(this);customOptions.clear();customOptPages.clear(); connect(this,&qmpSettingsWindow::dialogClosing,(qmpMainWindow*)parent,&qmpMainWindow::dialogClosed); settings=qmpsettings; cwt=new qmpCustomizeWindow(this); cwa=new qmpCustomizeWindow(this); dps=new qmpDevPropDialog(this); devpriod=new qmpDevicePriorityDialog(this); } qmpSettingsWindow::~qmpSettingsWindow() { delete ui; } void qmpSettingsWindow::closeEvent(QCloseEvent *event) { setVisible(false); loadOption(); emit dialogClosing(); event->accept(); } void qmpSettingsWindow::hideEvent(QHideEvent *event) { emit dialogClosing(); event->accept(); } void qmpSettingsWindow::on_buttonBox_accepted() { saveOption(); qmpMainWindow::getInstance()->setupWidget(); emit dialogClosing(); } void qmpSettingsWindow::on_buttonBox_rejected() { loadOption(); emit dialogClosing(); } void qmpSettingsWindow::updatePluginList(qmpPluginManager *pmgr) { std::vector *plugins=pmgr->getPlugins(); QVariant *data=static_cast(settings->getOptionCustom("DisabledPlugins")); QList disabled_plugins_l=static_cast(data)->toList(); delete data; std::set disabled_plugins_s; for(auto &i:disabled_plugins_l) disabled_plugins_s.insert(i.toString().toStdString()); for(unsigned i=0;isize();++i) { bool enabled=disabled_plugins_s.find(plugins->at(i).name)==disabled_plugins_s.end(); plugins->at(i).enabled=enabled; } } void qmpSettingsWindow::postInit() { setupWidgets(); int sf=0; QVariant *data=static_cast(settings->getOptionCustom("FluidSynth/SoundFonts")); for(auto i:data->toList()) if(!i.toString().startsWith('#')) { sf=1; break; } delete data; std::string selecteddev; std::vector devs=qmpMainWindow::getInstance()->getPlayer()->getMidiOutDevices(); std::set devset; for(auto dev:devs)devset.insert(dev); QVariant *devpriov=static_cast(qmpMainWindow::getInstance()->getSettings()->getOptionCustom("Midi/DevicePriority")); QList devprio=devpriov->toList(); delete devpriov; for(auto &setdev:devprio) if(devset.find(setdev.toString().toStdString())!=devset.end()) { selecteddev=setdev.toString().toStdString(); break; } if(selecteddev=="Internal FluidSynth"&&!sf) { if(QMessageBox::question(this, tr("No soundfont loaded"), tr("Internal fluidsynth is the only available MIDI output but it has no soundfont set. " "Would you like to setup soundfonts now? You may have to reload the internal synth afterwards."))==QMessageBox::Yes) { show(); ui->tabWidget->setCurrentWidget(qobject_cast(pageForTab("SoundFonts")->parent())); } } } void qmpSettingsWindow::registerCustomizeWidgetOptions() { QPushButton *pbCustomizeToolbar=new QPushButton(tr("Customize...")); QPushButton *pbCustomizeActions=new QPushButton(tr("Customize...")); QVariant toolbar_def_val=QList({"Channel","Playlist","Effects","Visualization"}); QVariant actions_def_val=QList({"FileInfo","Render","Panic","ReloadSynth"}); settings->registerOptionCustom("Behavior","Customize toolbar","Behavior/Toolbar",pbCustomizeToolbar,&toolbar_def_val,std::bind(&qmpCustomizeWindow::save,cwt),std::bind(&qmpCustomizeWindow::load,cwt,std::placeholders::_1)); settings->registerOptionCustom("Behavior","Customize actions","Behavior/Actions",pbCustomizeActions,&actions_def_val,std::bind(&qmpCustomizeWindow::save,cwa),std::bind(&qmpCustomizeWindow::load,cwa,std::placeholders::_1)); connect(pbCustomizeToolbar,&QPushButton::clicked,[this]{loadOption("Behavior/Toolbar");cwt->show();}); connect(pbCustomizeActions,&QPushButton::clicked,[this]{loadOption("Behavior/Actions");cwa->show();}); connect(cwt,&QDialog::accepted,[this]{saveOption("Behavior/Toolbar");qmpMainWindow::getInstance()->setupWidget();}); connect(cwa,&QDialog::accepted,[this]{saveOption("Behavior/Actions");qmpMainWindow::getInstance()->setupWidget();}); connect(cwt,&QDialog::rejected,[this]{loadOption("Behavior/Toolbar");}); connect(cwa,&QDialog::rejected,[this]{loadOption("Behavior/Actions");}); qmpMainWindow::getInstance()->setupWidget(); } void qmpSettingsWindow::registerSoundFontOption() { QWidget *sfpanel=new QWidget(); sfpanel->setLayout(new QVBoxLayout); sfpanel->layout()->setMargin(0); QTableWidget *twsf=new QTableWidget(); twsf->setColumnCount(2); twsf->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents); twsf->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); twsf->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows); twsf->setHorizontalHeaderLabels({tr("E"),tr("Path")}); twsf->setHorizontalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); twsf->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); sfpanel->layout()->addWidget(twsf); QWidget *controls=new QWidget(); controls->setLayout(new QHBoxLayout); controls->layout()->setMargin(0); QPushButton *pbsfadd=new QPushButton(style()->standardIcon(QStyle::StandardPixmap::SP_DialogOpenButton),QString()); QPushButton *pbsfrem=new QPushButton(style()->standardIcon(QStyle::StandardPixmap::SP_DialogDiscardButton),QString()); QPushButton *pbsfmup=new QPushButton(style()->standardIcon(QStyle::StandardPixmap::SP_ArrowUp),QString()); QPushButton *pbsfmdn=new QPushButton(style()->standardIcon(QStyle::StandardPixmap::SP_ArrowDown),QString()); controls->layout()->addWidget(pbsfadd); controls->layout()->addWidget(pbsfrem); controls->layout()->addWidget(pbsfmup); controls->layout()->addWidget(pbsfmdn); sfpanel->layout()->addWidget(controls); connect(pbsfadd,&QPushButton::clicked,[twsf,this]{ QStringList sl=QFileDialog::getOpenFileNames(this,"Add File","","SoundFont files (*.sf2)"); for(int i=0;iinsertRow(twsf->rowCount()); QTableWidgetItem *sfn,*sfe; twsf->setItem(twsf->rowCount()-1,1,sfn=new QTableWidgetItem(sl[i])); twsf->setItem(twsf->rowCount()-1,0,sfe=new QTableWidgetItem()); sfe->setCheckState(Qt::CheckState::Unchecked); sfn->setFlags(Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable); sfe->setFlags(Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable|Qt::ItemFlag::ItemIsUserCheckable); } }); connect(pbsfrem,&QPushButton::clicked,[twsf]{ QList sl=twsf->selectedItems(); for(int i=0;iremoveRow(twsf->row(sl[i])); }); connect(pbsfmup,&QPushButton::clicked,[twsf]{ int cid=twsf->currentRow();if(!cid)return; QTableWidgetItem *ci=twsf->takeItem(cid,1); QTableWidgetItem *ce=twsf->takeItem(cid,0); twsf->removeRow(cid); twsf->insertRow(cid-1); twsf->setItem(cid-1,0,ce); twsf->setItem(cid-1,1,ci); twsf->setCurrentCell(cid-1,1); }); connect(pbsfmdn,&QPushButton::clicked,[twsf]{ int cid=twsf->currentRow();if(cid==twsf->rowCount()-1)return; QTableWidgetItem *ci=twsf->takeItem(cid,1); QTableWidgetItem *ce=twsf->takeItem(cid,0); twsf->removeRow(cid); twsf->insertRow(cid+1); twsf->setItem(cid+1,0,ce); twsf->setItem(cid+1,1,ci); twsf->setCurrentCell(cid+1,1); }); QVariant sf_def_val=QList(); auto save_func=[twsf]()->void*{ QList sflist; for(int i=0;irowCount();++i) { QString sfs=twsf->item(i,1)->text(); if(twsf->item(i,0)->checkState()==Qt::CheckState::Unchecked) sfs="#"+sfs; sflist.push_back(sfs); } return new QVariant(sflist); }; auto load_func=[twsf](void* data){ QList sflist=static_cast(data)->toList(); twsf->clearContents(); twsf->setRowCount(0); for(int i=0;iinsertRow(i); QTableWidgetItem *sfn,*sfe; QString sf=sflist[i].toString(); bool enabled=!sf.startsWith('#'); if(!enabled)sf=sf.mid(1); twsf->setItem(i,1,sfn=new QTableWidgetItem(sf)); twsf->setItem(i,0,sfe=new QTableWidgetItem()); sfn->setFlags(Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable); sfe->setFlags(Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable|Qt::ItemFlag::ItemIsUserCheckable); sfe->setCheckState(enabled?Qt::CheckState::Checked:Qt::CheckState::Unchecked); } }; settings->registerOptionCustom("SoundFonts","","FluidSynth/SoundFonts",sfpanel,&sf_def_val,save_func,load_func); } void qmpSettingsWindow::registerPluginOption(qmpPluginManager *pmgr) { QTableWidget *twplugins=new QTableWidget(); twplugins->setColumnCount(4); twplugins->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents); twplugins->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); twplugins->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows); twplugins->setHorizontalHeaderLabels({tr("E"),tr("Plugin Name"),tr("Version"),tr("Path")}); twplugins->setHorizontalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); twplugins->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); QVariant ep_def_val=QList(); auto save_func=[twplugins,this]()->void*{ QVariant *data=static_cast(settings->getOptionCustom("DisabledPlugins")); QList disabled_plugins_ol=static_cast(data)->toList(); delete data; std::set disabled_plugins_s; for(auto &i:disabled_plugins_ol) disabled_plugins_s.insert(i.toString().toStdString()); for(int i=0;irowCount();++i) { QString pn=twplugins->item(i,1)->text(); if(twplugins->item(i,0)->checkState()==Qt::CheckState::Unchecked) disabled_plugins_s.insert(pn.toStdString()); else disabled_plugins_s.erase(pn.toStdString()); } QList disabled_plugins; for(auto &i:disabled_plugins_s) disabled_plugins.push_back(QString(i.c_str())); return new QVariant(disabled_plugins); }; auto load_func=[twplugins,pmgr](void* data){ QList disabled_plugins_l=static_cast(data)->toList(); std::set disabled_plugins; for(auto i:disabled_plugins_l) disabled_plugins.insert(i.toString().toStdString()); twplugins->clearContents(); twplugins->setRowCount(0); std::vector *plugins=pmgr->getPlugins(); for(int i=0;static_cast(i)size();++i) { twplugins->insertRow(i); qmpPlugin &p=plugins->at(static_cast(i)); QTableWidgetItem *icb; twplugins->setItem(i,0,icb=new QTableWidgetItem()); bool enabled=disabled_plugins.find(p.name)==disabled_plugins.end(); icb->setCheckState(enabled?Qt::CheckState::Checked:Qt::CheckState::Unchecked); icb->setFlags(Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable|Qt::ItemFlag::ItemIsUserCheckable); twplugins->setItem(i,1,new QTableWidgetItem(p.name.c_str())); twplugins->setItem(i,2,new QTableWidgetItem(p.version.c_str())); twplugins->setItem(i,3,new QTableWidgetItem(p.path.c_str())); for(int j=1;j<=3;++j) twplugins->item(i,j)->setFlags(Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable); } }; settings->registerOptionCustom("Plugins","","DisabledPlugins",twplugins,&ep_def_val,save_func,load_func); } void qmpSettingsWindow::registerExtraMidiOptions() { QPushButton *pbDevPrio=new QPushButton("..."); connect(pbDevPrio,&QPushButton::clicked,[this]{loadOption("Midi/DevicePriority");devpriod->show();}); connect(devpriod,&QDialog::accepted,[this]{saveOption("Midi/DevicePriority");}); connect(devpriod,&QDialog::rejected,[this]{loadOption("Midi/DevicePriority");}); QVariant devprio_def_val=QList({"Internal FluidSynth"}); settings->registerOptionCustom("MIDI","Select MIDI output devices","Midi/DevicePriority",pbDevPrio,&devprio_def_val,std::bind(&qmpDevicePriorityDialog::save,devpriod),std::bind(&qmpDevicePriorityDialog::load,devpriod,std::placeholders::_1)); QPushButton *pbDevProp=new QPushButton("..."); connect(pbDevProp,&QPushButton::clicked,[this]{loadOption("Midi/DeviceInitializationFiles");dps->show();}); connect(dps,&QDialog::accepted,[this]{saveOption("Midi/DeviceInitializationFiles");}); connect(dps,&QDialog::rejected,[this]{loadOption("Midi/DeviceInitializationFiles");}); QVariant devprop_def_val=QList({}); settings->registerOptionCustom("MIDI","External MIDI device setup","Midi/DeviceInitializationFiles",pbDevProp,&devprop_def_val,std::bind(&qmpDevPropDialog::save,dps),std::bind(&qmpDevPropDialog::load,dps,std::placeholders::_1)); } void qmpSettingsWindow::saveOption(std::string key) { auto save_opt=[this](std::string& key)->QVariant { qmpOption &o=settings->options[key]; QVariant ret; switch(o.type) { case qmpOption::ParameterType::parameter_int: { QSpinBox *sb=qobject_cast(o.widget); if(sb) ret=sb->value(); } break; case qmpOption::ParameterType::parameter_uint: { QHexSpinBox *sb=qobject_cast(o.widget); if(sb) { int val=sb->value(); ret=reinterpret_cast(val); } } break; case qmpOption::ParameterType::parameter_bool: { QCheckBox *cb=qobject_cast(o.widget); if(cb) ret=cb->isChecked(); } break; case qmpOption::ParameterType::parameter_double: { QDoubleSpinBox *sb=qobject_cast(o.widget); if(sb) ret=sb->value(); } break; case qmpOption::ParameterType::parameter_str: { QLineEdit *le=qobject_cast(o.widget); if(le) ret=le->text(); } break; case qmpOption::ParameterType::parameter_enum: { QComboBox *cb=qobject_cast(o.widget); if(cb) ret=cb->currentText(); } break; case qmpOption::ParameterType::parameter_url: { QFileEdit *fe=qobject_cast(o.widget); if(fe) ret=fe->text(); } break; default: if(o.save_func) { QVariant* var=static_cast(o.save_func()); ret=QVariant(*var); delete var; } break; } return ret; }; if(key.length()) { QVariant r=save_opt(key); if(r.isValid()) settings->settings->setValue(QString(key.c_str()),r); } else for(std::string& key:settings->optionlist) { QVariant r=save_opt(key); if(r.isValid()) settings->settings->setValue(QString(key.c_str()),r); } settings->settings->sync(); } void qmpSettingsWindow::loadOption(std::string key) { auto load_opt=[this](std::string& key) { qmpOption &o=settings->options[key]; switch(o.type) { case qmpOption::ParameterType::parameter_int: { QSpinBox *sb=qobject_cast(o.widget); if(sb) sb->setValue(settings->getOptionInt(key)); } break; case qmpOption::ParameterType::parameter_uint: { QHexSpinBox *sb=qobject_cast(o.widget); if(sb) sb->setValue(settings->getOptionUint(key)); } break; case qmpOption::ParameterType::parameter_bool: { QCheckBox *cb=qobject_cast(o.widget); if(cb) cb->setChecked(settings->getOptionBool(key)); } break; case qmpOption::ParameterType::parameter_double: { QDoubleSpinBox *sb=qobject_cast(o.widget); if(sb) sb->setValue(settings->getOptionDouble(key)); } break; case qmpOption::ParameterType::parameter_str: { QLineEdit *le=qobject_cast(o.widget); if(le) le->setText(QString(settings->getOptionString(key).c_str())); } break; case qmpOption::ParameterType::parameter_enum: { QComboBox *cb=qobject_cast(o.widget); if(cb) cb->setCurrentIndex(settings->getOptionEnumInt(key)); } break; case qmpOption::ParameterType::parameter_url: { QFileEdit *fe=qobject_cast(o.widget); if(fe) fe->setText(QString(settings->getOptionString(key).c_str())); } break; default: if(o.load_func) { void *var=settings->getOptionCustom(key); o.load_func(var); delete static_cast(var); } break; } }; if(key.length())load_opt(key); else for(std::string& key:settings->optionlist) load_opt(key); } void qmpSettingsWindow::setupWidgets() { for(std::string& key:settings->optionlist) { if(!settings->options[key].desc.length()&&settings->options[key].type!=qmpOption::ParameterType::parameter_custom) continue; QWidget *optw=nullptr; qmpOption &o=settings->options[key]; switch(o.type) { case qmpOption::ParameterType::parameter_int: { QSpinBox *sb=new QSpinBox; sb->setMinimum(o.minv.toInt()); sb->setMaximum(o.maxv.toInt()); sb->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed); optw=sb; } break; case qmpOption::ParameterType::parameter_uint: { QHexSpinBox *sb=new QHexSpinBox; sb->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed); optw=sb; } break; case qmpOption::ParameterType::parameter_bool: { QCheckBox *cb=new QCheckBox(QString(o.desc.c_str())); cb->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); optw=cb; } break; case qmpOption::ParameterType::parameter_double: { QDoubleSpinBox *sb=new QDoubleSpinBox; sb->setMinimum(o.minv.toDouble()); sb->setMaximum(o.maxv.toDouble()); sb->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed); optw=sb; } break; case qmpOption::ParameterType::parameter_str: { QLineEdit* te=new QLineEdit(); te->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed); optw=te; } break; case qmpOption::ParameterType::parameter_enum: { QComboBox* cb=new QComboBox(); for(std::string& item:o.enumlist)cb->addItem(QString(item.c_str())); cb->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed); optw=cb; } break; case qmpOption::ParameterType::parameter_url: { QFileEdit* fe=new QFileEdit(); fe->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed); optw=fe; } break; default: optw=o.widget; break; } o.widget=optw; QGridLayout* page=pageForTab(o.tab); if(o.type==qmpOption::ParameterType::parameter_bool|| (o.type==qmpOption::parameter_custom&&!o.desc.length())) { int row=page->rowCount(); page->addWidget(o.widget,row,0,1,2); } else { QLabel* lb=new QLabel(o.desc.c_str(),page->parentWidget()); lb->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); int row=page->rowCount(); page->addWidget(lb,row,0); page->addWidget(o.widget,row,1); } } loadOption(); } QGridLayout* qmpSettingsWindow::pageForTab(std::string tab) { if(customOptPages.find(tab)!=customOptPages.end()) return customOptPages[tab]; QWidget* w=new QWidget; QGridLayout* page=new QGridLayout(w); w->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); ui->tabWidget->addTab(w,QString(tab.c_str())); customOptPages[tab]=page; return page; } QFileEdit::QFileEdit(QWidget *par):QWidget(par) { QHBoxLayout *layout=new QHBoxLayout(this); layout->setMargin(0); le=new QLineEdit(this); layout->addWidget(le); tb=new QToolButton(this); tb->setText("..."); layout->addWidget(tb); connect(tb,&QToolButton::clicked,this,&QFileEdit::chooseFile); } QString QFileEdit::text(){return le->text();} void QFileEdit::setText(const QString& s){le->setText(s);} void QFileEdit::chooseFile() { QString s=QFileDialog::getOpenFileName(nullptr,tr("Select a file"),QFileInfo(text()).dir().absolutePath()); if(s.length())setText(s); }