diff --git a/obs/data/locale/en-US.ini b/obs/data/locale/en-US.ini index 82fb10ef1..aa6e9856d 100644 --- a/obs/data/locale/en-US.ini +++ b/obs/data/locale/en-US.ini @@ -109,6 +109,8 @@ Basic.PropertiesWindow="Properties for '%1'" Basic.PropertiesWindow.AutoSelectFormat="%1 (unsupported; autoselect: %2)" Basic.PropertiesWindow.SelectColor="Select color" Basic.PropertiesWindow.SelectFont="Select font" +Basic.PropertiesWindow.ConfirmTitle="Settings Changed" +Basic.PropertiesWindow.Confirm="There are unsaved changes. Do you want to keep them?" # interaction window Basic.InteractionWindow="Interacting with '%1'" diff --git a/obs/window-basic-main.cpp b/obs/window-basic-main.cpp index f9cddaabe..6cd6c3804 100644 --- a/obs/window-basic-main.cpp +++ b/obs/window-basic-main.cpp @@ -1536,6 +1536,16 @@ void OBSBasic::closeEvent(QCloseEvent *event) if (!event->isAccepted()) return; + /* Check all child dialogs and ensure they run their proper closeEvent + * methods before exiting the application. Otherwise Qt doesn't send + * the proper QCloseEvent messages. */ + QList childDialogs = this->findChildren(); + if (!childDialogs.isEmpty()) { + for (int i = 0; i < childDialogs.size(); ++i) { + childDialogs.at(i)->close(); + } + } + // remove draw callback in case our drawable surfaces go away before // the destructor gets called obs_remove_draw_callback(OBSBasic::RenderMain, this); diff --git a/obs/window-basic-properties.cpp b/obs/window-basic-properties.cpp index b578969af..fc533545a 100644 --- a/obs/window-basic-properties.cpp +++ b/obs/window-basic-properties.cpp @@ -24,6 +24,7 @@ #include #include #include +#include using namespace std; @@ -31,6 +32,7 @@ OBSBasicProperties::OBSBasicProperties(QWidget *parent, OBSSource source_) : QDialog (parent), main (qobject_cast(parent)), resizeTimer (0), + acceptClicked (false), ui (new Ui::OBSBasicProperties), source (source_), removedSignal (obs_source_get_signal_handler(source), @@ -39,20 +41,26 @@ OBSBasicProperties::OBSBasicProperties(QWidget *parent, OBSSource source_) updatePropertiesSignal (obs_source_get_signal_handler(source), "update_properties", OBSBasicProperties::UpdateProperties, - this) - + this), + buttonBox (new QDialogButtonBox(this)), + oldSettings (obs_data_create()) { int cx = (int)config_get_int(App()->GlobalConfig(), "PropertiesWindow", "cx"); int cy = (int)config_get_int(App()->GlobalConfig(), "PropertiesWindow", "cy"); + buttonBox->setStandardButtons(QDialogButtonBox::Ok | + QDialogButtonBox::Cancel); + buttonBox->setObjectName(QStringLiteral("buttonBox")); + ui->setupUi(this); if (cx > 400 && cy > 400) resize(cx, cy); OBSData settings = obs_source_get_settings(source); + obs_data_apply(oldSettings, settings); obs_data_release(settings); view = new OBSPropertiesView(settings, source, @@ -60,6 +68,8 @@ OBSBasicProperties::OBSBasicProperties(QWidget *parent, OBSSource source_) (PropertiesUpdateCallback)obs_source_update); layout()->addWidget(view); + layout()->addWidget(buttonBox); + layout()->setAlignment(buttonBox, Qt::AlignRight | Qt::AlignBottom); layout()->setAlignment(view, Qt::AlignBottom); view->setMaximumHeight(250); view->setMinimumHeight(150); @@ -92,6 +102,21 @@ void OBSBasicProperties::UpdateProperties(void *data, calldata_t *) "ReloadProperties"); } +void OBSBasicProperties::on_buttonBox_clicked(QAbstractButton *button) +{ + QDialogButtonBox::ButtonRole val = buttonBox->buttonRole(button); + + if (val == QDialogButtonBox::AcceptRole) { + acceptClicked = true; + close(); + } + + if (val == QDialogButtonBox::RejectRole) { + obs_source_update(source, oldSettings); + close(); + } +} + void OBSBasicProperties::DrawPreview(void *data, uint32_t cx, uint32_t cy) { OBSBasicProperties *window = static_cast(data); @@ -154,10 +179,19 @@ void OBSBasicProperties::timerEvent(QTimerEvent *event) void OBSBasicProperties::closeEvent(QCloseEvent *event) { + if (!acceptClicked && (CheckSettings() != 0)) { + if (!ConfirmQuit()) { + event->ignore(); + return; + } + } + QDialog::closeEvent(event); if (!event->isAccepted()) return; + obs_data_release(oldSettings); + // remove draw callback and release display in case our drawable // surfaces go away before the destructor gets called obs_display_remove_draw_callback(display, @@ -188,3 +222,43 @@ void OBSBasicProperties::Init() obs_display_add_draw_callback(display, OBSBasicProperties::DrawPreview, this); } + +int OBSBasicProperties::CheckSettings() +{ + OBSData currentSettings = obs_source_get_settings(source); + const char *oldSettingsJson = obs_data_get_json(oldSettings); + const char *currentSettingsJson = obs_data_get_json(currentSettings); + + int ret = strcmp(currentSettingsJson, oldSettingsJson); + + obs_data_release(currentSettings); + return ret; +} + +bool OBSBasicProperties::ConfirmQuit() +{ + QMessageBox::StandardButton button; + + button = QMessageBox::question(this, + QTStr("Basic.PropertiesWindow.ConfirmTitle"), + QTStr("Basic.PropertiesWindow.Confirm"), + QMessageBox::Save | QMessageBox::Discard | + QMessageBox::Cancel); + + switch (button) { + case QMessageBox::Save: + // Do nothing because the settings are already updated + break; + case QMessageBox::Discard: + obs_source_update(source, oldSettings); + break; + case QMessageBox::Cancel: + return false; + break; + default: + /* If somehow the dialog fails to show, just default to + * saving the settings. */ + break; + } + return true; +} diff --git a/obs/window-basic-properties.hpp b/obs/window-basic-properties.hpp index 6a92fb45e..6f0380836 100644 --- a/obs/window-basic-properties.hpp +++ b/obs/window-basic-properties.hpp @@ -18,8 +18,8 @@ #pragma once #include +#include #include - #include #include "properties-view.hpp" @@ -34,20 +34,26 @@ class OBSBasicProperties : public QDialog { private: OBSBasic *main; int resizeTimer; + bool acceptClicked; std::unique_ptr ui; OBSSource source; OBSDisplay display; OBSSignal removedSignal; OBSSignal updatePropertiesSignal; + OBSData oldSettings; OBSPropertiesView *view; + QDialogButtonBox *buttonBox; static void SourceRemoved(void *data, calldata_t *params); static void UpdateProperties(void *data, calldata_t *params); static void DrawPreview(void *data, uint32_t cx, uint32_t cy); + bool ConfirmQuit(); + int CheckSettings(); private slots: void OnPropertiesResized(); + void on_buttonBox_clicked(QAbstractButton *button); public: OBSBasicProperties(QWidget *parent, OBSSource source_);