LibGUI: Support "modified" window state in SettingsWindow

SettingsWindow now notices if the window is marked as modified, and
shows a confirmation pop-up to check if the user wants to apply or
discard their changes. It automatically marks the window as unmodified
after restoring defaults or applying the changes, but each Tab subclass
needs to call `set_modified(true)` when the user modifies things.

The "Apply" button is automatically disabled when there are no unsaved
changes to be applied.
This commit is contained in:
Sam Atkins 2022-04-29 17:00:24 +01:00 committed by Andreas Kling
parent ebbbca98fa
commit 4f9f948b6d
2 changed files with 70 additions and 10 deletions

View file

@ -10,11 +10,19 @@
#include <LibGUI/Application.h>
#include <LibGUI/BoxLayout.h>
#include <LibGUI/Button.h>
#include <LibGUI/MessageBox.h>
#include <LibGUI/SettingsWindow.h>
#include <LibGUI/Widget.h>
namespace GUI {
void SettingsWindow::set_modified(bool modified)
{
Window::set_modified(modified);
if (m_apply_button)
m_apply_button->set_enabled(modified);
}
ErrorOr<NonnullRefPtr<SettingsWindow>> SettingsWindow::create(String title, ShowDefaultsButton show_defaults_button)
{
auto window = TRY(SettingsWindow::try_create());
@ -41,10 +49,7 @@ ErrorOr<NonnullRefPtr<SettingsWindow>> SettingsWindow::create(String title, Show
window->m_reset_button = TRY(button_container->try_add<GUI::Button>("Defaults"));
window->m_reset_button->set_fixed_width(75);
window->m_reset_button->on_click = [window = window->make_weak_ptr<SettingsWindow>()](auto) mutable {
for (auto& [id, tab] : window->m_tabs) {
tab->reset_default_values();
tab->apply_settings();
}
window->reset_default_values();
};
}
@ -53,24 +58,38 @@ ErrorOr<NonnullRefPtr<SettingsWindow>> SettingsWindow::create(String title, Show
window->m_ok_button = TRY(button_container->try_add<GUI::Button>("OK"));
window->m_ok_button->set_fixed_width(75);
window->m_ok_button->on_click = [window = window->make_weak_ptr<SettingsWindow>()](auto) mutable {
for (auto& [id, tab] : window->m_tabs)
tab->apply_settings();
window->apply_settings();
GUI::Application::the()->quit();
};
window->m_cancel_button = TRY(button_container->try_add<GUI::Button>("Cancel"));
window->m_cancel_button->set_fixed_width(75);
window->m_cancel_button->on_click = [window = window->make_weak_ptr<SettingsWindow>()](auto) mutable {
for (auto& [id, tab] : window->m_tabs)
tab->cancel_settings();
window->cancel_settings();
GUI::Application::the()->quit();
};
window->m_apply_button = TRY(button_container->try_add<GUI::Button>("Apply"));
window->m_apply_button->set_fixed_width(75);
window->m_apply_button->on_click = [window = window->make_weak_ptr<SettingsWindow>()](auto) mutable {
for (auto& [id, tab] : window->m_tabs)
tab->apply_settings();
window->apply_settings();
};
window->on_close_request = [window = window->make_weak_ptr<SettingsWindow>()]() mutable -> Window::CloseRequestDecision {
if (!window->is_modified())
return Window::CloseRequestDecision::Close;
auto result = MessageBox::show(window, "Apply these settings before closing?", "Unsaved changes", MessageBox::Type::Warning, MessageBox::InputType::YesNoCancel);
switch (result) {
case MessageBox::ExecYes:
window->apply_settings();
return Window::CloseRequestDecision::Close;
case MessageBox::ExecNo:
window->cancel_settings();
return Window::CloseRequestDecision::Close;
default:
return Window::CloseRequestDecision::StayOpen;
}
};
return window;
@ -90,4 +109,26 @@ void SettingsWindow::set_active_tab(StringView id)
m_tab_widget->set_active_widget(tab.value());
}
void SettingsWindow::apply_settings()
{
for (auto& [id, tab] : m_tabs)
tab->apply_settings();
set_modified(false);
}
void SettingsWindow::cancel_settings()
{
for (auto& [id, tab] : m_tabs)
tab->cancel_settings();
}
void SettingsWindow::reset_default_values()
{
for (auto& [id, tab] : m_tabs) {
tab->reset_default_values();
tab->apply_settings();
}
set_modified(false);
}
}

View file

@ -23,6 +23,18 @@ public:
virtual void apply_settings() = 0;
virtual void cancel_settings() { }
virtual void reset_default_values() { }
SettingsWindow& settings_window() { return *m_window; }
void set_settings_window(SettingsWindow& settings_window) { m_window = settings_window; }
void set_modified(bool modified)
{
if (m_window)
m_window->set_modified(modified);
}
private:
WeakPtr<SettingsWindow> m_window;
};
enum class ShowDefaultsButton {
@ -39,12 +51,19 @@ public:
{
auto tab = TRY(m_tab_widget->try_add_tab<T>(move(title), forward<Args>(args)...));
TRY(m_tabs.try_set(id, tab));
tab->set_settings_window(*this);
return tab;
}
Optional<NonnullRefPtr<Tab>> get_tab(StringView id) const;
void set_active_tab(StringView id);
void apply_settings();
void cancel_settings();
void reset_default_values();
void set_modified(bool);
private:
SettingsWindow() = default;