#include "options_window.hpp" #include #include #include Glib::RefPtr UIBackendColumns::create(const Glib::ustring &id, const Glib::ustring &name) { return Glib::make_refptr_for_instance(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> listStore = Gio::ListStore::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& list_item) { auto box = Gtk::make_managed(Gtk::Orientation::HORIZONTAL, 10); box->append(*Gtk::make_managed()); box->append(*Gtk::make_managed()); list_item->set_child(*box); }); factory->signal_bind().connect([this](const Glib::RefPtr& list_item) { auto col = std::dynamic_pointer_cast(list_item->get_item()); if (!col) return; auto box = dynamic_cast(list_item->get_child()); if (!box) return; box->set_css_classes({"ui-backend-option"}); auto name_label = dynamic_cast(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(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("ui.gtk.dark_mode", false)); darkModeSwitch->property_active().signal_changed().connect([this, darkModeSwitch]() { Looper::Options::set_option("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(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(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; } }