+
+void
+RouteUI::setup_invert_buttons ()
+{
+ /* remove old invert buttons */
+ for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
+ _invert_button_box.remove (**i);
+ }
+
+ _invert_buttons.clear ();
+
+ if (!_route || !_route->input()) {
+ return;
+ }
+
+ uint32_t const N = _route->input()->n_ports().n_audio ();
+
+ uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
+
+ for (uint32_t i = 0; i < to_add; ++i) {
+ ArdourButton* b = manage (new ArdourButton);
+ b->set_size_request(20,20);
+ b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
+ b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i));
+
+ b->set_name (X_("invert button"));
+ if (to_add == 1) {
+ if (N > 1) {
+ b->set_text (string_compose (X_("Ø (%1)"), N));
+ } else {
+ b->set_text (X_("Ø"));
+ }
+ } else {
+ b->set_text (string_compose (X_("Ø%1"), i + 1));
+ }
+
+ if (N <= _max_invert_buttons) {
+ UI::instance()->set_tip (*b, string_compose (_("Left-click to invert (phase reverse) channel %1 of this track. Right-click to show menu."), i + 1));
+ } else {
+ UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
+ }
+
+ _invert_buttons.push_back (b);
+ _invert_button_box.pack_start (*b);
+ }
+
+ _invert_button_box.set_spacing (1);
+ _invert_button_box.show_all ();
+}
+
+void
+RouteUI::set_invert_button_state ()
+{
+ ++_i_am_the_modifier;
+
+ uint32_t const N = _route->input()->n_ports().n_audio();
+ if (N > _max_invert_buttons) {
+
+ /* One button for many channels; explicit active if all channels are inverted,
+ implicit active if some are, off if none are.
+ */
+
+ ArdourButton* b = _invert_buttons.front ();
+
+ if (_route->phase_invert().count() == _route->phase_invert().size()) {
+ b->set_active_state (Gtkmm2ext::ExplicitActive);
+ } else if (_route->phase_invert().any()) {
+ b->set_active_state (Gtkmm2ext::ImplicitActive);
+ } else {
+ b->set_active_state (Gtkmm2ext::Off);
+ }
+
+ } else {
+
+ /* One button per channel; just set active */
+
+ int j = 0;
+ for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
+ (*i)->set_active (_route->phase_invert (j));
+ }
+
+ }
+
+ --_i_am_the_modifier;
+}
+
+bool
+RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
+{
+ if (ev->button == 1 && i < _invert_buttons.size()) {
+ uint32_t const N = _route->input()->n_ports().n_audio ();
+ if (N <= _max_invert_buttons) {
+ /* left-click inverts phase so long as we have a button per channel */
+ _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+RouteUI::invert_press (GdkEventButton* ev)
+{
+ using namespace Menu_Helpers;
+
+ uint32_t const N = _route->input()->n_ports().n_audio();
+ if (N <= _max_invert_buttons && ev->button != 3) {
+ /* If we have an invert button per channel, we only pop
+ up a menu on right-click; left click is handled
+ on release.
+ */
+ return true;
+ }
+
+ delete _invert_menu;
+ _invert_menu = new Menu;
+ _invert_menu->set_name ("ArdourContextMenu");
+ MenuList& items = _invert_menu->items ();
+
+ for (uint32_t i = 0; i < N; ++i) {
+ items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
+ CheckMenuItem* e = dynamic_cast<CheckMenuItem*> (&items.back ());
+ ++_i_am_the_modifier;
+ e->set_active (_route->phase_invert (i));
+ --_i_am_the_modifier;
+ }
+
+ _invert_menu->popup (0, ev->time);
+
+ return false;
+}
+
+void
+RouteUI::invert_menu_toggled (uint32_t c)
+{
+ if (_i_am_the_modifier) {
+ return;
+ }
+
+ _route->set_phase_invert (c, !_route->phase_invert (c));
+}
+
+void
+RouteUI::set_invert_sensitive (bool yn)
+{
+ for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
+ (*b)->set_sensitive (yn);
+ }
+}
+
+void
+RouteUI::request_redraw ()
+{
+ if (_route) {
+ _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
+ }
+}
+
+/** The Route's gui_changed signal has been emitted */
+void
+RouteUI::route_gui_changed (string what_changed)
+{
+ if (what_changed == "color") {
+ if (set_color_from_route () == 0) {
+ route_color_changed ();
+ }
+ }
+}
+
+/** @return the color that this route should use; it maybe its own,
+ or it maybe that of its route group.
+*/
+Gdk::Color
+RouteUI::color () const
+{
+ RouteGroup* g = _route->route_group ();
+
+ if (g && g->is_color()) {
+ return GroupTabs::group_color (g);
+ }
+
+ return _color;
+}
+
+void
+RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
+{
+ _showing_sends_to = send_to;
+ BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
+}
+
+void
+RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
+{
+ if (_route == send_to) {
+ show_sends_button->set_active (true);
+ send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun (*this, &RouteUI::send_blink));
+ } else {
+ show_sends_button->set_active (false);
+ send_blink_connection.disconnect ();
+ }
+}
+
+RouteGroup*
+RouteUI::route_group() const
+{
+ return _route->route_group();
+}