diff options
author | David Robillard <d@drobilla.net> | 2021-05-11 13:45:26 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2021-05-11 13:45:26 -0400 |
commit | df0fdf362347495531bc3a5d19233220721d846b (patch) | |
tree | e3631d08630d4d6651eb24aa53c9fc49157778ab /src/Patchage.cpp | |
parent | c6ae340c6222240dc45e9bba714c722cebece186 (diff) | |
download | patchage-df0fdf362347495531bc3a5d19233220721d846b.tar.gz patchage-df0fdf362347495531bc3a5d19233220721d846b.tar.bz2 patchage-df0fdf362347495531bc3a5d19233220721d846b.zip |
Refactor most functionality around actions and settings
This moves more code into general places, and completely eliminates
dependencies on the Patchage "god object".
Diffstat (limited to 'src/Patchage.cpp')
-rw-r--r-- | src/Patchage.cpp | 450 |
1 files changed, 234 insertions, 216 deletions
diff --git a/src/Patchage.cpp b/src/Patchage.cpp index 9c346f2..5adb524 100644 --- a/src/Patchage.cpp +++ b/src/Patchage.cpp @@ -47,6 +47,8 @@ PATCHAGE_DISABLE_FMT_WARNINGS PATCHAGE_RESTORE_WARNINGS #include <boost/optional/optional.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant.hpp> #include <glib-object.h> #include <glib.h> #include <glibmm/fileutils.h> @@ -96,6 +98,7 @@ PATCHAGE_RESTORE_WARNINGS #include <cmath> #include <cstdint> #include <cstdlib> +#include <functional> #include <map> #include <utility> @@ -164,6 +167,7 @@ port_order(const GanvPort* a, const GanvPort* b, void*) Patchage::Patchage(Options options) : _xml(UIFile::open("patchage")) + , _conf([this](const Setting& setting) { on_conf_change(setting); }) , INIT_WIDGET(_about_win) , INIT_WIDGET(_main_scrolledwin) , INIT_WIDGET(_main_win) @@ -201,16 +205,13 @@ Patchage::Patchage(Options options) , INIT_WIDGET(_status_text) , _legend(nullptr) , _log(_status_text) - , _reactor(*this) , _drivers(_log, [this](const Event& event) { on_driver_event(event); }) + , _canvas(new Canvas{_log, _action_sink, 1600 * 2, 1200 * 2}) + , _reactor(_conf, _drivers, *_canvas, _log) , _action_sink([this](const Action& action) { _reactor(action); }) , _options{options} - , _pane_initialized(false) , _attach(true) { - _canvas = - std::unique_ptr<Canvas>{new Canvas(_action_sink, 1600 * 2, 1200 * 2)}; - Glib::set_application_name("Patchage"); _about_win->property_program_name() = "Patchage"; _about_win->property_logo_icon_name() = "patchage"; @@ -245,8 +246,8 @@ Patchage::Patchage(Options options) sigc::mem_fun(this, &Patchage::on_quit)); _menu_export_image->signal_activate().connect( sigc::mem_fun(this, &Patchage::on_export_image)); - _menu_view_refresh->signal_activate().connect( - sigc::mem_fun(this, &Patchage::refresh)); + _menu_view_refresh->signal_activate().connect(sigc::bind( + sigc::mem_fun(this, &Patchage::on_menu_action), Action{action::Refresh{}})); _menu_view_human_names->signal_activate().connect( sigc::mem_fun(this, &Patchage::on_view_human_names)); _menu_view_sort_ports->signal_activate().connect( @@ -261,20 +262,26 @@ Patchage::Patchage(Options options) sigc::mem_fun(this, &Patchage::on_view_toolbar)); _menu_help_about->signal_activate().connect( sigc::mem_fun(this, &Patchage::on_help_about)); - _menu_zoom_in->signal_activate().connect( - sigc::mem_fun(this, &Patchage::on_zoom_in)); - _menu_zoom_out->signal_activate().connect( - sigc::mem_fun(this, &Patchage::on_zoom_out)); + + _menu_zoom_in->signal_activate().connect(sigc::bind( + sigc::mem_fun(this, &Patchage::on_menu_action), Action{action::ZoomIn{}})); + _menu_zoom_out->signal_activate().connect(sigc::bind( + sigc::mem_fun(this, &Patchage::on_menu_action), Action{action::ZoomOut{}})); _menu_zoom_normal->signal_activate().connect( - sigc::mem_fun(this, &Patchage::on_zoom_normal)); + sigc::bind(sigc::mem_fun(this, &Patchage::on_menu_action), + Action{action::ZoomNormal{}})); _menu_zoom_full->signal_activate().connect( - sigc::mem_fun(this, &Patchage::on_zoom_full)); + sigc::bind(sigc::mem_fun(this, &Patchage::on_menu_action), + Action{action::ZoomFull{}})); _menu_increase_font_size->signal_activate().connect( - sigc::mem_fun(this, &Patchage::on_increase_font_size)); + sigc::bind(sigc::mem_fun(this, &Patchage::on_menu_action), + Action{action::IncreaseFontSize{}})); _menu_decrease_font_size->signal_activate().connect( - sigc::mem_fun(this, &Patchage::on_decrease_font_size)); + sigc::bind(sigc::mem_fun(this, &Patchage::on_menu_action), + Action{action::DecreaseFontSize{}})); _menu_normal_font_size->signal_activate().connect( - sigc::mem_fun(this, &Patchage::on_normal_font_size)); + sigc::bind(sigc::mem_fun(this, &Patchage::on_menu_action), + Action{action::ResetFontSize{}})); if (_canvas->supports_sprung_layout()) { _menu_view_sprung_layout->set_active(true); @@ -283,22 +290,15 @@ Patchage::Patchage(Options options) _menu_view_sprung_layout->set_sensitive(false); } + // Present window so that display attributes like font size are available _canvas->widget().show(); _main_win->present(); + // Set the default font size based on the current GUI environment _conf.set<setting::FontSize>(_canvas->get_default_font_size()); - _conf.load(); - _canvas->set_zoom(_conf.get<setting::Zoom>()); - _canvas->set_font_size(_conf.get<setting::FontSize>()); - if (_conf.get<setting::SortedPorts>()) { - _canvas->set_port_order(port_order, nullptr); - } - _main_win->resize(static_cast<int>(_conf.get<setting::WindowSize>().x), - static_cast<int>(_conf.get<setting::WindowSize>().y)); - - _main_win->move(static_cast<int>(_conf.get<setting::WindowLocation>().x), - static_cast<int>(_conf.get<setting::WindowLocation>().y)); + // Load configuration file (but do not apply it yet, see below) + _conf.load(); _legend = new Legend(_conf); _legend->signal_color_changed.connect( @@ -307,6 +307,7 @@ Patchage::Patchage(Options options) _legend->show_all(); _about_win->set_transient_for(*_main_win); + #ifdef __APPLE__ try { _about_win->set_logo(Gdk::Pixbuf::create_from_file( @@ -338,10 +339,6 @@ Patchage::Patchage(Options options) _menu_alsa_disconnect->set_sensitive(false); } - _menu_view_toolbar->set_active(_conf.get<setting::ToolbarVisible>()); - _menu_view_sprung_layout->set_active(_conf.get<setting::SprungLayout>()); - _menu_view_sort_ports->set_active(_conf.get<setting::SortedPorts>()); - g_signal_connect( _main_win->gobj(), "configure-event", G_CALLBACK(configure_cb), this); @@ -366,6 +363,9 @@ Patchage::Patchage(Options options) gtkosx_application_ready(osxapp); #endif + // Apply all configuration settings to ensure the GUI is synced + _conf.each([this](const Setting& setting) { on_conf_change(setting); }); + // Set up an idle callback to process events and update the GUI if necessary Glib::signal_timeout().connect(sigc::mem_fun(this, &Patchage::idle_callback), 100); @@ -389,7 +389,6 @@ Patchage::attach() } process_events(); - refresh(); update_toolbar(); } @@ -466,83 +465,6 @@ Patchage::update_load() } void -Patchage::refresh() -{ - auto sink = [this](const Event& event) { - _log.info("Refresh: " + event_to_string(event)); - handle_event(*this, event); - }; - - if (_canvas) { - sink(event::Cleared{}); - - if (_drivers.jack()) { - _drivers.jack()->refresh(sink); - } - - if (_drivers.alsa()) { - _drivers.alsa()->refresh(sink); - } - } -} - -void -Patchage::driver_attached(const ClientType type) -{ - switch (type) { - case ClientType::jack: - _menu_jack_connect->set_sensitive(false); - _menu_jack_disconnect->set_sensitive(true); - - if (_drivers.jack()) { - _drivers.jack()->refresh( - [this](const Event& event) { handle_event(*this, event); }); - } - - break; - case ClientType::alsa: - _menu_alsa_connect->set_sensitive(false); - _menu_alsa_disconnect->set_sensitive(true); - - if (_drivers.alsa()) { - _drivers.alsa()->refresh( - [this](const Event& event) { handle_event(*this, event); }); - } - - break; - } -} - -void -Patchage::driver_detached(const ClientType type) -{ - switch (type) { - case ClientType::jack: - _menu_jack_connect->set_sensitive(true); - _menu_jack_disconnect->set_sensitive(false); - - _canvas->remove_ports([](const CanvasPort* port) { - return (port->type() == PortType::jack_audio || - port->type() == PortType::jack_midi || - port->type() == PortType::jack_osc || - port->type() == PortType::jack_cv); - }); - - break; - - case ClientType::alsa: - _menu_alsa_connect->set_sensitive(true); - _menu_alsa_disconnect->set_sensitive(false); - - _canvas->remove_ports([](const CanvasPort* port) { - return port->type() == PortType::alsa_midi; - }); - - break; - } -} - -void Patchage::store_window_location() { int loc_x = 0; @@ -569,47 +491,58 @@ Patchage::clear_load() } void -Patchage::on_driver_event(const Event& event) +Patchage::operator()(const setting::AlsaAttached& setting) { - std::lock_guard<std::mutex> lock{_events_mutex}; - - _driver_events.emplace(event); -} + if (setting.value) { + _menu_alsa_connect->set_sensitive(false); + _menu_alsa_disconnect->set_sensitive(true); -void -Patchage::process_events() -{ - std::lock_guard<std::mutex> lock{_events_mutex}; + if (_drivers.alsa()) { + _drivers.alsa()->refresh([this](const Event& event) { + handle_event(_conf, _metadata, *_canvas, _log, event); + }); + } + } else { + _menu_alsa_connect->set_sensitive(true); + _menu_alsa_disconnect->set_sensitive(false); - while (!_driver_events.empty()) { - _log.info(event_to_string(_driver_events.front())); - handle_event(*this, _driver_events.front()); - _driver_events.pop(); + _canvas->remove_ports([](const CanvasPort* port) { + return port->type() == PortType::alsa_midi; + }); } } void -Patchage::on_arrange() +Patchage::operator()(const setting::JackAttached& setting) { - if (_canvas) { - _canvas->arrange(); - } -} + if (setting.value) { + _menu_jack_connect->set_sensitive(false); + _menu_jack_disconnect->set_sensitive(true); -void -Patchage::on_sprung_layout_toggled() -{ - const bool sprung = _menu_view_sprung_layout->get_active(); + if (_drivers.jack()) { + _drivers.jack()->refresh([this](const Event& event) { + handle_event(_conf, _metadata, *_canvas, _log, event); + }); + } + } else { + _menu_jack_connect->set_sensitive(true); + _menu_jack_disconnect->set_sensitive(false); - _canvas->set_sprung_layout(sprung); - _conf.set<setting::SprungLayout>(sprung); + _canvas->remove_ports([](const CanvasPort* port) { + return (port->type() == PortType::jack_audio || + port->type() == PortType::jack_midi || + port->type() == PortType::jack_osc || + port->type() == PortType::jack_cv); + }); + } } void -Patchage::on_help_about() +Patchage::operator()(const setting::FontSize& setting) { - _about_win->run(); - _about_win->hide(); + if (_canvas->get_font_size() != setting.value) { + _canvas->set_font_size(setting.value); + } } static void @@ -631,72 +564,37 @@ update_labels(GanvNode* node, void* data) } void -Patchage::on_view_human_names() -{ - bool human_names = show_human_names(); - _canvas->for_each_node(update_labels, &human_names); -} - -void -Patchage::on_view_sort_ports() -{ - const bool sort_ports = this->sort_ports(); - _canvas->set_port_order(sort_ports ? port_order : nullptr, nullptr); - _conf.set<setting::SortedPorts>(sort_ports); - refresh(); -} - -void -Patchage::on_zoom_in() -{ - const float zoom = _canvas->get_zoom() * 1.25; - _canvas->set_zoom(zoom); - _conf.set<setting::Zoom>(zoom); -} - -void -Patchage::on_zoom_out() +Patchage::operator()(const setting::HumanNames& setting) { - const float zoom = _canvas->get_zoom() * 0.75; - _canvas->set_zoom(zoom); - _conf.set<setting::Zoom>(zoom); -} + bool human_names = setting.value; -void -Patchage::on_zoom_normal() -{ - _canvas->set_zoom(1.0); - _conf.set<setting::Zoom>(1.0); + _menu_view_human_names->set_active(human_names); + _canvas->for_each_node(update_labels, &human_names); } void -Patchage::on_zoom_full() +Patchage::operator()(const setting::MessagesHeight& setting) { - _canvas->zoom_full(); - _conf.set<setting::Zoom>(_canvas->get_zoom()); -} + if (_log_scrolledwindow->is_visible()) { + const int min_height = _log.min_height(); + const int max_pos = _main_paned->get_allocation().get_height(); + const int conf_height = setting.value; -void -Patchage::on_increase_font_size() -{ - const float points = _canvas->get_font_size() + 1.0; - _canvas->set_font_size(points); - _conf.set<setting::FontSize>(points); + _main_paned->set_position(max_pos - std::max(conf_height, min_height)); + } } void -Patchage::on_decrease_font_size() +Patchage::operator()(const setting::MessagesVisible& setting) { - const float points = _canvas->get_font_size() - 1.0; - _canvas->set_font_size(points); - _conf.set<setting::FontSize>(points); -} + if (setting.value) { + _log_scrolledwindow->show(); + _status_text->scroll_to_mark(_status_text->get_buffer()->get_insert(), 0); + } else { + _log_scrolledwindow->hide(); + } -void -Patchage::on_normal_font_size() -{ - _canvas->set_font_size(_canvas->get_default_font_size()); - _conf.set<setting::FontSize>(_canvas->get_default_font_size()); + _menu_view_messages->set_active(setting.value); } static inline guint @@ -748,17 +646,154 @@ update_edge_color(GanvEdge* edge, void* data) } void -Patchage::on_legend_color_change(PortType id, const std::string&, uint32_t rgba) +Patchage::operator()(const setting::PortColor&) { - _conf.set_port_color(id, rgba); _canvas->for_each_node(update_port_colors, this); _canvas->for_each_edge(update_edge_color, this); } void +Patchage::operator()(const setting::SortedPorts& setting) +{ + _menu_view_sort_ports->set_active(setting.value); + if (setting.value) { + _canvas->set_port_order(port_order, nullptr); + } else { + _canvas->set_port_order(nullptr, nullptr); + } +} + +void +Patchage::operator()(const setting::SprungLayout& setting) +{ + _canvas->set_sprung_layout(setting.value); + _menu_view_sprung_layout->set_active(setting.value); +} + +void +Patchage::operator()(const setting::ToolbarVisible& setting) +{ + if (setting.value) { + _toolbar->show(); + _menu_view_toolbar->set_active(true); + } else { + _toolbar->hide(); + _menu_view_toolbar->set_active(false); + } +} + +void +Patchage::operator()(const setting::WindowLocation& setting) +{ + const int new_x = static_cast<int>(setting.value.x); + const int new_y = static_cast<int>(setting.value.y); + + int current_x = 0; + int current_y = 0; + _main_win->get_position(current_x, current_y); + + if (new_x != current_x || new_y != current_y) { + _main_win->move(new_x, new_y); + } +} + +void +Patchage::operator()(const setting::WindowSize& setting) +{ + const int new_w = static_cast<int>(setting.value.x); + const int new_h = static_cast<int>(setting.value.y); + + int current_w = 0; + int current_h = 0; + _main_win->get_size(current_w, current_h); + + if (new_w != current_w || new_h != current_h) { + _main_win->resize(new_w, new_h); + } +} + +void +Patchage::operator()(const setting::Zoom& setting) +{ + if (_canvas->get_zoom() != setting.value) { + _canvas->set_zoom(setting.value); + } +} + +void +Patchage::on_driver_event(const Event& event) +{ + std::lock_guard<std::mutex> lock{_events_mutex}; + + _driver_events.emplace(event); +} + +void +Patchage::process_events() +{ + std::lock_guard<std::mutex> lock{_events_mutex}; + + while (!_driver_events.empty()) { + const Event& event = _driver_events.front(); + + _log.info(event_to_string(event)); + handle_event(_conf, _metadata, *_canvas, _log, event); + + _driver_events.pop(); + } +} + +void +Patchage::on_conf_change(const Setting& setting) +{ + boost::apply_visitor(*this, setting); +} + +void +Patchage::on_arrange() +{ + if (_canvas) { + _canvas->arrange(); + } +} + +void +Patchage::on_sprung_layout_toggled() +{ + _conf.set<setting::SprungLayout>(_menu_view_sprung_layout->get_active()); +} + +void +Patchage::on_help_about() +{ + _about_win->run(); + _about_win->hide(); +} + +void +Patchage::on_view_human_names() +{ + _conf.set<setting::HumanNames>(_menu_view_human_names->get_active()); +} + +void +Patchage::on_view_sort_ports() +{ + _conf.set<setting::SortedPorts>(_menu_view_sort_ports->get_active()); + _reactor(action::Refresh{}); +} + +void +Patchage::on_legend_color_change(PortType id, const std::string&, uint32_t rgba) +{ + _conf.set_port_color(id, rgba); +} + +void Patchage::on_messages_resized(Gtk::Allocation&) { const int max_pos = _main_paned->get_allocation().get_height(); + _conf.set<setting::MessagesHeight>(max_pos - _main_paned->get_position()); } @@ -840,35 +875,12 @@ Patchage::on_export_image() void Patchage::on_view_messages() { - if (_menu_view_messages->get_active()) { - Glib::RefPtr<Gtk::TextBuffer> buffer = _status_text->get_buffer(); - if (!_pane_initialized) { - const int min_height = _log.min_height(); - const int max_pos = _main_paned->get_allocation().get_height(); - const int conf_height = _conf.get<setting::MessagesHeight>(); - _main_paned->set_position(max_pos - std::max(conf_height, min_height)); - - _pane_initialized = true; - } - - _log_scrolledwindow->show(); - _status_text->scroll_to_mark(_status_text->get_buffer()->get_insert(), 0); - _conf.set<setting::MessagesVisible>(true); - } else { - _log_scrolledwindow->hide(); - _conf.set<setting::MessagesVisible>(false); - } + _conf.set<setting::MessagesVisible>(_menu_view_messages->get_active()); } void Patchage::on_view_toolbar() { - if (_menu_view_toolbar->get_active()) { - _toolbar->show(); - } else { - _toolbar->hide(); - } - _conf.set<setting::ToolbarVisible>(_menu_view_toolbar->get_active()); } @@ -879,6 +891,12 @@ Patchage::on_scroll(GdkEventScroll*) } void +Patchage::on_menu_action(const Action& action) +{ + _reactor(action); +} + +void Patchage::buffer_size_changed() { if (_drivers.jack()) { |