From 2152b40e683795a55cd9103e00e965a7de946eb8 Mon Sep 17 00:00:00 2001 From: Weikardzaena Date: Tue, 13 Jan 2015 19:03:52 -0700 Subject: [PATCH] UI: Add Okay/Cancel Buttons to Properties Dialog Use QDialogButtonBox to add "Okay" and "Cancel" buttons to the properties dialog. The core functionality of the dialog is not changed; I.E. the settings are still applied to the source as the user changes them. If the user clicks "Okay", the dialog simply exits. If the user clicks "Cancel", the original settings are reapplied to the source then the dialog exits. If the window is closed by any other means (I.E. by the main obs window closing) then the properties dialog prompts the user if they changed anything and asks if they wish to save their settings. In order to implement this last feature, a method of checking for open dialogs and sending each a quit message is added to the closeEvent() method for OBSBasic. --- obs/data/locale/en-US.ini | 2 + obs/window-basic-main.cpp | 10 +++++ obs/window-basic-properties.cpp | 78 ++++++++++++++++++++++++++++++++- obs/window-basic-properties.hpp | 8 +++- 4 files changed, 95 insertions(+), 3 deletions(-) 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_);