/****************************************************************************** * The MIT License (MIT) * * Copyright (c) 2017-2019 Baldur Karlsson * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. ******************************************************************************/ #include "SettingsDialog.h" #include #include #include #include "Code/Interface/QRDInterface.h" #include "Code/QRDUtils.h" #include "Styles/StyleData.h" #include "Widgets/OrderedListEditor.h" #include "CaptureDialog.h" #include "ui_SettingsDialog.h" SettingsDialog::SettingsDialog(ICaptureContext &ctx, QWidget *parent) : QDialog(parent), ui(new Ui::SettingsDialog), m_Ctx(ctx) { ui->setupUi(this); QString styleChooseTooltip = ui->UIStyle->toolTip(); for(int i = 0; i < StyleData::numAvailable; i++) styleChooseTooltip += lit("
- ") + StyleData::availStyles[i].styleDescription; ui->UIStyle->setToolTip(styleChooseTooltip); ui->UIStyle_label->setToolTip(styleChooseTooltip); for(int i = 0; i < StyleData::numAvailable; i++) ui->UIStyle->addItem(StyleData::availStyles[i].styleName); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); ui->tabWidget->tabBar()->setVisible(false); for(int i = 0; i < ui->tabWidget->count(); i++) ui->pages->addItem(ui->tabWidget->tabText(i)); m_Init = true; for(int i = 0; i < (int)TimeUnit::Count; i++) { ui->EventBrowser_TimeUnit->addItem(UnitSuffix((TimeUnit)i)); } ui->pages->clearSelection(); ui->pages->setItemSelected(ui->pages->item(0), true); ui->tabWidget->setCurrentIndex(0); ui->pages->setMinimumWidth(ui->pages->sizeHintForColumn(0)); ui->pages->adjustSize(); for(int i = 0; i < StyleData::numAvailable; i++) { if(StyleData::availStyles[i].styleID == m_Ctx.Config().UIStyle) { ui->UIStyle->setCurrentIndex(i); break; } } ui->saveDirectory->setText(m_Ctx.Config().DefaultCaptureSaveDirectory); ui->tempDirectory->setText(m_Ctx.Config().TemporaryCaptureDirectory); ui->shaderTools->setColumnCount(2); ui->shaderTools->setHorizontalHeaderLabels(QStringList() << tr("Tool") << tr("Process")); ui->shaderTools->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Interactive); ui->shaderTools->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); for(const ShaderProcessingTool &tool : m_Ctx.Config().ShaderProcessors) addProcessor(tool); ui->shaderTools->horizontalHeader()->resizeSection(0, 100); ui->shaderTools->verticalHeader()->setSectionsMovable(true); ui->shaderTools->verticalHeader()->setMinimumWidth(20); ui->deleteShaderTool->setEnabled(false); ui->editShaderTool->setEnabled(false); ui->ExternalTool_RGPIntegration->setChecked(m_Ctx.Config().ExternalTool_RGPIntegration); ui->ExternalTool_RadeonGPUProfiler->setText(m_Ctx.Config().ExternalTool_RadeonGPUProfiler); ui->Android_SDKPath->setText(m_Ctx.Config().Android_SDKPath); ui->Android_JDKPath->setText(m_Ctx.Config().Android_JDKPath); ui->Android_MaxConnectTimeout->setValue(m_Ctx.Config().Android_MaxConnectTimeout); ui->TextureViewer_ResetRange->setChecked(m_Ctx.Config().TextureViewer_ResetRange); ui->TextureViewer_PerTexSettings->setChecked(m_Ctx.Config().TextureViewer_PerTexSettings); ui->TextureViewer_PerTexYFlip->setChecked(m_Ctx.Config().TextureViewer_PerTexYFlip); ui->ShaderViewer_FriendlyNaming->setChecked(m_Ctx.Config().ShaderViewer_FriendlyNaming); ui->CheckUpdate_AllowChecks->setChecked(m_Ctx.Config().CheckUpdate_AllowChecks); ui->Font_PreferMonospaced->setChecked(m_Ctx.Config().Font_PreferMonospaced); ui->TextureViewer_PerTexYFlip->setEnabled(ui->TextureViewer_PerTexSettings->isChecked()); ui->AlwaysReplayLocally->setChecked(m_Ctx.Config().AlwaysReplayLocally); #if RENDERDOC_ANALYTICS_ENABLE if(m_Ctx.Config().Analytics_TotalOptOut) { ui->analyticsAutoSubmit->setChecked(false); ui->analyticsManualCheck->setChecked(false); ui->analyticsOptOut->setChecked(true); // once we've started with analytics disabled, only a restart can re-enable them. ui->analyticsAutoSubmit->setText(ui->analyticsAutoSubmit->text() + tr(" (Requires Restart)")); ui->analyticsManualCheck->setText(ui->analyticsManualCheck->text() + tr(" (Requires Restart)")); } else if(m_Ctx.Config().Analytics_ManualCheck) { ui->analyticsAutoSubmit->setChecked(false); ui->analyticsManualCheck->setChecked(true); ui->analyticsOptOut->setChecked(false); } else { ui->analyticsAutoSubmit->setChecked(true); ui->analyticsManualCheck->setChecked(false); ui->analyticsOptOut->setChecked(false); } #else ui->analyticsDescribeLabel->setText(tr("Analytics was disabled at compile time.")); ui->analyticsAutoSubmit->setEnabled(false); ui->analyticsManualCheck->setEnabled(false); ui->analyticsOptOut->setEnabled(false); #endif ui->AllowGlobalHook->setChecked(m_Ctx.Config().AllowGlobalHook); ui->EventBrowser_TimeUnit->setCurrentIndex((int)m_Ctx.Config().EventBrowser_TimeUnit); ui->EventBrowser_AddFake->setChecked(m_Ctx.Config().EventBrowser_AddFake); ui->EventBrowser_HideEmpty->setChecked(m_Ctx.Config().EventBrowser_HideEmpty); ui->EventBrowser_HideAPICalls->setChecked(m_Ctx.Config().EventBrowser_HideAPICalls); ui->EventBrowser_ApplyColors->setChecked(m_Ctx.Config().EventBrowser_ApplyColors); ui->EventBrowser_ColorEventRow->setChecked(m_Ctx.Config().EventBrowser_ColorEventRow); // disable sub-checkbox ui->EventBrowser_ColorEventRow->setEnabled(ui->EventBrowser_ApplyColors->isChecked()); ui->Comments_ShowOnLoad->setChecked(m_Ctx.Config().Comments_ShowOnLoad); ui->Formatter_MinFigures->setValue(m_Ctx.Config().Formatter_MinFigures); ui->Formatter_MaxFigures->setValue(m_Ctx.Config().Formatter_MaxFigures); ui->Formatter_NegExp->setValue(m_Ctx.Config().Formatter_NegExp); ui->Formatter_PosExp->setValue(m_Ctx.Config().Formatter_PosExp); if(!RENDERDOC_CanGlobalHook()) { ui->AllowGlobalHook->setEnabled(false); QString disabledTooltip = tr("Global hooking is not supported on this platform"); ui->AllowGlobalHook->setToolTip(disabledTooltip); ui->globalHookLabel->setToolTip(disabledTooltip); } m_Init = false; QObject::connect(ui->shaderTools->verticalHeader(), &QHeaderView::sectionMoved, this, &SettingsDialog::shaderTools_rowMoved); QObject::connect(ui->Formatter_MinFigures, OverloadedSlot::of(&QSpinBox::valueChanged), this, &SettingsDialog::formatter_valueChanged); QObject::connect(ui->Formatter_MaxFigures, OverloadedSlot::of(&QSpinBox::valueChanged), this, &SettingsDialog::formatter_valueChanged); QObject::connect(ui->Formatter_NegExp, OverloadedSlot::of(&QSpinBox::valueChanged), this, &SettingsDialog::formatter_valueChanged); QObject::connect(ui->Formatter_PosExp, OverloadedSlot::of(&QSpinBox::valueChanged), this, &SettingsDialog::formatter_valueChanged); } SettingsDialog::~SettingsDialog() { delete ui; } void SettingsDialog::focusItem(QString item) { for(int i = 0; i < ui->tabWidget->count(); i++) { QWidget *w = ui->tabWidget->widget(i)->findChild(item); if(w) { ui->tabWidget->setCurrentIndex(i); w->setFocus(Qt::MouseFocusReason); return; } } qCritical() << "Couldn't find" << item << "to focus on settings dialog"; } void SettingsDialog::on_pages_itemSelectionChanged() { QList sel = ui->pages->selectedItems(); if(sel.empty()) { ui->pages->setItemSelected(ui->pages->item(ui->tabWidget->currentIndex()), true); } else { ui->tabWidget->setCurrentIndex(ui->pages->row(sel[0])); } } void SettingsDialog::on_okButton_accepted() { setResult(1); accept(); } // general void SettingsDialog::formatter_valueChanged(int val) { m_Ctx.Config().Formatter_MinFigures = ui->Formatter_MinFigures->value(); m_Ctx.Config().Formatter_MaxFigures = ui->Formatter_MaxFigures->value(); m_Ctx.Config().Formatter_NegExp = ui->Formatter_NegExp->value(); m_Ctx.Config().Formatter_PosExp = ui->Formatter_PosExp->value(); m_Ctx.Config().SetupFormatting(); m_Ctx.Config().Save(); } void SettingsDialog::on_tempDirectory_textEdited(const QString &dir) { if(QDir(dir).exists()) m_Ctx.Config().TemporaryCaptureDirectory = dir; else m_Ctx.Config().TemporaryCaptureDirectory = QString(); m_Ctx.Config().Save(); } void SettingsDialog::on_saveDirectory_textEdited(const QString &dir) { if(QDir(dir).exists() || dir.isEmpty()) m_Ctx.Config().DefaultCaptureSaveDirectory = dir; m_Ctx.Config().Save(); } void SettingsDialog::on_browseSaveCaptureDirectory_clicked() { QString dir = RDDialog::getExistingDirectory(this, tr("Choose default directory for saving captures"), m_Ctx.Config().DefaultCaptureSaveDirectory); if(!dir.isEmpty()) { m_Ctx.Config().DefaultCaptureSaveDirectory = dir; ui->saveDirectory->setText(dir); } m_Ctx.Config().Save(); } void SettingsDialog::on_AllowGlobalHook_toggled(bool checked) { m_Ctx.Config().AllowGlobalHook = ui->AllowGlobalHook->isChecked(); m_Ctx.Config().Save(); if(m_Ctx.HasCaptureDialog()) m_Ctx.GetCaptureDialog()->UpdateGlobalHook(); } void SettingsDialog::on_CheckUpdate_AllowChecks_toggled(bool checked) { m_Ctx.Config().CheckUpdate_AllowChecks = ui->CheckUpdate_AllowChecks->isChecked(); if(!m_Ctx.Config().CheckUpdate_AllowChecks) { m_Ctx.Config().CheckUpdate_UpdateAvailable = false; m_Ctx.Config().CheckUpdate_UpdateResponse = ""; } m_Ctx.Config().Save(); } void SettingsDialog::on_Font_PreferMonospaced_toggled(bool checked) { m_Ctx.Config().Font_PreferMonospaced = ui->Font_PreferMonospaced->isChecked(); m_Ctx.Config().SetupFormatting(); m_Ctx.Config().Save(); } void SettingsDialog::on_AlwaysReplayLocally_toggled(bool checked) { m_Ctx.Config().AlwaysReplayLocally = ui->AlwaysReplayLocally->isChecked(); m_Ctx.Config().Save(); } void SettingsDialog::on_analyticsAutoSubmit_toggled(bool checked) { if(checked) { m_Ctx.Config().Analytics_ManualCheck = false; m_Ctx.Config().Analytics_TotalOptOut = false; m_Ctx.Config().Save(); } } void SettingsDialog::on_analyticsManualCheck_toggled(bool checked) { if(checked) { m_Ctx.Config().Analytics_ManualCheck = true; m_Ctx.Config().Analytics_TotalOptOut = false; m_Ctx.Config().Save(); } } void SettingsDialog::on_analyticsOptOut_toggled(bool checked) { if(checked) { m_Ctx.Config().Analytics_ManualCheck = false; m_Ctx.Config().Analytics_TotalOptOut = true; // immediately disable the analytics collection and ensure it can't send any reports. Analytics::Disable(); m_Ctx.Config().Save(); } } void SettingsDialog::on_analyticsDescribeLabel_linkActivated(const QString &link) { Analytics::DocumentReport(); } // core void SettingsDialog::on_chooseSearchPaths_clicked() { QDialog listEditor; listEditor.setWindowTitle(tr("Shader debug info search paths")); listEditor.setWindowFlags(listEditor.windowFlags() & ~Qt::WindowContextHelpButtonHint); OrderedListEditor list(tr("Search Path"), BrowseMode::Folder); QVBoxLayout layout; QDialogButtonBox okCancel; okCancel.setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); layout.addWidget(&list); layout.addWidget(&okCancel); QObject::connect(&okCancel, &QDialogButtonBox::accepted, &listEditor, &QDialog::accept); QObject::connect(&okCancel, &QDialogButtonBox::rejected, &listEditor, &QDialog::reject); listEditor.setLayout(&layout); QString setting = m_Ctx.Config().GetConfigSetting("shader.debug.searchPaths"); list.setItems(setting.split(QLatin1Char(';'), QString::SkipEmptyParts)); int res = RDDialog::show(&listEditor); if(res) m_Ctx.Config().SetConfigSetting(lit("shader.debug.searchPaths"), list.getItems().join(QLatin1Char(';'))); } void SettingsDialog::on_ExternalTool_RGPIntegration_toggled(bool checked) { m_Ctx.Config().ExternalTool_RGPIntegration = checked; m_Ctx.Config().Save(); } void SettingsDialog::on_ExternalTool_RadeonGPUProfiler_textEdited(const QString &rgp) { if(QFileInfo::exists(rgp) || rgp.isEmpty()) m_Ctx.Config().ExternalTool_RadeonGPUProfiler = rgp; m_Ctx.Config().Save(); } void SettingsDialog::on_browseRGPPath_clicked() { QString rgp = RDDialog::getExecutableFileName( this, tr("Locate RGP executable"), QFileInfo(m_Ctx.Config().ExternalTool_RadeonGPUProfiler).absoluteDir().path()); if(!rgp.isEmpty()) { ui->ExternalTool_RadeonGPUProfiler->setText(rgp); m_Ctx.Config().ExternalTool_RadeonGPUProfiler = rgp; } m_Ctx.Config().Save(); } // texture viewer void SettingsDialog::on_TextureViewer_PerTexSettings_toggled(bool checked) { m_Ctx.Config().TextureViewer_PerTexSettings = ui->TextureViewer_PerTexSettings->isChecked(); ui->TextureViewer_PerTexYFlip->setEnabled(ui->TextureViewer_PerTexSettings->isChecked()); m_Ctx.Config().Save(); } void SettingsDialog::on_TextureViewer_PerTexYFlip_toggled(bool checked) { m_Ctx.Config().TextureViewer_PerTexYFlip = ui->TextureViewer_PerTexYFlip->isChecked(); m_Ctx.Config().Save(); } void SettingsDialog::on_TextureViewer_ResetRange_toggled(bool checked) { m_Ctx.Config().TextureViewer_ResetRange = ui->TextureViewer_ResetRange->isChecked(); m_Ctx.Config().Save(); } // shader viewer void SettingsDialog::on_ShaderViewer_FriendlyNaming_toggled(bool checked) { m_Ctx.Config().ShaderViewer_FriendlyNaming = ui->ShaderViewer_FriendlyNaming->isChecked(); m_Ctx.Config().Save(); } void SettingsDialog::addProcessor(const ShaderProcessingTool &tool) { int row = ui->shaderTools->rowCount(); ui->shaderTools->insertRow(row); ui->shaderTools->setVerticalHeaderItem(row, new QTableWidgetItem(QString())); ui->shaderTools->setItem(row, 0, new QTableWidgetItem(tool.name)); ui->shaderTools->setItem( row, 1, new QTableWidgetItem(QFormatStr("%1 -> %2").arg(ToQStr(tool.input)).arg(ToQStr(tool.output)))); } bool SettingsDialog::editTool(int existing, ShaderProcessingTool &tool) { QDialog dialog; dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint); dialog.setWindowTitle(tr("Configure Shader Processing Tool")); dialog.resize(400, 0); QGridLayout grid(&dialog); QLabel *lab; lab = new QLabel(tr("Name:"), &dialog); lab->setAlignment(Qt::AlignRight | Qt::AlignTop); grid.addWidget(lab, 0, 0, 1, 1); lab = new QLabel(tr("Tool Type:"), &dialog); lab->setAlignment(Qt::AlignRight | Qt::AlignTop); grid.addWidget(lab, 1, 0, 1, 1); lab = new QLabel(tr("Executable:"), &dialog); lab->setAlignment(Qt::AlignRight | Qt::AlignTop); grid.addWidget(lab, 2, 0, 1, 1); lab = new QLabel(tr("Command Line:"), &dialog); lab->setAlignment(Qt::AlignRight | Qt::AlignTop); grid.addWidget(lab, 3, 0, 1, 1); lab = new QLabel(tr("Input/Output:"), &dialog); lab->setAlignment(Qt::AlignRight | Qt::AlignTop); grid.addWidget(lab, 4, 0, 1, 1); QLineEdit nameEdit; nameEdit.setPlaceholderText(lit("Tool Name")); nameEdit.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); nameEdit.setMinimumHeight(20); QStringList strs; for(KnownShaderTool t : values()) { if(t == KnownShaderTool::Unknown) strs << tr("Custom Tool"); else strs << ToQStr(t); } QComboBox toolEdit; toolEdit.addItems(strs); toolEdit.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); QHBoxLayout executableLayout; QLineEdit executableEdit; executableEdit.setPlaceholderText(lit("tool")); executableEdit.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); executableEdit.setMinimumHeight(20); QToolButton executableBrowse; executableBrowse.setText(lit("...")); executableBrowse.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); executableLayout.addWidget(&executableEdit); executableLayout.addWidget(&executableBrowse); QTextEdit argsEdit; argsEdit.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); argsEdit.setMinimumHeight(80); strs.clear(); for(ShaderEncoding enc : values()) { if(enc == ShaderEncoding::Unknown) continue; else strs << ToQStr(enc); } QHBoxLayout inputOutputLayout; QComboBox inputEdit; inputEdit.addItems(strs); QComboBox outputEdit; outputEdit.addItems(strs); inputOutputLayout.addWidget(&inputEdit); inputOutputLayout.addWidget(&outputEdit); grid.addWidget(&nameEdit, 0, 1, 1, 1); grid.addWidget(&toolEdit, 1, 1, 1, 1); grid.addLayout(&executableLayout, 2, 1, 1, 1); grid.addWidget(&argsEdit, 3, 1, 1, 1); grid.addLayout(&inputOutputLayout, 4, 1, 1, 1); QDialogButtonBox buttons; buttons.setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); grid.addWidget(&buttons, 5, 0, 1, 2); QObject::connect(&buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); QObject::connect(&buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); QObject::connect(&executableBrowse, &QToolButton::clicked, [&]() { QString initDir; QFileInfo f(executableEdit.text()); QDir dir = f.dir(); if(f.isAbsolute() && dir.exists()) { initDir = dir.absolutePath(); } QString filename = RDDialog::getExecutableFileName(this, tr("Choose executable"), initDir); if(!filename.isEmpty()) executableEdit.setText(filename); }); QObject::connect(&toolEdit, OverloadedSlot::of(&QComboBox::currentIndexChanged), [&](int index) { if(index > 0) { KnownShaderTool tool = KnownShaderTool(index); // -1 because we skip ShaderEncoding::Unknown inputEdit.setCurrentIndex(int(ToolInput(tool)) - 1); outputEdit.setCurrentIndex(int(ToolOutput(tool)) - 1); argsEdit.setEnabled(false); inputEdit.setEnabled(false); outputEdit.setEnabled(false); } else { argsEdit.setEnabled(true); inputEdit.setEnabled(true); outputEdit.setEnabled(true); } }); // -1 because we skip ShaderEncoding::Unknown inputEdit.setCurrentIndex(int(tool.input) - 1); outputEdit.setCurrentIndex(int(tool.output) - 1); executableEdit.setText(tool.executable); argsEdit.setText(tool.args); nameEdit.setText(tool.name); toolEdit.setCurrentIndex(int(tool.tool)); bool invalid = false; do { RDDialog::show(&dialog); // don't validate if they cancelled if(dialog.result() != QDialog::Accepted) return false; tool.tool = KnownShaderTool(toolEdit.currentIndex()); tool.name = nameEdit.text(); tool.executable = executableEdit.text(); tool.args = argsEdit.toPlainText(); // +1 because we skip ShaderEncoding::Unknown tool.input = ShaderEncoding(inputEdit.currentIndex() + 1); tool.output = ShaderEncoding(outputEdit.currentIndex() + 1); QString message; // ensure we don't have an invalid name if(tool.name == "Builtin") { invalid = true; message = tr("'Builtin' is a reserved tool name, please select another."); } else if(tool.name.isEmpty()) { invalid = true; message = tr("No tool name specified."); } else if(tool.executable.isEmpty()) { invalid = true; message = tr("No tool executable selected."); } else if(tool.input == ShaderEncoding::Unknown) { invalid = true; message = tr("Input type cannot be unknown."); } else if(tool.output == ShaderEncoding::Unknown) { invalid = true; message = tr("Output type cannot be unknown."); } else if(tool.tool == KnownShaderTool::Unknown && !QString(tool.args).contains(lit("{input_file}")) && !QString(tool.args).contains(lit("{stdin}"))) { invalid = true; message = tr("Custom tool arguments must include at least {input_file} or {stdin}."); } else { for(int i = 0; i < m_Ctx.Config().ShaderProcessors.count(); i++) { if(i == existing) continue; if(tool.name == m_Ctx.Config().ShaderProcessors[i].name) { invalid = true; message = tr("There's already a tool named '%1', please select another.").arg(tool.name); break; } } } if(invalid) { RDDialog::critical(this, tr("Invalid parameters specified"), message); } } while(invalid); return true; } void SettingsDialog::on_addShaderTool_clicked() { ShaderProcessingTool tool; // start with example arguments tool.args = lit("--input {input_file} --output {output_file} --mode foo"); // impossible to pick a single default, but at least show the principle. tool.input = ShaderEncoding::HLSL; tool.output = ShaderEncoding::SPIRV; bool success = editTool(-1, tool); if(success) { m_Ctx.Config().ShaderProcessors.push_back(tool); addProcessor(tool); m_Ctx.Config().Save(); } } void SettingsDialog::on_editShaderTool_clicked() { int row = -1; QModelIndexList selected = ui->shaderTools->selectionModel()->selectedRows(); if(!selected.isEmpty()) row = selected[0].row(); if(row < 0 || row >= m_Ctx.Config().ShaderProcessors.count()) return; ShaderProcessingTool tool = m_Ctx.Config().ShaderProcessors[row]; bool success = editTool(row, tool); if(success) { ui->shaderTools->setItem(row, 0, new QTableWidgetItem(tool.name)); ui->shaderTools->setItem( row, 1, new QTableWidgetItem( QFormatStr("%1 -> %2").arg(ToQStr(tool.input)).arg(ToQStr(tool.output)))); m_Ctx.Config().ShaderProcessors[row] = tool; m_Ctx.Config().Save(); } } void SettingsDialog::on_deleteShaderTool_clicked() { int row = -1; QModelIndexList selected = ui->shaderTools->selectionModel()->selectedRows(); if(!selected.isEmpty()) row = selected[0].row(); if(row < 0 || row >= m_Ctx.Config().ShaderProcessors.count()) return; const ShaderProcessingTool &tool = m_Ctx.Config().ShaderProcessors[row]; QMessageBox::StandardButton res = RDDialog::question( this, tr("Are you sure?"), tr("Are you sure you want to delete '%1'?").arg(tool.name), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); if(res == QMessageBox::Yes) { ui->shaderTools->removeRow(row); m_Ctx.Config().ShaderProcessors.erase(row); m_Ctx.Config().Save(); } } void SettingsDialog::on_shaderTools_itemSelectionChanged() { ui->deleteShaderTool->setEnabled(!ui->shaderTools->selectionModel()->selectedIndexes().empty()); ui->editShaderTool->setEnabled(ui->deleteShaderTool->isEnabled()); } void SettingsDialog::on_shaderTools_keyPress(QKeyEvent *event) { if(event->key() == Qt::Key_Delete) { ui->deleteShaderTool->click(); } if(event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { ui->editShaderTool->click(); } } void SettingsDialog::on_shaderTools_itemDoubleClicked(QTableWidgetItem *item) { ui->editShaderTool->click(); } void SettingsDialog::shaderTools_rowMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex) { if(oldVisualIndex < 0 || oldVisualIndex >= m_Ctx.Config().ShaderProcessors.count() || newVisualIndex < 0 || newVisualIndex >= m_Ctx.Config().ShaderProcessors.count()) return; ShaderProcessingTool tool = m_Ctx.Config().ShaderProcessors.at(oldVisualIndex); m_Ctx.Config().ShaderProcessors.erase(oldVisualIndex); m_Ctx.Config().ShaderProcessors.insert(newVisualIndex, tool); m_Ctx.Config().Save(); } // event browser void SettingsDialog::on_EventBrowser_TimeUnit_currentIndexChanged(int index) { if(m_Init) return; m_Ctx.Config().EventBrowser_TimeUnit = (TimeUnit)qMax(0, ui->EventBrowser_TimeUnit->currentIndex()); if(m_Ctx.HasEventBrowser()) m_Ctx.GetEventBrowser()->UpdateDurationColumn(); m_Ctx.Config().Save(); } void SettingsDialog::on_EventBrowser_AddFake_toggled(bool checked) { m_Ctx.Config().EventBrowser_AddFake = ui->EventBrowser_AddFake->isChecked(); m_Ctx.Config().Save(); } void SettingsDialog::on_EventBrowser_HideEmpty_toggled(bool checked) { m_Ctx.Config().EventBrowser_HideEmpty = ui->EventBrowser_HideEmpty->isChecked(); m_Ctx.Config().Save(); } void SettingsDialog::on_EventBrowser_HideAPICalls_toggled(bool checked) { m_Ctx.Config().EventBrowser_HideAPICalls = ui->EventBrowser_HideAPICalls->isChecked(); m_Ctx.Config().Save(); } void SettingsDialog::on_EventBrowser_ApplyColors_toggled(bool checked) { m_Ctx.Config().EventBrowser_ApplyColors = ui->EventBrowser_ApplyColors->isChecked(); m_Ctx.Config().Save(); } void SettingsDialog::on_EventBrowser_ColorEventRow_toggled(bool checked) { m_Ctx.Config().EventBrowser_ColorEventRow = ui->EventBrowser_ColorEventRow->isChecked(); m_Ctx.Config().Save(); } void SettingsDialog::on_Comments_ShowOnLoad_toggled(bool checked) { m_Ctx.Config().Comments_ShowOnLoad = ui->Comments_ShowOnLoad->isChecked(); m_Ctx.Config().Save(); } // android void SettingsDialog::on_browseTempCaptureDirectory_clicked() { QString dir = RDDialog::getExistingDirectory(this, tr("Choose directory for temporary captures"), m_Ctx.Config().TemporaryCaptureDirectory); if(!dir.isEmpty()) { m_Ctx.Config().TemporaryCaptureDirectory = dir; ui->tempDirectory->setText(dir); } m_Ctx.Config().Save(); } void SettingsDialog::on_browseAndroidSDKPath_clicked() { QString adb = RDDialog::getExistingDirectory( this, tr("Locate SDK root folder (containing build-tools, platform-tools)"), QFileInfo(m_Ctx.Config().Android_SDKPath).absoluteDir().path()); if(!adb.isEmpty()) { ui->Android_SDKPath->setText(adb); m_Ctx.Config().Android_SDKPath = adb; } m_Ctx.Config().Save(); } void SettingsDialog::on_Android_SDKPath_textEdited(const QString &adb) { if(QFileInfo::exists(adb) || adb.isEmpty()) m_Ctx.Config().Android_SDKPath = adb; m_Ctx.Config().Save(); } void SettingsDialog::on_browseJDKPath_clicked() { QString adb = RDDialog::getExistingDirectory(this, tr("Locate JDK root folder (containing bin, jre, lib)"), QFileInfo(m_Ctx.Config().Android_JDKPath).absoluteDir().path()); if(!adb.isEmpty()) { ui->Android_JDKPath->setText(adb); m_Ctx.Config().Android_JDKPath = adb; } m_Ctx.Config().Save(); } void SettingsDialog::on_Android_JDKPath_textEdited(const QString &adb) { if(QFileInfo::exists(adb) || adb.isEmpty()) m_Ctx.Config().Android_JDKPath = adb; m_Ctx.Config().Save(); } void SettingsDialog::on_Android_MaxConnectTimeout_valueChanged(double timeout) { m_Ctx.Config().Android_MaxConnectTimeout = ui->Android_MaxConnectTimeout->value(); m_Ctx.Config().Save(); } void SettingsDialog::on_UIStyle_currentIndexChanged(int index) { if(index < 0 || index >= StyleData::numAvailable) return; // don't do anything until the dialog is initialised and visible if(!isVisible()) return; QString oldStyle = m_Ctx.Config().UIStyle; QString newStyle = StyleData::availStyles[index].styleID; if(oldStyle == newStyle) return; QMessageBox::StandardButton ret = RDDialog::question( this, tr("Switch to new theme?"), tr("Would you like to switch to the new theme now?

Some parts of a theme might " "require a full application restart to properly apply."), RDDialog::YesNoCancel, QMessageBox::Yes); if(ret == QMessageBox::Cancel) { // change the index back. Since we haven't changed the style yet, this will early out above // instead of recursing. for(int i = 0; i < StyleData::numAvailable; i++) { if(StyleData::availStyles[i].styleID == oldStyle) { ui->UIStyle->setCurrentIndex(i); break; } } return; } // set the style but don't change anything unless the user selected yes. m_Ctx.Config().UIStyle = newStyle; if(ret == QMessageBox::Yes) { m_Ctx.Config().SetStyle(); } m_Ctx.Config().Save(); }