From c1d99e42674d26a2699e5a7244dbaa988820b40d Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 10 May 2021 13:19:34 -0400 Subject: Add Action representation to isolate behaviour from canvas objects A step towards isolating the canvas and ultimately the entire UI away so it can be replaced. --- src/Action.hpp | 76 +++++++++++++++++++++++++ src/ActionSink.hpp | 31 +++++++++++ src/Canvas.cpp | 34 ++++++++---- src/Canvas.hpp | 10 ++-- src/CanvasModule.cpp | 63 +++++++-------------- src/CanvasModule.hpp | 29 +++++----- src/Connector.cpp | 72 ------------------------ src/Connector.hpp | 47 ---------------- src/Event.hpp | 4 +- src/Patchage.cpp | 27 +++------ src/Patchage.hpp | 8 ++- src/Reactor.cpp | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/Reactor.hpp | 74 +++++++++++++++++++++++++ src/handle_event.hpp | 4 +- 14 files changed, 414 insertions(+), 218 deletions(-) create mode 100644 src/Action.hpp create mode 100644 src/ActionSink.hpp delete mode 100644 src/Connector.cpp delete mode 100644 src/Connector.hpp create mode 100644 src/Reactor.cpp create mode 100644 src/Reactor.hpp (limited to 'src') diff --git a/src/Action.hpp b/src/Action.hpp new file mode 100644 index 0000000..f843a14 --- /dev/null +++ b/src/Action.hpp @@ -0,0 +1,76 @@ +/* This file is part of Patchage. + * Copyright 2007-2021 David Robillard + * + * Patchage is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. + * + * You should have received a copy of the GNU General Public License + * along with Patchage. If not, see . + */ + +#ifndef PATCHAGE_ACTION_HPP +#define PATCHAGE_ACTION_HPP + +#include "ClientID.hpp" +#include "PortID.hpp" +#include "SignalDirection.hpp" + +#include + +namespace patchage { +namespace action { + +struct ConnectPorts { + PortID tail; + PortID head; +}; + +struct DisconnectClient { + ClientID client; + SignalDirection direction; +}; + +struct DisconnectPort { + PortID port; +}; + +struct DisconnectPorts { + PortID tail; + PortID head; +}; + +struct MoveModule { + ClientID client; + SignalDirection direction; + double x; + double y; +}; + +struct SplitModule { + ClientID client; +}; + +struct UnsplitModule { + ClientID client; +}; + +} // namespace action + +/// A high-level action from the user +using Action = boost::variant; + +} // namespace patchage + +#endif // PATCHAGE_ACTION_HPP diff --git a/src/ActionSink.hpp b/src/ActionSink.hpp new file mode 100644 index 0000000..c0d92ec --- /dev/null +++ b/src/ActionSink.hpp @@ -0,0 +1,31 @@ +/* This file is part of Patchage. + * Copyright 2007-2020 David Robillard + * + * Patchage is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. + * + * You should have received a copy of the GNU General Public License + * along with Patchage. If not, see . + */ + +#ifndef PATCHAGE_ACTION_SINK_HPP +#define PATCHAGE_ACTION_SINK_HPP + +#include "Action.hpp" + +#include + +namespace patchage { + +/// Sink function for user actions +using ActionSink = std::function; + +} // namespace patchage + +#endif // PATCHAGE_ACTION_SINK_HPP diff --git a/src/Canvas.cpp b/src/Canvas.cpp index b9e5e52..aba9f75 100644 --- a/src/Canvas.cpp +++ b/src/Canvas.cpp @@ -1,5 +1,5 @@ /* This file is part of Patchage. - * Copyright 2007-2020 David Robillard + * Copyright 2007-2021 David Robillard * * Patchage is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free @@ -16,11 +16,11 @@ #include "Canvas.hpp" +#include "Action.hpp" #include "CanvasModule.hpp" #include "CanvasPort.hpp" #include "ClientInfo.hpp" #include "Configuration.hpp" -#include "Connector.hpp" #include "ILog.hpp" #include "Metadata.hpp" #include "Patchage.hpp" @@ -48,6 +48,8 @@ PATCHAGE_RESTORE_WARNINGS #include #include +#include +#include #include #include #include @@ -55,9 +57,9 @@ PATCHAGE_RESTORE_WARNINGS namespace patchage { -Canvas::Canvas(Connector& connector, int width, int height) +Canvas::Canvas(ActionSink& action_sink, int width, int height) : Ganv::Canvas(width, height) - , _connector(connector) + , _action_sink(action_sink) { signal_event.connect(sigc::mem_fun(this, &Canvas::on_event)); signal_connect.connect(sigc::mem_fun(this, &Canvas::on_connect)); @@ -97,9 +99,19 @@ Canvas::create_port(Patchage& patchage, const PortID& id, const PortInfo& info) // Find or create parent module CanvasModule* parent = find_module(client_id, module_type); if (!parent) { - parent = new CanvasModule(&patchage, client_name, module_type, client_id); + // Determine initial position + Coord loc; + if (!patchage.conf().get_module_location(client_name, module_type, loc)) { + // No position saved, come up with a pseudo-random one + loc.x = 20 + rand() % 640; + loc.y = 20 + rand() % 480; + + patchage.conf().set_module_location(client_name, module_type, loc); + } + + parent = new CanvasModule( + *this, _action_sink, client_name, module_type, client_id, loc.x, loc.y); - parent->load_location(); add_module(client_id, parent); } @@ -234,7 +246,7 @@ Canvas::remove_ports(bool (*pred)(const CanvasPort*)) i = next; } - for (ClientID id : data.empty_clients) { + for (const ClientID& id : data.empty_clients) { remove_module(id); } } @@ -247,9 +259,9 @@ Canvas::on_connect(Ganv::Node* port1, Ganv::Node* port2) if (p1 && p2) { if (p1->is_output() && p2->is_input()) { - _connector.connect(p1->id(), p2->id()); + _action_sink(action::ConnectPorts{p1->id(), p2->id()}); } else if (p2->is_output() && p1->is_input()) { - _connector.connect(p2->id(), p1->id()); + _action_sink(action::ConnectPorts{p2->id(), p1->id()}); } } } @@ -262,9 +274,9 @@ Canvas::on_disconnect(Ganv::Node* port1, Ganv::Node* port2) if (p1 && p2) { if (p1->is_output() && p2->is_input()) { - _connector.disconnect(p1->id(), p2->id()); + _action_sink(action::DisconnectPorts{p1->id(), p2->id()}); } else if (p2->is_output() && p1->is_input()) { - _connector.disconnect(p2->id(), p1->id()); + _action_sink(action::DisconnectPorts{p2->id(), p1->id()}); } } } diff --git a/src/Canvas.hpp b/src/Canvas.hpp index c571c5e..3a15ca6 100644 --- a/src/Canvas.hpp +++ b/src/Canvas.hpp @@ -1,5 +1,5 @@ /* This file is part of Patchage. - * Copyright 2007-2020 David Robillard + * Copyright 2007-2021 David Robillard * * Patchage is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free @@ -17,6 +17,7 @@ #ifndef PATCHAGE_CANVAS_HPP #define PATCHAGE_CANVAS_HPP +#include "ActionSink.hpp" #include "ClientID.hpp" #include "PortID.hpp" #include "SignalDirection.hpp" @@ -39,15 +40,14 @@ namespace patchage { struct PortInfo; -class Patchage; class CanvasModule; class CanvasPort; -class Connector; +class Patchage; class Canvas : public Ganv::Canvas { public: - Canvas(Connector& connector, int width, int height); + Canvas(ActionSink& action_sink, int width, int height); CanvasPort* create_port(Patchage& patchage, const PortID& id, @@ -79,7 +79,7 @@ private: void on_connect(Ganv::Node* port1, Ganv::Node* port2); void on_disconnect(Ganv::Node* port1, Ganv::Node* port2); - Connector& _connector; + ActionSink& _action_sink; PortIndex _port_index; ModuleIndex _module_index; }; diff --git a/src/CanvasModule.cpp b/src/CanvasModule.cpp index f5b750e..8d69218 100644 --- a/src/CanvasModule.cpp +++ b/src/CanvasModule.cpp @@ -1,5 +1,5 @@ /* This file is part of Patchage. - * Copyright 2010-2020 David Robillard + * Copyright 2010-2021 David Robillard * * Patchage is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free @@ -16,10 +16,9 @@ #include "CanvasModule.hpp" +#include "Action.hpp" #include "Canvas.hpp" #include "CanvasPort.hpp" -#include "Configuration.hpp" -#include "Patchage.hpp" #include "PortID.hpp" #include "SignalDirection.hpp" #include "warnings.hpp" @@ -37,30 +36,27 @@ PATCHAGE_RESTORE_WARNINGS #include #include -#include +#include #include #include namespace patchage { -CanvasModule::CanvasModule(Patchage* app, +CanvasModule::CanvasModule(Canvas& canvas, + ActionSink& action_sink, const std::string& name, SignalDirection type, ClientID id, double x, double y) - : Module(*app->canvas(), name, x, y) - , _app(app) + : Module(canvas, name, x, y) + , _action_sink(action_sink) , _name(name) , _type(type) , _id(std::move(id)) { signal_event().connect(sigc::mem_fun(this, &CanvasModule::on_event)); - - signal_moved().connect(sigc::mem_fun(this, &CanvasModule::store_location)); - - // Set as source by default, turned off if input ports added - set_is_source(true); + signal_moved().connect(sigc::mem_fun(this, &CanvasModule::on_moved)); } void @@ -98,15 +94,15 @@ CanvasModule::show_menu(GdkEventButton* ev) if (_type == SignalDirection::duplex) { items.push_back(Gtk::Menu_Helpers::MenuElem( - "_Split", sigc::mem_fun(this, &CanvasModule::split))); + "_Split", sigc::mem_fun(this, &CanvasModule::on_split))); update_menu(); } else { items.push_back(Gtk::Menu_Helpers::MenuElem( - "_Join", sigc::mem_fun(this, &CanvasModule::join))); + "_Join", sigc::mem_fun(this, &CanvasModule::on_join))); } items.push_back(Gtk::Menu_Helpers::MenuElem( - "_Disconnect All", sigc::mem_fun(this, &CanvasModule::disconnect_all))); + "_Disconnect", sigc::mem_fun(this, &CanvasModule::on_disconnect))); _menu->popup(ev->button, ev->time); return true; @@ -122,50 +118,29 @@ CanvasModule::on_event(GdkEvent* ev) } void -CanvasModule::load_location() -{ - Coord loc; - - if (_app->conf().get_module_location(_name, _type, loc)) { - move_to(loc.x, loc.y); - } else { - const double x = 20 + rand() % 640; - const double y = 20 + rand() % 480; - - // Move, then store generated location so it is stable - move_to(x, y); - store_location(x, y); - } -} - -void -CanvasModule::store_location(double x, double y) +CanvasModule::on_moved(double x, double y) { - _app->conf().set_module_location(_name, _type, {x, y}); + _action_sink(action::MoveModule{_id, _type, x, y}); } void -CanvasModule::split() +CanvasModule::on_split() { assert(_type == SignalDirection::duplex); - _app->conf().set_module_split(_name, true); - _app->refresh(); + _action_sink(action::SplitModule{_id}); } void -CanvasModule::join() +CanvasModule::on_join() { assert(_type != SignalDirection::duplex); - _app->conf().set_module_split(_name, false); - _app->refresh(); + _action_sink(action::UnsplitModule{_id}); } void -CanvasModule::disconnect_all() +CanvasModule::on_disconnect() { - for (Ganv::Port* p : *this) { - p->disconnect(); - } + _action_sink(action::DisconnectClient{_id, _type}); } CanvasPort* diff --git a/src/CanvasModule.hpp b/src/CanvasModule.hpp index 4f8412e..2dcdcc1 100644 --- a/src/CanvasModule.hpp +++ b/src/CanvasModule.hpp @@ -1,5 +1,5 @@ /* This file is part of Patchage. - * Copyright 2007-2020 David Robillard + * Copyright 2007-2021 David Robillard * * Patchage is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free @@ -17,6 +17,7 @@ #ifndef PATCHAGE_CANVASMODULE_HPP #define PATCHAGE_CANVASMODULE_HPP +#include "ActionSink.hpp" #include "ClientID.hpp" #include "SignalDirection.hpp" #include "warnings.hpp" @@ -38,18 +39,21 @@ namespace patchage { struct PortID; +class Configuration; +class Canvas; + class CanvasPort; -class Patchage; class CanvasModule : public Ganv::Module { public: - CanvasModule(Patchage* app, + CanvasModule(Canvas& canvas, + ActionSink& action_sink, const std::string& name, SignalDirection type, ClientID id, - double x = 0.0, - double y = 0.0); + double x, + double y); CanvasModule(const CanvasModule&) = delete; CanvasModule& operator=(const CanvasModule&) = delete; @@ -57,26 +61,25 @@ public: CanvasModule(CanvasModule&&) = delete; CanvasModule& operator=(CanvasModule&&) = delete; + ~CanvasModule() override = default; + bool show_menu(GdkEventButton* ev); void update_menu(); - void split(); - void join(); - void disconnect_all(); - CanvasPort* get_port(const PortID& id); - void load_location(); - void store_location(double x, double y); - SignalDirection type() const { return _type; } ClientID id() const { return _id; } const std::string& name() const { return _name; } protected: bool on_event(GdkEvent* ev) override; + void on_moved(double x, double y); + void on_split(); + void on_join(); + void on_disconnect(); - Patchage* _app; + ActionSink& _action_sink; std::unique_ptr _menu; std::string _name; SignalDirection _type; diff --git a/src/Connector.cpp b/src/Connector.cpp deleted file mode 100644 index fe008ce..0000000 --- a/src/Connector.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* This file is part of Patchage. - * Copyright 2007-2020 David Robillard - * - * Patchage is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License - * along with Patchage. If not, see . - */ - -#include "Connector.hpp" - -#include "Driver.hpp" -#include "ILog.hpp" -#include "PortID.hpp" - -#include -#include - -namespace patchage { - -Connector::Connector(ILog& log) - : _log(log) -{} - -void -Connector::add_driver(PortID::Type type, Driver* driver) -{ - _drivers.emplace(type, driver); -} - -void -Connector::connect(const PortID& tail, const PortID& head) -{ - if (tail.type() != head.type()) { - _log.warning("Unable to connect incompatible port types"); - return; - } - - auto d = _drivers.find(tail.type()); - if (d == _drivers.end()) { - _log.error("No driver for port type"); - return; - } - - d->second->connect(tail, head); -} - -void -Connector::disconnect(const PortID& tail, const PortID& head) -{ - if (tail.type() != head.type()) { - _log.error("Unable to disconnect incompatible port types"); - return; - } - - auto d = _drivers.find(tail.type()); - if (d == _drivers.end()) { - _log.error("No driver for port type"); - return; - } - - d->second->disconnect(tail, head); -} - -} // namespace patchage diff --git a/src/Connector.hpp b/src/Connector.hpp deleted file mode 100644 index f3e3816..0000000 --- a/src/Connector.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* This file is part of Patchage. - * Copyright 2007-2020 David Robillard - * - * Patchage is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License - * along with Patchage. If not, see . - */ - -#ifndef PATCHAGE_CONNECTOR_HPP -#define PATCHAGE_CONNECTOR_HPP - -#include "PortID.hpp" - -#include - -namespace patchage { - -class Driver; -class ILog; - -/// Controller that makes and breaks connections on the system -class Connector -{ -public: - explicit Connector(ILog& log); - - void add_driver(PortID::Type type, Driver* driver); - - void connect(const PortID& tail, const PortID& head); - void disconnect(const PortID& tail, const PortID& head); - -private: - ILog& _log; - std::unordered_map _drivers; -}; - -} // namespace patchage - -#endif // PATCHAGE_CONNECTOR_HPP diff --git a/src/Event.hpp b/src/Event.hpp index 46fdb1e..378f35eb 100644 --- a/src/Event.hpp +++ b/src/Event.hpp @@ -1,5 +1,5 @@ /* This file is part of Patchage. - * Copyright 2007-2020 David Robillard + * Copyright 2007-2021 David Robillard * * Patchage is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free @@ -66,7 +66,7 @@ struct PortsDisconnected { } // namespace event -/// An event from drivers that is processed by the GUI +/// An event from drivers that represents a change to the system using Event = boost::variant + * Copyright 2007-2021 David Robillard * * Patchage is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free @@ -16,6 +16,7 @@ #include "Patchage.hpp" +#include "Action.hpp" #include "AudioDriver.hpp" #include "Canvas.hpp" #include "CanvasModule.hpp" @@ -158,18 +159,6 @@ port_order(const GanvPort* a, const GanvPort* b, void*) return 0; } -void -load_module_location(GanvNode* node, void*) -{ - if (GANV_IS_MODULE(node)) { - Ganv::Module* gmod = Glib::wrap(GANV_MODULE(node)); - auto* pmod = dynamic_cast(gmod); - if (pmod) { - pmod->load_location(); - } - } -} - } // namespace #define INIT_WIDGET(x) x(_xml, (#x) + 1) @@ -214,12 +203,14 @@ Patchage::Patchage(Options options) , INIT_WIDGET(_status_text) , _legend(nullptr) , _log(_status_text) - , _connector(_log) + , _reactor(*this) + , _action_sink([this](const Action& action) { _reactor(action); }) , _options{options} , _pane_initialized(false) , _attach(true) { - _canvas = std::unique_ptr{new Canvas(_connector, 1600 * 2, 1200 * 2)}; + _canvas = + std::unique_ptr{new Canvas(_action_sink, 1600 * 2, 1200 * 2)}; Glib::set_application_name("Patchage"); _about_win->property_program_name() = "Patchage"; @@ -331,7 +322,7 @@ Patchage::Patchage(Options options) _log, [this](const Event& event) { on_driver_event(event); }); if (_jack_driver) { - _connector.add_driver(PortID::Type::jack, _jack_driver.get()); + _reactor.add_driver(PortID::Type::jack, _jack_driver.get()); _menu_jack_connect->signal_activate().connect(sigc::bind( sigc::mem_fun(_jack_driver.get(), &AudioDriver::attach), true)); @@ -347,7 +338,7 @@ Patchage::Patchage(Options options) _log, [this](const Event& event) { on_driver_event(event); }); if (_alsa_driver) { - _connector.add_driver(PortID::Type::alsa, _alsa_driver.get()); + _reactor.add_driver(PortID::Type::alsa, _alsa_driver.get()); _menu_alsa_connect->signal_activate().connect( sigc::bind(sigc::mem_fun(_alsa_driver.get(), &Driver::attach), false)); @@ -359,8 +350,6 @@ Patchage::Patchage(Options options) _menu_alsa_disconnect->set_sensitive(false); } - _canvas->for_each_node(load_module_location, nullptr); - _menu_view_toolbar->set_active(_conf.get_show_toolbar()); _menu_view_sprung_layout->set_active(_conf.get_sprung_layout()); _menu_view_sort_ports->set_active(_conf.get_sort_ports()); diff --git a/src/Patchage.hpp b/src/Patchage.hpp index e108748..ecc1256 100644 --- a/src/Patchage.hpp +++ b/src/Patchage.hpp @@ -1,5 +1,5 @@ /* This file is part of Patchage. - * Copyright 2007-2020 David Robillard + * Copyright 2007-2021 David Robillard * * Patchage is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free @@ -24,13 +24,14 @@ #include #include +#include "ActionSink.hpp" #include "ClientType.hpp" #include "Configuration.hpp" -#include "Connector.hpp" #include "Event.hpp" #include "Metadata.hpp" #include "Options.hpp" #include "PortType.hpp" +#include "Reactor.hpp" #include "TextViewLog.hpp" #include "Widget.hpp" @@ -206,8 +207,9 @@ protected: Widget _status_text; Legend* _legend; TextViewLog _log; - Connector _connector; Metadata _metadata; + Reactor _reactor; + ActionSink _action_sink; Glib::RefPtr _error_tag; Glib::RefPtr _warning_tag; diff --git a/src/Reactor.cpp b/src/Reactor.cpp new file mode 100644 index 0000000..c81df22 --- /dev/null +++ b/src/Reactor.cpp @@ -0,0 +1,153 @@ +/* This file is part of Patchage. + * Copyright 2007-2021 David Robillard + * + * Patchage is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. + * + * You should have received a copy of the GNU General Public License + * along with Patchage. If not, see . + */ + +#include "Reactor.hpp" + +#include "Canvas.hpp" +#include "CanvasModule.hpp" +#include "CanvasPort.hpp" +#include "ClientID.hpp" +#include "Configuration.hpp" +#include "Driver.hpp" +#include "ILog.hpp" +#include "Patchage.hpp" +#include "PortID.hpp" +#include "warnings.hpp" + +#include "ganv/Port.hpp" + +PATCHAGE_DISABLE_FMT_WARNINGS +#include +PATCHAGE_RESTORE_WARNINGS + +#include + +#include +#include +#include + +namespace patchage { + +Reactor::Reactor(Patchage& patchage) + : _patchage{patchage} + , _log{patchage.log()} +{} + +void +Reactor::add_driver(PortID::Type type, Driver* driver) +{ + _drivers.emplace(type, driver); +} + +void +Reactor::operator()(const action::ConnectPorts& action) +{ + if (action.tail.type() != action.head.type()) { + _log.warning("Unable to connect incompatible port types"); + return; + } + + auto d = _drivers.find(action.tail.type()); + if (d == _drivers.end()) { + _log.error(fmt::format("No driver for port type {}", action.tail.type())); + return; + } + + d->second->connect(action.tail, action.head); +} + +void +Reactor::operator()(const action::DisconnectClient& action) +{ + if (CanvasModule* mod = find_module(action.client, action.direction)) { + for (Ganv::Port* p : *mod) { + p->disconnect(); + } + } +} + +void +Reactor::operator()(const action::DisconnectPort& action) +{ + if (CanvasPort* port = find_port(action.port)) { + port->disconnect(); + } +} + +void +Reactor::operator()(const action::DisconnectPorts& action) +{ + if (action.tail.type() != action.head.type()) { + _log.error("Unable to disconnect incompatible port types"); + return; + } + + auto d = _drivers.find(action.tail.type()); + if (d == _drivers.end()) { + _log.error("No driver for port type"); + return; + } + + d->second->disconnect(action.tail, action.head); +} + +void +Reactor::operator()(const action::MoveModule& action) +{ + if (CanvasModule* mod = find_module(action.client, action.direction)) { + _patchage.conf().set_module_location( + mod->name(), action.direction, {action.x, action.y}); + } +} + +void +Reactor::operator()(const action::SplitModule& action) +{ + if (CanvasModule* mod = find_module(action.client, SignalDirection::duplex)) { + _patchage.conf().set_module_split(mod->name(), true); + _patchage.refresh(); + } +} + +void +Reactor::operator()(const action::UnsplitModule& action) +{ + CanvasModule* mod = find_module(action.client, SignalDirection::input); + if (mod || (mod = find_module(action.client, SignalDirection::output))) { + _patchage.conf().set_module_split(mod->name(), false); + _patchage.refresh(); + } +} + +void +Reactor::operator()(const Action& action) +{ + boost::apply_visitor(*this, action); +} + +CanvasModule* +Reactor::find_module(const ClientID& client, const SignalDirection type) +{ + return _patchage.canvas()->find_module(client, type); +} + +CanvasPort* +Reactor::find_port(const PortID& port) +{ + return _patchage.canvas()->find_port(port); +} + +} // namespace patchage diff --git a/src/Reactor.hpp b/src/Reactor.hpp new file mode 100644 index 0000000..bb31cca --- /dev/null +++ b/src/Reactor.hpp @@ -0,0 +1,74 @@ +/* This file is part of Patchage. + * Copyright 2007-2021 David Robillard + * + * Patchage is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. + * + * You should have received a copy of the GNU General Public License + * along with Patchage. If not, see . + */ + +#ifndef PATCHAGE_REACTOR_HPP +#define PATCHAGE_REACTOR_HPP + +#include "Action.hpp" +#include "ClientID.hpp" +#include "PortID.hpp" +#include "SignalDirection.hpp" + +#include + +namespace patchage { + +class CanvasModule; +class CanvasPort; +class Driver; +class ILog; +class Patchage; + +/// Reacts to actions from the user +class Reactor +{ +public: + using result_type = void; ///< For boost::apply_visitor + + explicit Reactor(Patchage& patchage); + + Reactor(const Reactor&) = delete; + Reactor& operator=(const Reactor&) = delete; + + Reactor(Reactor&&) = delete; + Reactor& operator=(Reactor&&) = delete; + + ~Reactor() = default; + + void add_driver(PortID::Type type, Driver* driver); + + void operator()(const action::ConnectPorts& action); + void operator()(const action::DisconnectClient& action); + void operator()(const action::DisconnectPort& action); + void operator()(const action::DisconnectPorts& action); + void operator()(const action::MoveModule& action); + void operator()(const action::SplitModule& action); + void operator()(const action::UnsplitModule& action); + + void operator()(const Action& action); + +private: + CanvasModule* find_module(const ClientID& client, SignalDirection type); + CanvasPort* find_port(const PortID& port); + + Patchage& _patchage; + ILog& _log; + std::unordered_map _drivers; +}; + +} // namespace patchage + +#endif // PATCHAGE_REACTOR_HPP diff --git a/src/handle_event.hpp b/src/handle_event.hpp index 975b3bb..6a62d61 100644 --- a/src/handle_event.hpp +++ b/src/handle_event.hpp @@ -1,5 +1,5 @@ /* This file is part of Patchage. - * Copyright 2007-2020 David Robillard + * Copyright 2007-2021 David Robillard * * Patchage is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free @@ -23,7 +23,7 @@ namespace patchage { class Patchage; -/// Handle an event in the GUI +/// Handle an event from the system by updating the GUI as necessary void handle_event(Patchage& patchage, const Event& event); -- cgit v1.2.1