diff --git a/gtk2_ardour/io_button.cc b/gtk2_ardour/io_button.cc index e75aaa9eb3..5aa330895d 100644 --- a/gtk2_ardour/io_button.cc +++ b/gtk2_ardour/io_button.cc @@ -45,6 +45,377 @@ using namespace PBD; using namespace Gtkmm2ext; using namespace std; +void +IOButtonBase::maybe_update (PropertyChange const& what_changed) +{ + if (what_changed.contains (ARDOUR::Properties::name)) { + update (); + } +} + +static bool +exclusively_connected (boost::shared_ptr dest_io, boost::shared_ptr io, DataType dt, uint32_t tcnt, std::string const& name, ostringstream& label) +{ + /* check if IO is exclusively connected to a subset of this Route's ports */ + uint32_t n = 0; + uint32_t cnt = 0; + std::set pn; + PortSet const& psa (dest_io->ports ()); + PortSet const& psb (io->ports ()); + + for (auto a = psa.begin (dt); a != psa.end (dt); ++a, ++n) { + for (auto b = psb.begin (dt); b != psb.end (dt); ++b) { + if (a->connected_to (b->name ())) { + ++cnt; + pn.insert (n); + } + } + } + + if (cnt != tcnt) { + /* IO has additional connections. + * No need to check other Routes/IOPs (they will produce + * the same result). + */ + return false; + } + + label << Gtkmm2ext::markup_escape_text (name) << " "; + + bool first = true; + for (auto const& num : pn) { + if (first) { + first = false; + } else { + label << "+"; + } + label << dest_io->bundle ()->channel_name (num); + } + return true; +} + +DataType +IOButtonBase::guess_main_type (boost::shared_ptr io) +{ + /* The heuristic follows these principles: + * A) If all ports that the user connected are of the same type, then he + * very probably intends to use the IO with that type. A common subcase + * is when the IO has only ports of the same type (connected or not). + * B) If several types of ports are connected, then we should guess based + * on the likeliness of the user wanting to use a given type. + * We assume that the DataTypes are ordered from the most likely to the + * least likely when iterating or comparing them with "<". + * C) If no port is connected, the same logic can be applied with all ports + * instead of connected ones. TODO: Try other ideas, for instance look at + * the last plugin output when |for_input| is false (note: when StrictIO + * the outs of the last plugin should be the same as the outs of the route + * modulo the panner which forwards non-audio anyway). + * All of these constraints are respected by the following algorithm that + * just returns the most likely datatype found in connected ports if any, or + * available ports if any (since if all ports are of the same type, the most + * likely found will be that one obviously). */ + + /* Find most likely type among connected ports */ + DataType type = DataType::NIL; /* NIL is always last so least likely */ + for (PortSet::iterator p = io->ports ().begin (); p != io->ports ().end (); ++p) { + if (p->connected () && p->type () < type) + type = p->type (); + } + if (type != DataType::NIL) { + /* There has been a connected port (necessarily non-NIL) */ + return type; + } + + /* Find most likely type among available ports. + * The iterator stops before NIL. */ + for (DataType::iterator t = DataType::begin (); t != DataType::end (); ++t) { + if (io->n_ports ().n (*t) > 0) + return *t; + } + + /* No port at all, return the most likely datatype by default */ + return DataType::front (); +} + +/* + * Output port labelling + * + * Case 1: Each output has one connection, all connections are to system:playback_%i + * out 1 -> system:playback_1 + * out 2 -> system:playback_2 + * out 3 -> system:playback_3 + * Display as: 1/2/3 + * + * Case 2: Each output has one connection, all connections are to ardour:track_x + * out 1 -> ardour:track_x/in 1 + * out 2 -> ardour:track_x/in 2 + * Display as: track_x + * + * Case 2b: Some outputs are connected, but all connections are to ardour:track_x + * out 1 -> ardour:track_x/in 1 + * out 2 -> N/C + * Display as: track_x 1 + * + * Case 3, 3a: + * same as 2, but for I/O Plugins (not routes) + * + * Case 4: Each output has one connection, all connections are to Jack client "program x" + * out 1 -> program x:foo + * out 2 -> program x:foo + * Display as: program x + * this include internal one to many connections which show as "ardour" + * + * Case 4: No connections (Disconnected) + * Display as: - + * + * Default case (unusual routing): + * Display as: *number of connections* + * + * + * Tooltips + * + * .-----------------------------------------------. + * | Mixdown | + * | out 1 -> ardour:master/in 1, jamin:input/in 1 | + * | out 2 -> ardour:master/in 2, jamin:input/in 2 | + * '-----------------------------------------------' + * .-----------------------------------------------. + * | Guitar SM58 | + * | Disconnected | + * '-----------------------------------------------' + */ +void +IOButtonBase::set_label (IOButtonBase& self, ARDOUR::Session& session, boost::shared_ptr& bndl, boost::shared_ptr io) +{ + ostringstream tooltip; + ostringstream label; + bool have_label = false; + + uint32_t total_connection_count = 0; + uint32_t typed_connection_count = 0; + bool each_typed_port_has_one_connection = true; + + DataType dt = guess_main_type (io); + bool input = io->direction () == IO::Input; + string arrow = Gtkmm2ext::markup_escape_text (input ? " <- " : " -> "); + + /* Fill in the tooltip. Also count: + * - The total number of connections. + * - The number of main-typed connections. + * - Whether each main-typed port has exactly one connection. */ + if (input) { + tooltip << string_compose (_("INPUT to %1"), + Gtkmm2ext::markup_escape_text (io->name ())); + } else { + tooltip << string_compose (_("OUTPUT from %1"), + Gtkmm2ext::markup_escape_text (io->name ())); + } + + vector port_connections; + + for (auto const& port : io->ports ()) { + port_connections.clear (); + port->get_connections (port_connections); + + uint32_t port_connection_count = 0; + + for (auto const& i : port_connections) { + ++port_connection_count; + + if (port_connection_count == 1) { + tooltip << endl + << Gtkmm2ext::markup_escape_text (port->name ().substr (port->name ().find ("/") + 1)); + tooltip << arrow; + } else { + tooltip << ", "; + } + + tooltip << Gtkmm2ext::markup_escape_text (i); + } + + total_connection_count += port_connection_count; + if (port->type () == dt) { + typed_connection_count += port_connection_count; + each_typed_port_has_one_connection &= (port_connection_count == 1); + } + } + + if (total_connection_count == 0) { + tooltip << endl + << _("Disconnected"); + } + + if (typed_connection_count == 0) { + label << "-"; + have_label = true; + } + + /* Are all main-typed channels connected to the same route ? */ + if (!have_label) { + boost::shared_ptr routes = session.get_routes (); + for (auto const& route : *routes) { + boost::shared_ptr dest_io = input ? route->output () : route->input (); + if (io->bundle ()->connected_to (dest_io->bundle (), session.engine (), dt, true)) { + label << Gtkmm2ext::markup_escape_text (route->name ()); + have_label = true; + route->PropertyChanged.connect (self._bundle_connections, invalidator (self), boost::bind (&IOButtonBase::maybe_update, &self, _1), gui_context ()); + break; + } + + if (!io->connected_to (dest_io)) { + continue; + } + + if (exclusively_connected (dest_io, io, dt, typed_connection_count, route->name (), label)) { + have_label = true; + route->PropertyChanged.connect (self._bundle_connections, invalidator (self), boost::bind (&IOButtonBase::maybe_update, &self, _1), gui_context ()); + } + break; + } + } + + /* Are all main-typed channels connected to the same (user) bundle ? */ + if (!have_label) { + boost::shared_ptr bundles = session.bundles (); + boost::shared_ptr ap = boost::dynamic_pointer_cast (session.vkbd_output_port ()); + std::string vkbd_portname = AudioEngine::instance ()->make_port_name_non_relative (ap->name ()); + for (auto const& bundle : *bundles) { + if (boost::dynamic_pointer_cast (bundle) == 0) { + if (!bundle->offers_port (vkbd_portname)) { + continue; + } + } + if (io->bundle ()->connected_to (bundle, session.engine (), dt, true)) { + label << Gtkmm2ext::markup_escape_text (bundle->name ()); + have_label = true; + bndl = bundle; + break; + } + } + } + + /* Is each main-typed channel only connected to a physical output ? */ + if (!have_label && each_typed_port_has_one_connection) { + ostringstream temp_label; + vector phys; + string playorcapture; + if (input) { + session.engine ().get_physical_inputs (dt, phys); + playorcapture = "capture_"; + } else { + session.engine ().get_physical_outputs (dt, phys); + playorcapture = "playback_"; + } + for (PortSet::iterator port = io->ports ().begin (dt); + port != io->ports ().end (dt); + ++port) { + string pn = ""; + for (auto const& s : phys) { + if (!port->connected_to (s)) { + continue; + } + pn = AudioEngine::instance ()->get_pretty_name_by_name (s); + if (pn.empty ()) { + string::size_type start = (s).find (playorcapture); + if (start != string::npos) { + pn = (s).substr (start + playorcapture.size ()); + } + } + break; + } + + if (pn.empty ()) { + temp_label.str (""); /* erase the failed attempt */ + break; + } + if (port != io->ports ().begin (dt)) { + temp_label << "/"; + } + temp_label << pn; + } + + if (!temp_label.str ().empty ()) { + label << temp_label.str (); + have_label = true; + } + } + + /* check for direct connections to I/O Plugins */ + if (!have_label) { + for (auto const& iop : *session.io_plugs ()) { + boost::shared_ptr i = input ? iop->output () : iop->input (); + if (!io->connected_to (i)) { + continue; + } + + /* direct 1:1 connection to IOP */ + if (io->bundle ()->connected_to (i->bundle (), session.engine (), dt, true)) { + label << Gtkmm2ext::markup_escape_text (iop->io_name ()); + have_label = true; + break; + } + + if (exclusively_connected (i, io, dt, typed_connection_count, iop->io_name (), label)) { + have_label = true; + } + break; + } + } + + // TODO check for internal connection (port_is_mine), do not simply + // print "ardour" as client name + + /* Is each main-typed channel connected to a single and different port with + * the same client name (e.g. another JACK client) ? */ + if (!have_label && each_typed_port_has_one_connection) { + string maybe_client = ""; + vector connections; + for (PortSet::iterator port = io->ports ().begin (dt); + port != io->ports ().end (dt); + ++port) { + port_connections.clear (); + port->get_connections (port_connections); + string connection = port_connections.front (); + + vector::iterator i = connections.begin (); + while (i != connections.end () && *i != connection) { + ++i; + } + if (i != connections.end ()) { + break; /* duplicate connection */ + } + connections.push_back (connection); + + connection = connection.substr (0, connection.find (":")); + + if (maybe_client.empty ()) { + maybe_client = connection; + } + if (maybe_client != connection) { + break; + } + } + if (connections.size () == io->n_ports ().n (dt)) { + label << Gtkmm2ext::markup_escape_text (maybe_client); + have_label = true; + } + } + + /* Odd configuration */ + if (!have_label) { + label << "*" << total_connection_count << "*"; + } + + if (total_connection_count > typed_connection_count) { + label << "\u2295"; /* circled plus */ + } + + self.set_text (label.str ()); + set_tooltip (&self, tooltip.str ()); +} + +/* ****************************************************************************/ + IOButton::IOButton (bool input) : _input (input) , _route_ui (0) @@ -259,7 +630,7 @@ IOButton::button_press (GdkEventButton* ev) DataType intended_type = guess_main_type (_input ? _route->input () : _route->output ()); /* other routes inputs */ - for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) { + for (ARDOUR::RouteList::const_iterator i = copy.begin (); i != copy.end (); ++i) { if ((*i)->is_foldbackbus () || _route->is_foldbackbus ()) { continue; } @@ -267,7 +638,7 @@ IOButton::button_press (GdkEventButton* ev) /* do not offer connections that would cause feedback */ continue; } - maybe_add_bundle_to_menu ((*i)->input()->bundle(), current, intended_type); + maybe_add_bundle_to_menu ((*i)->input ()->bundle (), current, intended_type); } /* then try adding user output bundles, often labeled/grouped physical inputs */ @@ -323,356 +694,19 @@ IOButton::button_press (GdkEventButton* ev) return true; } -DataType -IOButton::guess_main_type (boost::shared_ptr io) -{ - /* The heuristic follows these principles: - * A) If all ports that the user connected are of the same type, then he - * very probably intends to use the IO with that type. A common subcase - * is when the IO has only ports of the same type (connected or not). - * B) If several types of ports are connected, then we should guess based - * on the likeliness of the user wanting to use a given type. - * We assume that the DataTypes are ordered from the most likely to the - * least likely when iterating or comparing them with "<". - * C) If no port is connected, the same logic can be applied with all ports - * instead of connected ones. TODO: Try other ideas, for instance look at - * the last plugin output when |for_input| is false (note: when StrictIO - * the outs of the last plugin should be the same as the outs of the route - * modulo the panner which forwards non-audio anyway). - * All of these constraints are respected by the following algorithm that - * just returns the most likely datatype found in connected ports if any, or - * available ports if any (since if all ports are of the same type, the most - * likely found will be that one obviously). */ - - /* Find most likely type among connected ports */ - DataType type = DataType::NIL; /* NIL is always last so least likely */ - for (PortSet::iterator p = io->ports ().begin (); p != io->ports ().end (); ++p) { - if (p->connected () && p->type () < type) - type = p->type (); - } - if (type != DataType::NIL) { - /* There has been a connected port (necessarily non-NIL) */ - return type; - } - - /* Find most likely type among available ports. - * The iterator stops before NIL. */ - for (DataType::iterator t = DataType::begin (); t != DataType::end (); ++t) { - if (io->n_ports ().n (*t) > 0) - return *t; - } - - /* No port at all, return the most likely datatype by default */ - return DataType::front (); -} - -/* - * Output port labelling - * - * Case 1: Each output has one connection, all connections are to system:playback_%i - * out 1 -> system:playback_1 - * out 2 -> system:playback_2 - * out 3 -> system:playback_3 - * Display as: 1/2/3 - * - * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1 - * out 1 -> ardour:track_x/in 1 - * out 2 -> ardour:track_x/in 2 - * Display as: track_x - * - * Case 3: Each output has one connection, all connections are to Jack client "program x" - * out 1 -> program x:foo - * out 2 -> program x:foo - * Display as: program x - * - * Case 4: No connections (Disconnected) - * Display as: - - * - * Default case (unusual routing): - * Display as: *number of connections* - * - * - * Tooltips - * - * .-----------------------------------------------. - * | Mixdown | - * | out 1 -> ardour:master/in 1, jamin:input/in 1 | - * | out 2 -> ardour:master/in 2, jamin:input/in 2 | - * '-----------------------------------------------' - * .-----------------------------------------------. - * | Guitar SM58 | - * | Disconnected | - * '-----------------------------------------------' - */ - void IOButton::update () { boost::shared_ptr bundle; _bundle_connections.drop_connections (); - set_label (*this, _route->session(), bundle, _input ? _route->input () : _route->output ()); + set_label (*this, _route->session (), bundle, _input ? _route->input () : _route->output ()); if (bundle) { bundle->Changed.connect (_bundle_connections, invalidator (*this), boost::bind (&IOButton::update, this), gui_context ()); } } -void -IOButton::set_label (ArdourWidgets::ArdourButton& self, ARDOUR::Session& session, boost::shared_ptr& bndl, boost::shared_ptr io) -{ - ostringstream tooltip; - ostringstream label; - bool have_label = false; - - uint32_t total_connection_count = 0; - uint32_t typed_connection_count = 0; - bool each_typed_port_has_one_connection = true; - - DataType dt = guess_main_type (io); - bool input = io->direction () == IO::Input; - string arrow = Gtkmm2ext::markup_escape_text (input ? " <- " : " -> "); - - /* Fill in the tooltip. Also count: - * - The total number of connections. - * - The number of main-typed connections. - * - Whether each main-typed port has exactly one connection. */ - if (input) { - tooltip << string_compose (_("INPUT to %1"), - Gtkmm2ext::markup_escape_text (io->name ())); - } else { - tooltip << string_compose (_("OUTPUT from %1"), - Gtkmm2ext::markup_escape_text (io->name ())); - } - - vector port_connections; - - for (auto const& port : io->ports ()) { - port_connections.clear (); - port->get_connections (port_connections); - - uint32_t port_connection_count = 0; - - for (auto const& i : port_connections) { - ++port_connection_count; - - if (port_connection_count == 1) { - tooltip << endl - << Gtkmm2ext::markup_escape_text (port->name ().substr (port->name ().find ("/") + 1)); - tooltip << arrow; - } else { - tooltip << ", "; - } - - tooltip << Gtkmm2ext::markup_escape_text (i); - } - - total_connection_count += port_connection_count; - if (port->type () == dt) { - typed_connection_count += port_connection_count; - each_typed_port_has_one_connection &= (port_connection_count == 1); - } - } - - if (total_connection_count == 0) { - tooltip << endl - << _("Disconnected"); - } - - if (typed_connection_count == 0) { - label << "-"; - have_label = true; - } - - /* Are all main-typed channels connected to the same route ? */ - if (!have_label) { - boost::shared_ptr routes = session.get_routes (); - for (ARDOUR::RouteList::const_iterator route = routes->begin (); - route != routes->end (); - ++route) { - boost::shared_ptr dest_io = input ? (*route)->output () : (*route)->input (); - if (io->bundle ()->connected_to (dest_io->bundle (), session.engine (), dt, true)) { - label << Gtkmm2ext::markup_escape_text ((*route)->name ()); - have_label = true; - break; - } - } - } - - /* Are all main-typed channels connected to the same (user) bundle ? */ - if (!have_label) { - boost::shared_ptr bundles = session.bundles (); - boost::shared_ptr ap = boost::dynamic_pointer_cast (session.vkbd_output_port ()); - std::string vkbd_portname = AudioEngine::instance ()->make_port_name_non_relative (ap->name ()); - for (auto const& bundle : *bundles) { - if (boost::dynamic_pointer_cast (bundle) == 0) { - if (!bundle->offers_port (vkbd_portname)) { - continue; - } - } - if (io->bundle ()->connected_to (bundle, session.engine (), dt, true)) { - label << Gtkmm2ext::markup_escape_text (bundle->name ()); - have_label = true; - bndl = bundle; - break; - } - } - } - - /* Is each main-typed channel only connected to a physical output ? */ - if (!have_label && each_typed_port_has_one_connection) { - ostringstream temp_label; - vector phys; - string playorcapture; - if (input) { - session.engine ().get_physical_inputs (dt, phys); - playorcapture = "capture_"; - } else { - session.engine ().get_physical_outputs (dt, phys); - playorcapture = "playback_"; - } - for (PortSet::iterator port = io->ports ().begin (dt); - port != io->ports ().end (dt); - ++port) { - string pn = ""; - for (auto const& s : phys) { - if (!port->connected_to (s)) { - continue; - } - pn = AudioEngine::instance ()->get_pretty_name_by_name (s); - if (pn.empty ()) { - string::size_type start = (s).find (playorcapture); - if (start != string::npos) { - pn = (s).substr (start + playorcapture.size ()); - } - } - break; - } - - if (pn.empty ()) { - temp_label.str (""); /* erase the failed attempt */ - break; - } - if (port != io->ports ().begin (dt)) { - temp_label << "/"; - } - temp_label << pn; - } - - if (!temp_label.str ().empty ()) { - label << temp_label.str (); - have_label = true; - } - } - - /* check for direct connections to I/O Plugins */ - if (!have_label) { - for (auto const& iop : *session.io_plugs ()) { - boost::shared_ptr i = input ? iop->output () : iop->input (); - if (!io->connected_to (i)) { - continue; - } - - /* direct 1:1 connection to IOP */ - if (io->bundle ()->connected_to (i->bundle (), session.engine (), dt, true)) { - label << iop->io_name(); - have_label = true; - break; - } - - /* check if IO is exclusively connected to a subset of this IOP's ports */ - uint32_t n = 0; - uint32_t cnt = 0; - std::set pn; - PortSet const& psa (i->ports ()); - PortSet const& psb (io->ports ()); - - for (auto a = psa.begin (dt); a != psa.end (dt); ++a, ++n) { - for (auto b = psb.begin (dt); b != psb.end (dt); ++b) { - if (a->connected_to (b->name ())) { - ++cnt; - pn.insert (n); - } - } - } - - if (cnt != typed_connection_count) { - /* IO has additional connections. - * No need to check other IOPs (they will produce - * the same result). - */ - assert (cnt > 0); - break; - } - - have_label = true; - label << iop->io_name() << " "; - - bool first = true; - for (auto const& num : pn) { - if (first) { - first = false; - } else { - label << "+"; - } - label << i->bundle()->channel_name (num); - } - break; - } - } - - // TODO check for internal connection (port_is_mine), do not simply - // print "ardour" as client name - - /* Is each main-typed channel connected to a single and different port with - * the same client name (e.g. another JACK client) ? */ - if (!have_label && each_typed_port_has_one_connection) { - string maybe_client = ""; - vector connections; - for (PortSet::iterator port = io->ports ().begin (dt); - port != io->ports ().end (dt); - ++port) { - port_connections.clear (); - port->get_connections (port_connections); - string connection = port_connections.front (); - - vector::iterator i = connections.begin (); - while (i != connections.end () && *i != connection) { - ++i; - } - if (i != connections.end ()) { - break; /* duplicate connection */ - } - connections.push_back (connection); - - connection = connection.substr (0, connection.find (":")); - - if (maybe_client.empty ()) { - maybe_client = connection; - } - if (maybe_client != connection) { - break; - } - } - if (connections.size () == io->n_ports ().n (dt)) { - label << maybe_client; - have_label = true; - } - } - - /* Odd configuration */ - if (!have_label) { - label << "*" << total_connection_count << "*"; - } - - if (total_connection_count > typed_connection_count) { - label << "\u2295"; /* circled plus */ - } - - self.set_text (label.str ()); - set_tooltip (&self, tooltip.str ()); -} - void IOButton::maybe_add_bundle_to_menu (boost::shared_ptr b, ARDOUR::BundleList const& /*current*/, ARDOUR::DataType type) { @@ -708,7 +742,7 @@ IOButton::maybe_add_bundle_to_menu (boost::shared_ptr b, ARDOUR::BundleL } /* Avoid adding duplicates */ - list >::iterator i = _menu_bundles.begin (); + list>::iterator i = _menu_bundles.begin (); while (i != _menu_bundles.end () && b->has_same_ports (*i) == false) { ++i; } diff --git a/gtk2_ardour/io_button.h b/gtk2_ardour/io_button.h index f4e605f66c..1bf7763cce 100644 --- a/gtk2_ardour/io_button.h +++ b/gtk2_ardour/io_button.h @@ -25,20 +25,44 @@ #include #include +#include "ardour/data_type.h" + #include "widgets/ardour_button.h" +namespace PBD +{ + class PropertyChange; +} + namespace ARDOUR { class Bundle; class IO; class Route; + class Session; class Track; class Port; } class RouteUI; -class IOButton : public ArdourWidgets::ArdourButton +class IOButtonBase : public ArdourWidgets::ArdourButton +{ +public: + virtual ~IOButtonBase () {} + +protected: + static void set_label (IOButtonBase&, ARDOUR::Session&, boost::shared_ptr&, boost::shared_ptr); + static ARDOUR::DataType guess_main_type (boost::shared_ptr); + + virtual void update () = 0; + void maybe_update (PBD::PropertyChange const& what_changed); + + PBD::ScopedConnectionList _connections; + PBD::ScopedConnectionList _bundle_connections; +}; + +class IOButton : public IOButtonBase { public: IOButton (bool input); @@ -46,9 +70,6 @@ public: void set_route (boost::shared_ptr, RouteUI*); - static ARDOUR::DataType guess_main_type (boost::shared_ptr); - static void set_label (ArdourWidgets::ArdourButton&, ARDOUR::Session&, boost::shared_ptr&, boost::shared_ptr); - private: void update (); bool button_press (GdkEventButton*); @@ -69,8 +90,6 @@ private: RouteUI* _route_ui; Gtk::Menu _menu; std::list > _menu_bundles; - PBD::ScopedConnectionList _connections; - PBD::ScopedConnectionList _bundle_connections; }; #endif diff --git a/gtk2_ardour/io_plugin_window.cc b/gtk2_ardour/io_plugin_window.cc index 98e3a2e15b..f2699d6bd0 100644 --- a/gtk2_ardour/io_plugin_window.cc +++ b/gtk2_ardour/io_plugin_window.cc @@ -38,7 +38,6 @@ #include "context_menu_helper.h" #include "gui_thread.h" #include "io_plugin_window.h" -#include "io_button.h" #include "io_selector.h" #include "mixer_ui.h" #include "plugin_selector.h" @@ -548,7 +547,7 @@ IOPluginWindow::IOButton::update () boost::shared_ptr bundle; _bundle_connections.drop_connections (); - ::IOButton::set_label (*this, _io->session (), bundle, _io); + set_label (*this, _io->session (), bundle, _io); if (bundle) { bundle->Changed.connect (_bundle_connections, invalidator (*this), boost::bind (&IOButton::update, this), gui_context ()); diff --git a/gtk2_ardour/io_plugin_window.h b/gtk2_ardour/io_plugin_window.h index 2fdda58ce7..388f710c8e 100644 --- a/gtk2_ardour/io_plugin_window.h +++ b/gtk2_ardour/io_plugin_window.h @@ -26,10 +26,9 @@ #include "pbd/signals.h" -#include "widgets/ardour_button.h" - #include "ardour_window.h" #include "plugin_interest.h" +#include "io_button.h" #include "window_manager.h" namespace ARDOUR @@ -106,7 +105,7 @@ private: bool _is_pre; }; - class IOButton : public ArdourWidgets::ArdourButton + class IOButton : public IOButtonBase { public: IOButton (boost::shared_ptr, bool pre); @@ -128,8 +127,6 @@ private: bool _pre; Gtk::Menu _menu; IOSelectorWindow* _io_selector; - PBD::ScopedConnectionList _connections; - PBD::ScopedConnectionList _bundle_connections; }; class IOPlugUI : public Gtk::Alignment