looper/backends/ui/gtk/options_window.cpp
2024-03-26 18:39:02 -07:00

174 lines
No EOL
7 KiB
C++

#include "options_window.hpp"
#include <backend.hpp>
#include <options.hpp>
#include <optional>
Glib::RefPtr<UIBackendColumns> UIBackendColumns::create(const Glib::ustring &id, const Glib::ustring &name) {
return Glib::make_refptr_for_instance<UIBackendColumns>(new UIBackendColumns(id, name));
}
UIBackendColumns::UIBackendColumns(const Glib::ustring &id, const Glib::ustring &name)
: backendId(id),
backendName(name)
{ }
void OptionsWindow::add_option(Glib::ustring title, Gtk::Widget *widget, std::string key) {
mainBox.insert_row(mainBoxRow);
Gtk::Label *label = new Gtk::Label();
label->set_css_classes({"option-label"});
label->set_justify(Gtk::Justification::LEFT);
label->set_hexpand(false);
label->set_text(title);
mainBox.attach(*label, 0, mainBoxRow);
optionWidgets.push_back(label);
Gtk::Label *emptyLabel = new Gtk::Label();
emptyLabel->set_hexpand(true);
emptyLabel->set_text("");
mainBox.attach(*emptyLabel, 1, mainBoxRow);
optionWidgets.push_back(emptyLabel);
auto widget_css_classes = widget->get_css_classes();
widget_css_classes.push_back("option-editor");
widget->set_css_classes(widget_css_classes);
if (!widget->get_hexpand()) {
widget->set_halign(Gtk::Align::END);
}
mainBox.attach(*widget, 2, mainBoxRow);
optionWidgets.push_back(widget);
mainBoxRow++;
modifiableOptions.insert(key);
}
void OptionsWindow::revert() {
Looper::Options::load_options();
for (auto option : modifiableOptions) {
optionChanged.emit(option);
}
needsRestartLabel.set_visible(savedOptionRequiresRestart);
}
void OptionsWindow::save() {
Looper::Options::save_options();
optionsSaved.emit();
savedOptionRequiresRestart = needsRestartLabel.get_visible();
}
OptionsWindow::OptionsWindow() {
set_title("Options...");
set_icon_name("preferences-other");
set_name("options-window");
rootBox.set_name("options-window-root");
mainBox.set_expand();
mainBox.insert_column(0);
mainBox.insert_column(1);
mainBox.insert_column(2);
mainBox.set_name("options-main-box");
needsRestartLabel.set_name("options-needs-restart-label");
needsRestartLabel.set_text("A restart is needed to apply some changes.");
needsRestartLabel.set_visible(false);
needsRestartLabel.insert_at_start(rootBox);
Gtk::DropDown *uiBackendBox = new Gtk::DropDown();
Glib::RefPtr<Gio::ListStore<UIBackendColumns>> listStore = Gio::ListStore<UIBackendColumns>::create();
for (auto kv : UIBackend::backends) {
auto backend = kv.second;
Glib::ustring id(backend->get_id().c_str());
Glib::ustring name(backend->get_name().c_str());
listStore->append(UIBackendColumns::create(id, name));
}
uiBackendBox->set_model(listStore);
auto factory = Gtk::SignalListItemFactory::create();
factory->signal_setup().connect([this](const Glib::RefPtr<Gtk::ListItem>& list_item) {
auto box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 10);
box->append(*Gtk::make_managed<Gtk::Label>());
box->append(*Gtk::make_managed<Gtk::Label>());
list_item->set_child(*box);
});
factory->signal_bind().connect([this](const Glib::RefPtr<Gtk::ListItem>& list_item) {
auto col = std::dynamic_pointer_cast<UIBackendColumns>(list_item->get_item());
if (!col) return;
auto box = dynamic_cast<Gtk::Box*>(list_item->get_child());
if (!box) return;
box->set_css_classes({"ui-backend-option"});
auto name_label = dynamic_cast<Gtk::Label*>(box->get_first_child());
name_label->set_hexpand();
name_label->set_text(col->backendName);
name_label->set_css_classes({"ui-backend-name", "primary"});
if (!name_label) return;
auto id_label = dynamic_cast<Gtk::Label*>(name_label->get_next_sibling());
if (!id_label) return;
id_label->set_text(col->backendId);
id_label->set_css_classes({"ui-backend-id", "secondary"});
});
uiBackendBox->set_factory(factory);
uiBackendBox->property_selected().signal_changed().connect([uiBackendBox, listStore, this]() {
std::string backendId = listStore->get_item(uiBackendBox->get_selected())->backendId;
this->change_option("ui.frontend", backendId);
this->needsRestartLabel.set_visible();
});
add_option("UI frontend", uiBackendBox, "ui.frontend");
Gtk::Switch *darkModeSwitch = new Gtk::Switch();
darkModeSwitch->set_active(Looper::Options::get_option<bool>("ui.gtk.dark_mode", false));
darkModeSwitch->property_active().signal_changed().connect([this, darkModeSwitch]() {
Looper::Options::set_option<bool>("ui.gtk.dark_mode", darkModeSwitch->get_active());
});
add_option("Dark mode", darkModeSwitch, "ui.gtk.dark_mode");
optionChanged.connect([this, uiBackendBox, listStore, darkModeSwitch](std::string key) {
if (key == "ui.frontend") {
std::string frontend = Looper::Options::get_option<std::string>(key);
for (int i = 0; i < listStore->get_n_items(); i++) {
if (std::string(listStore->get_item(i)->backendId.c_str()) == frontend) {
uiBackendBox->set_selected(i);
break;
}
}
} else if (key == "ui.gtk.dark_mode") {
darkModeSwitch->set_active(Looper::Options::get_option<bool>(key));
}
});
mainBox.set_row_spacing(2);
mainBox.set_column_spacing(2);
mainBox.insert_at_end(rootBox);
okBtn.set_name("options-ok-btn");
okBtn.set_css_classes({"options-window-btn"});
okBtn.set_label("OK");
cancelBtn.set_name("options-cancel-btn");
cancelBtn.set_css_classes({"options-window-btn"});
cancelBtn.set_label("Cancel");
saveBtn.set_name("options-save-btn");
saveBtn.set_css_classes({"options-window-btn"});
saveBtn.set_label("Save");
revertBtn.set_name("options-revert-btn");
revertBtn.set_css_classes({"options-window-btn"});
revertBtn.set_label("Revert");
okBtn.signal_clicked().connect([this]() {
this->save();
this->close();
});
cancelBtn.signal_clicked().connect([this]() {
this->revert();
this->close();
});
revertBtn.signal_clicked().connect([this]() {
this->revert();
});
saveBtn.signal_clicked().connect([this]() {
this->save();
});
okBtn.insert_at_end(btnBox);
saveBtn.insert_at_end(btnBox);
revertBtn.insert_at_end(btnBox);
cancelBtn.insert_at_end(btnBox);
rootBox.set_spacing(8);
btnBox.set_spacing(2);
btnBox.set_orientation(Gtk::Orientation::HORIZONTAL);
btnBox.set_name("options-window-btns");
btnBox.set_halign(Gtk::Align::END);
btnBox.insert_at_end(rootBox);
rootBox.set_orientation(Gtk::Orientation::VERTICAL);
rootBox.set_expand();
set_child(rootBox);
Gtk::Requisition min;
Gtk::Requisition nat;
rootBox.get_preferred_size(min, nat);
set_default_size(nat.get_width(), nat.get_height());
}
OptionsWindow::~OptionsWindow() {
for (auto widget : optionWidgets) {
delete widget;
}
}