X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Ffoldback_strip.cc;h=17fd37c1b2a36eef2bd1f1a304e265e0459dbf64;hb=9f474953fd878a703f7b69d886f5397fc57f9cca;hp=898023d5aa8e1ee97f17dad30341de43f3462df5;hpb=5414728c18e577740817f84ecbd014cbd8c73559;p=ardour.git diff --git a/gtk2_ardour/foldback_strip.cc b/gtk2_ardour/foldback_strip.cc index 898023d5aa..17fd37c1b2 100644 --- a/gtk2_ardour/foldback_strip.cc +++ b/gtk2_ardour/foldback_strip.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2006 Paul Davis + Copyright (C) 2018-2019 Len Ovens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,34 +16,16 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include -#include - -#include - -#include - -#include "pbd/convert.h" -#include "pbd/enumwriter.h" -#include "pbd/replace_all.h" -#include "pbd/stacktrace.h" - -#include "ardour/amp.h" #include "ardour/audioengine.h" -#include "ardour/internal_send.h" -#include "ardour/io.h" #include "ardour/pannable.h" -#include "ardour/panner.h" #include "ardour/panner_shell.h" #include "ardour/panner_manager.h" -#include "ardour/port.h" #include "ardour/profile.h" #include "ardour/route.h" #include "ardour/send.h" #include "ardour/session.h" -#include "ardour/types.h" #include "ardour/user_bundle.h" +#include "ardour/value_as_string.h" #include "gtkmm2ext/gtk_ui.h" #include "gtkmm2ext/menu_elems.h" @@ -59,6 +41,7 @@ #include "keyboard.h" #include "public_editor.h" #include "send_ui.h" +#include "timers.h" #include "io_selector.h" #include "utils.h" #include "gui_thread.h" @@ -73,6 +56,238 @@ using namespace Gtk; using namespace Gtkmm2ext; using namespace std; +#define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale())) + +FoldbackSend::FoldbackSend (boost::shared_ptr snd, \ + boost::shared_ptr sr, boost::shared_ptr fr, uint32_t wd) + : _button (ArdourButton::led_default_elements) + , _send (snd) + , _send_route (sr) + , _foldback_route (fr) + , _send_proc (snd) + , _send_del (snd) + , _width (wd) + , pan_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero)) + , _adjustment (gain_to_slider_position_with_max (1.0, Config->get_max_gain()), 0, 1, 0.01, 0.1) + , _slider (&_adjustment, boost::shared_ptr(), 0, max(13.f, rintf(13.f * UIConfiguration::instance().get_ui_scale()))) + , _ignore_ui_adjustment (true) + , _slider_persistant_tooltip (&_slider) + +{ + + HBox * snd_but_pan = new HBox (); + + _button.set_distinct_led_click (true); + _button.set_fallthrough_to_parent(true); + _button.set_led_left (true); + _button.signal_led_clicked.connect (sigc::mem_fun (*this, &FoldbackSend::led_clicked)); + _button.set_name ("processor prefader"); + _button.set_layout_ellipsize_width (PX_SCALE(_width) * PANGO_SCALE); + _button.set_text_ellipsize (Pango::ELLIPSIZE_END); + name_changed (); + snd_but_pan->pack_start (_button, true, true); + _button.set_active (_send_proc->enabled ()); + _button.show (); + + if (_foldback_route->input()->n_ports().n_audio() == 2) { + _button.set_layout_ellipsize_width (PX_SCALE(_width - 19) * PANGO_SCALE); + boost::shared_ptr pannable = _send_del->panner()->pannable(); + boost::shared_ptr ac; + ac = pannable->pan_azimuth_control; + pan_control.set_size_request (PX_SCALE(19), PX_SCALE(19)); + pan_control.set_tooltip_prefix (_("Pan: ")); + pan_control.set_name ("trim knob"); + pan_control.set_no_show_all (true); + snd_but_pan->pack_start (pan_control, false, false); + pan_control.show (); + pan_control.set_controllable (ac); + } + boost::shared_ptr lc; + lc = _send->gain_control(); + _slider.set_controllable (lc); + _slider.set_name ("ProcessorControlSlider"); + _slider.set_text (_("Level")); + + pack_start (*snd_but_pan, Gtk::PACK_SHRINK); + snd_but_pan->show(); + pack_start (_slider, true, true); + _slider.show (); + level_changed (); + + _adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &FoldbackSend::level_adjusted)); + lc->Changed.connect (_connections, invalidator (*this), boost::bind (&FoldbackSend::level_changed, this), gui_context ()); + _send_proc->ActiveChanged.connect (_connections, invalidator (*this), boost::bind (&FoldbackSend::send_state_changed, this), gui_context ()); + _button.signal_button_press_event().connect (sigc::mem_fun (*this, &FoldbackSend::button_press)); + _send_route->PropertyChanged.connect (_connections, invalidator (*this), boost::bind (&FoldbackSend::route_property_changed, this, _1), gui_context()); + + show (); + + +} + +FoldbackSend::~FoldbackSend () +{ + _connections.drop_connections(); + _slider.set_controllable (boost::shared_ptr ()); + pan_control.set_controllable (boost::shared_ptr ()); + _send = boost::shared_ptr (); + _send_route = boost::shared_ptr (); + _foldback_route = boost::shared_ptr (); + _send_proc = boost::shared_ptr (); + _send_del = boost::shared_ptr (); + +} + +void +FoldbackSend::route_property_changed (const PropertyChange& what_changed) +{ + if (what_changed.contains (ARDOUR::Properties::name)) { + name_changed (); + } +} + +void +FoldbackSend::name_changed () +{ + _button.set_text (_send_route->name ()); + + ArdourWidgets::set_tooltip (_button, Gtkmm2ext::markup_escape_text(_send_route->name())); +} + +void +FoldbackSend::led_clicked(GdkEventButton *ev) +{ + if (_send_proc) { + if (_button.get_active ()) { + _send_proc->enable (false); + + } else { + _send_proc->enable (true); + } + } +} + +gboolean +FoldbackSend::button_press (GdkEventButton* ev) +{ + if (ev->button == 1) { + Menu* menu = build_send_menu (); + + Gtkmm2ext::anchored_menu_popup(menu, &_button, "", 1, ev->time); + return true; + } + return false; +} + +void +FoldbackSend::send_state_changed () +{ + _button.set_active (_send_proc->enabled ()); + +} + +void +FoldbackSend::level_adjusted () +{ + if (_ignore_ui_adjustment) { + return; + } + boost::shared_ptr lc = _send->gain_control(); + + if (!lc) { + return; + } + + lc->set_value ( lc->interface_to_internal(_adjustment.get_value ()) , Controllable::NoGroup); + set_tooltip (); +} + +void +FoldbackSend::level_changed () +{ + boost::shared_ptr lc = _send->gain_control(); + if (!lc) { + return; + } + + _ignore_ui_adjustment = true; + + const double nval = lc->internal_to_interface (lc->get_value ()); + if (_adjustment.get_value() != nval) { + _adjustment.set_value (nval); + set_tooltip (); + } + + _ignore_ui_adjustment = false; +} + +void +FoldbackSend::set_tooltip () +{ + boost::shared_ptr lc = _send->gain_control(); + + if (!lc) { + return; + } + std::string tt = ARDOUR::value_as_string (lc->desc(), lc->get_value ()); + string sm = Gtkmm2ext::markup_escape_text (tt); + _slider_persistant_tooltip.set_tip (sm); +} + +Menu* +FoldbackSend::build_send_menu () +{ + using namespace Menu_Helpers; + + if (!_send) { + return NULL; + } + + Menu* menu = manage (new Menu); + MenuList& items = menu->items (); + menu->set_name ("ArdourContextMenu"); + + items.push_back ( + MenuElem(_("Copy track/bus gain to send"), sigc::bind (sigc::mem_fun (*this, &FoldbackSend::set_gain), -0.1)) + ); + items.push_back ( + MenuElem(_("Set send gain to -inf"), sigc::bind (sigc::mem_fun (*this, &FoldbackSend::set_gain), 0.0)) + ); + items.push_back ( + MenuElem(_("Set send gain to 0dB"), sigc::bind (sigc::mem_fun (*this, &FoldbackSend::set_gain), 1.0)) + ); + items.push_back (MenuElem(_("Remove This Send"), sigc::mem_fun (*this, &FoldbackSend::remove_me))); + + return menu; + +} + +void +FoldbackSend::set_gain (float new_gain) +{ + if (new_gain < 0) { + // get level from sending route + new_gain = _send_route->gain_control ()->get_value (); + } + boost::shared_ptr lc = _send->gain_control(); + + if (!lc) { + return; + } + lc->set_value (new_gain, Controllable::NoGroup); + +} + +void +FoldbackSend::remove_me () +{ + boost::shared_ptr send_proc = boost::dynamic_pointer_cast (_send); + _connections.drop_connections(); + _send_route->remove_processor (send_proc); + +} + + FoldbackStrip* FoldbackStrip::_entered_foldback_strip; PBD::Signal1 FoldbackStrip::CatchDeletion; @@ -81,16 +296,15 @@ FoldbackStrip::FoldbackStrip (Mixer_UI& mx, Session* sess, boost::shared_ptrset_tip (&_previous_button, _("Previous foldback bus"), ""); + _previous_button.set_sensitive (false); + _next_button.set_name ("mixer strip button"); + _next_button.set_icon (ArdourIcon::ScrollRight); + _next_button.set_tweaks (ArdourButton::Square); + UI::instance()->set_tip (&_next_button, _("Next foldback bus"), ""); + _next_button.set_sensitive (false); - output_button.set_text (_("Output")); - output_button.set_name ("mixer strip button"); -// send_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); -// send_scroller.add (send_display); + _hide_button.set_name ("mixer strip button"); + _hide_button.set_icon (ArdourIcon::HideEye); + _hide_button.set_tweaks (ArdourButton::Square); + set_tooltip (&_hide_button, _("Hide Foldback strip")); - send_display.set_flags (CAN_FOCUS); - send_display.set_name ("ProcessorList"); - send_display.set_data ("sendbox", this); - send_display.set_size_request (48, -1); - send_display.set_spacing (0); + prev_next_box.pack_start (_previous_button, false, true); + prev_next_box.pack_start (_next_button, false, true); + prev_next_box.pack_end (_hide_button, false, true); - insert_box = new ProcessorBox (0, boost::bind (&FoldbackStrip::plugin_selector, this), _pr_selection, 0); - insert_box->set_no_show_all (); - insert_box->show (); + name_button.set_name ("mixer strip button"); + name_button.set_text_ellipsize (Pango::ELLIPSIZE_END); + name_button.set_layout_ellipsize_width (PX_SCALE(_width) * PANGO_SCALE); -// send_scroller.show (); - send_display.show (); + // invertbuttons and box in route_ui - // TODO implement ArdourKnob::on_size_request properly - fb_level_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent); + _show_sends_button.set_name ("send alert button"); + _show_sends_button.set_text (_("Show Sends")); + UI::instance()->set_tip (&_show_sends_button, _("make mixer strips show sends to this bus"), ""); -#define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale())) - fb_level_control->set_size_request (PX_SCALE(65), PX_SCALE(65)); -#undef PX_SCALE - fb_level_control->set_tooltip_prefix (_("Level: ")); - fb_level_control->set_name ("monitor section knob"); - fb_level_control->set_no_show_all (true); + send_display.set_flags (CAN_FOCUS); + send_display.set_spacing (4); + + send_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + send_scroller.add (send_display); + send_scroller.get_child()->set_name ("FoldbackBusStripBase"); - bottom_button_table.attach (*fb_level_control, 0, 1, 0, 1,FILL,FILL,20,20); //EXPAND + // panners from route_ui + panners.set_width (Wide); + insert_box = new ProcessorBox (0, boost::bind (&FoldbackStrip::plugin_selector, this), _pr_selection, 0); + insert_box->set_no_show_all (); + insert_box->show (); + insert_box->set_session (_session); + insert_box->set_width (Wide); + insert_box->set_size_request (PX_SCALE(_width + 34), PX_SCALE(100)); mute_solo_table.set_homogeneous (true); mute_solo_table.set_spacings (2); + solo_button->set_text (_("Listen")); + mute_solo_table.attach (*solo_button, 0, 2, 0, 1); + mute_solo_table.set_size_request (PX_SCALE(_width + 34), PX_SCALE(20)); - show_sends_button->set_text (_("Show Sends")); - - show_sends_box.pack_start (*show_sends_button, true, true); - show_sends_button->show(); - - bottom_button_table.set_spacings (20); - bottom_button_table.set_row_spacings (20); - bottom_button_table.set_homogeneous (true); + fb_level_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent); + fb_level_control->set_size_request (PX_SCALE(50), PX_SCALE(50)); + fb_level_control->set_tooltip_prefix (_("Level: ")); + fb_level_control->set_name ("foldback knob"); + fb_level_control->set_no_show_all (true); - name_button.set_name ("monitor section button"); - name_button.set_text_ellipsize (Pango::ELLIPSIZE_END); + VBox* level_box = manage (new VBox); + level_box->pack_start (*fb_level_control, true, false); + master_box.pack_start (*level_box, true, false); + master_box.set_size_request (PX_SCALE(_width + 34), PX_SCALE(80)); + master_box.set_name ("FoldbackBusStripBase"); + level_box->show (); - _select_button.set_name ("monitor section button"); - _select_button.set_text (_("Select Foldback Bus")); + output_button.set_text (_("Output")); + output_button.set_name ("mixer strip button"); + output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE); + output_button.set_layout_ellipsize_width (PX_SCALE(_width) * PANGO_SCALE); _comment_button.set_name (X_("mixer strip button")); _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END); - _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor)); + _comment_button.set_layout_ellipsize_width (PX_SCALE(_width) * PANGO_SCALE); global_vpacker.set_border_width (1); - - global_vpacker.set_spacing (4); - global_vpacker.pack_start (_select_button, Gtk::PACK_SHRINK); + global_vpacker.set_spacing (2); + + // Packing is from top down to the send box. Thje send box + // needs the most room and takes all left over space + // Everything below the send box is packed from the bottom up + // the panner is the last thing to pack as it doesn't always show + // and packing it below the sendbox means nothing moves when it shows + // or hides. + global_vpacker.pack_start (prev_next_box, Gtk::PACK_SHRINK); global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK); global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK); - global_vpacker.pack_start (show_sends_box, Gtk::PACK_SHRINK); - + global_vpacker.pack_start (_show_sends_button, Gtk::PACK_SHRINK); + global_vpacker.pack_start (send_scroller, true, true); #ifndef MIXBUS //add a spacer underneath the foldback bus; //this fills the area that is taken up by the scrollbar on the tracks; @@ -190,11 +426,10 @@ FoldbackStrip::init () #endif global_vpacker.pack_end (_comment_button, Gtk::PACK_SHRINK); global_vpacker.pack_end (output_button, Gtk::PACK_SHRINK); + global_vpacker.pack_end (master_box, Gtk::PACK_SHRINK); global_vpacker.pack_end (mute_solo_table, Gtk::PACK_SHRINK); - global_vpacker.pack_end (panners, Gtk::PACK_SHRINK); - global_vpacker.pack_end (bottom_button_table, Gtk::PACK_SHRINK); -// global_vpacker.pack_end (*insert_box, true, true); global_vpacker.pack_end (*insert_box, Gtk::PACK_SHRINK); + global_vpacker.pack_end (panners, Gtk::PACK_SHRINK); global_frame.add (global_vpacker); global_frame.set_shadow_type (Gtk::SHADOW_IN); @@ -206,30 +441,22 @@ FoldbackStrip::init () _selected = true; set_selected (false); - _packed = false; _embedded = false; _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&FoldbackStrip::engine_stopped, this), gui_context()); _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&FoldbackStrip::engine_running, this), gui_context()); - output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE); - output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &FoldbackStrip::output_press), false); output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &FoldbackStrip::output_release), false); - name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &FoldbackStrip::name_button_button_press), false); - _select_button.signal_button_press_event().connect (sigc::mem_fun (*this, &FoldbackStrip::select_button_button_press), false); - - _width = Wide; - - - /* start off as a passthru strip. we'll correct this, if necessary, - in update_diskstream_display(). - */ - - + _previous_button.signal_clicked.connect (sigc::mem_fun (*this, &FoldbackStrip::previous_button_clicked)); + _next_button.signal_clicked.connect (sigc::mem_fun (*this, &FoldbackStrip::next_button_clicked)); + _hide_button.signal_clicked.connect (sigc::mem_fun(*this, &FoldbackStrip::hide_clicked)); + _show_sends_button.signal_clicked.connect (sigc::mem_fun(*this, &FoldbackStrip::show_sends_clicked)); + send_scroller.signal_button_press_event().connect (sigc::mem_fun (*this, &FoldbackStrip::send_button_press_event)); + _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor)); add_events (Gdk::BUTTON_RELEASE_MASK| Gdk::ENTER_NOTIFY_MASK| @@ -243,19 +470,6 @@ FoldbackStrip::init () *this, invalidator (*this), boost::bind (&FoldbackStrip::port_connected_or_disconnected, this, _1, _3), gui_context () ); - /* Add the widgets under visibility control to the VisibilityGroup; the names used here - must be the same as those used in RCOptionEditor so that the configuration changes - are recognised when they occur. - */ -/* _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false); - _visibility.add (&output_button, X_("Output"), _("Output"), false); - _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false); - - parameter_changed (X_("mixer-element-visibility")); - UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &FoldbackStrip::parameter_changed)); - Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&FoldbackStrip::parameter_changed, this, _1), gui_context()); - _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&FoldbackStrip::parameter_changed, this, _1), gui_context()); -*/ //watch for mouse enter/exit so we can do some stuff signal_enter_notify_event().connect (sigc::mem_fun(*this, &FoldbackStrip::mixer_strip_enter_event )); signal_leave_notify_event().connect (sigc::mem_fun(*this, &FoldbackStrip::mixer_strip_leave_event )); @@ -267,6 +481,9 @@ FoldbackStrip::~FoldbackStrip () CatchDeletion (this); delete fb_level_control; fb_level_control = 0; + _connections.drop_connections(); + clear_send_box (); + send_blink_connection.disconnect (); if (this ==_entered_foldback_strip) _entered_foldback_strip = NULL; @@ -317,159 +534,140 @@ FoldbackStrip::set_route (boost::shared_ptr rt) { /// FIX NO route if (!rt) { + clear_send_box (); RouteUI::self_delete (); return; } - if (show_sends_button->get_parent()) { - show_sends_box.remove (*show_sends_button); + if (_route) { + _route->solo_control()->set_value (0.0, Controllable::NoGroup); } RouteUI::set_route (rt); - /* ProcessorBox needs access to _route so that it can read - GUI object state. - */ -// processor_box.set_route (rt); - insert_box->set_route (rt); - + insert_box->set_route (_route); revert_to_default_display (); - - -// mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND); -// mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND); - - if (solo_button->get_parent()) { - mute_solo_table.remove (*solo_button); - } - - if (mute_button->get_parent()) { - mute_solo_table.remove (*mute_button); - } - - mute_solo_table.attach (*mute_button, 0, 1, 0, 1); - mute_solo_table.attach (*solo_button, 1, 2, 0, 1); - mute_button->show (); - solo_button->show (); - show_sends_box.show (); - - spacer.show(); - update_fb_level_control(); - show_sends_box.pack_start (*show_sends_button, true, true); - show_sends_button->show(); - - - delete route_ops_menu; - route_ops_menu = 0; - - delete route_select_menu; - route_select_menu = 0; - - _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&FoldbackStrip::update_output_display, this), gui_context()); - - _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&FoldbackStrip::io_changed_proxy, this), gui_context ()); + BusSendDisplayChanged (boost::shared_ptr ()); + _showing_sends = false; + _show_sends_button.set_active (false); + send_blink_connection.disconnect (); if (_route->panner_shell()) { update_panner_choices(); _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&FoldbackStrip::connect_to_pan, this), gui_context()); } - _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&FoldbackStrip::setup_comment_button, this), gui_context()); + _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&FoldbackStrip::update_output_display, this), gui_context()); + _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&FoldbackStrip::io_changed_proxy, this), gui_context ()); - set_stuff_from_route (); + _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&FoldbackStrip::setup_comment_button, this), gui_context()); /* now force an update of all the various elements */ + name_changed (); + update_send_box (); + _session->FBSendsChanged.connect (route_connections, invalidator (*this), boost::bind (&FoldbackStrip::update_send_box, this), gui_context()); update_mute_display (); update_solo_display (); - name_changed (); comment_changed (); - connect_to_pan (); panners.setup_pan (); panners.show_all (); - update_output_display (); add_events (Gdk::BUTTON_RELEASE_MASK); - + prev_next_changed (); + _previous_button.show(); + _next_button.show(); + _hide_button.show(); + prev_next_box.show (); + name_button.show(); + send_display.show (); + send_scroller.show (); + _show_sends_button.show(); insert_box->show (); - - Route::FedBy fed_by = _route->fed_by(); - for (Route::FedBy::iterator i = fed_by.begin(); i != fed_by.end(); ++i) { - if (i->sends_only) { - boost::shared_ptr s_rt (i->r.lock()); - boost::shared_ptr snd = s_rt->internal_send_for (_route); - //s_rt->DropReferences.connect (*this, MISSING_INVALIDATOR, boost::bind (&FoldbackStrip::fill_sendbox, this), this); - boost::shared_ptr processor (snd); - //boost::shared_ptr plugin_insert = boost::dynamic_pointer_cast (processor); -// Ok we have the info... now we need widgets to put it in... I suspect I need a class or three -// this doesn't work... and I need to clear it out and rebuild each time. - ArdourWidgets::ArdourButton _button; - _button.set_distinct_led_click (true); - _button.set_fallthrough_to_parent(true); - _button.set_led_left (true); -// _button.signal_led_clicked.connect (sigc::mem_fun (*this, &FoldbackStrip::led_clicked)); - _button.set_text (s_rt->name ()); - - //Gtk::VBox snd_entry = NULL; - Gtk::VBox snd_entry; - snd_entry.set_border_width (1); - snd_entry.set_spacing (4); - snd_entry.pack_start (_button, true, true); - send_display.pack_start (snd_entry, true, true); - _button.show (); - snd_entry.show (); - - - } - } - - - - global_frame.show(); - global_vpacker.show(); + solo_button->show (); mute_solo_table.show(); - bottom_button_table.show(); - show_sends_box.show_all(); - //send_scroller.show (); - send_display.show (); + master_box.show(); output_button.show(); - name_button.show(); - _select_button.show(); _comment_button.show(); + spacer.show(); + global_frame.show(); + global_vpacker.show(); map_frozen(); show (); + set_button_names (); } +// predicate for sort call in get_sorted_stripables +struct StripableByPresentationOrder +{ + bool operator () (const boost::shared_ptr & a, const boost::shared_ptr & b) const + { + return a->presentation_info().order() < b->presentation_info().order(); + } +}; + void -FoldbackStrip::set_stuff_from_route () +FoldbackStrip::update_send_box () { - /* if width is not set, it will be set by the MixerUI or editor */ + clear_send_box (); + if (!_route) { + return; + } + StripableList stripables; + stripables.clear (); - Width width; - if (get_gui_property ("strip-width", width)) { -// set_width_enum (width, this); + Route::FedBy fed_by = _route->fed_by(); + for (Route::FedBy::iterator i = fed_by.begin(); i != fed_by.end(); ++i) { + if (i->sends_only) { + boost::shared_ptr rt (i->r.lock()); + boost::shared_ptr s = boost::dynamic_pointer_cast (rt); + stripables.push_back (s); + } + } + stripables.sort (StripableByPresentationOrder()); + for (StripableList::iterator it = stripables.begin(); it != stripables.end(); ++it) { + + boost::shared_ptr s_sp = *it; + boost::shared_ptr s_rt = boost::dynamic_pointer_cast (s_sp); + boost::shared_ptr snd = s_rt->internal_send_for (_route); + if (snd) { + FoldbackSend * fb_s = new FoldbackSend (snd, s_rt, _route, _width); + send_display.pack_start (*fb_s, Gtk::PACK_SHRINK); + fb_s->show (); + s_rt->processors_changed.connect (_connections, invalidator (*this), boost::bind (&FoldbackStrip::processors_changed, this, _1), gui_context ()); + } } } void -FoldbackStrip::set_packed (bool yn) +FoldbackStrip::clear_send_box () { - _packed = yn; - set_gui_property ("visible", _packed); + std::vector< Widget* > snd_list = send_display.get_children (); + _connections.drop_connections (); + for (uint32_t i = 0; i < snd_list.size(); i++) { + send_display.remove (*(snd_list[i])); + delete snd_list[i]; + } + snd_list.clear(); } +void +FoldbackStrip::processors_changed (RouteProcessorChange) +{ + update_send_box (); +} -struct RouteCompareByName { - bool operator() (boost::shared_ptr a, boost::shared_ptr b) { - return a->name().compare (b->name()) < 0; - } -}; +void +FoldbackStrip::set_packed (bool yn) +{ + _packed = yn; +} gint FoldbackStrip::output_release (GdkEventButton *ev) @@ -512,21 +710,7 @@ FoldbackStrip::output_press (GdkEventButton *ev) boost::shared_ptr b = _session->bundles (); - /* guess the user-intended main type of the route output */ - DataType intended_type = guess_main_type(false); - - /* try adding the master bus first */ - boost::shared_ptr master = _session->master_out(); - if (master) { - maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type); - } - - /* then other routes inputs */ - RouteList copy = _session->get_routelist (); - copy.sort (RouteCompareByName ()); - for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) { - maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type); - } + DataType intended_type = DataType::AUDIO; /* then try adding user bundles, often labeled/grouped physical inputs */ for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) { @@ -547,19 +731,6 @@ FoldbackStrip::output_press (GdkEventButton *ev) citems.pop_back (); } - if (!ARDOUR::Profile->get_mixbus()) { - citems.push_back (SeparatorElem()); - - for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) { - citems.push_back ( - MenuElem ( - string_compose (_("Add %1 port"), (*i).to_i18n_string()), - sigc::bind (sigc::mem_fun (*this, &FoldbackStrip::add_output_port), *i) - ) - ); - } - } - citems.push_back (SeparatorElem()); citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast(this)), &RouteUI::edit_output_configuration))); @@ -596,19 +767,14 @@ FoldbackStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr b, ARD return; } - /* Don't add the monitor input unless we are Master */ + /* Don't add the monitor input */ boost::shared_ptr monitor = _session->monitor_out(); - if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle())) + if (monitor && b->has_same_ports (monitor->input()->bundle())) return; - /* It should either match exactly our outputs (if |type| is DataType::NIL) - * or have the same number of |type| channels than our outputs. */ - if (type == DataType::NIL) { - if(b->nchannels() != _route->n_outputs()) - return; - } else { - if (b->nchannels().n(type) != _route->n_outputs().n(type)) - return; + /* It should have the same number of |type| channels as our outputs. */ + if (b->nchannels().n(type) != _route->n_outputs().n(type)) { + return; } /* Avoid adding duplicates */ @@ -641,18 +807,6 @@ FoldbackStrip::connect_to_pan () boost::shared_ptr p = _route->pannable (); - //p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context()); - - /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself - * However, that only works a panner was previously set. - * - * PannerUI must remain subscribed to _panshell->Changed() in case - * we switch the panner eg. AUX-Send and back - * _route->panner_shell()->Changed() vs _panshell->Changed - */ - /*if (panners._panner == 0) { - panners.panshell_changed (); - }*/ update_panner_choices(); } @@ -671,53 +825,6 @@ FoldbackStrip::update_panner_choices () panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out)); } -DataType -FoldbackStrip::guess_main_type(bool for_input, bool favor_connected) const -{ - /* 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). */ - - boost::shared_ptr io = for_input ? _route->input() : _route->output(); - - /* Find most likely type among connected ports */ - if (favor_connected) { - 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 * @@ -768,7 +875,7 @@ FoldbackStrip::update_io_button () uint32_t typed_connection_count = 0; bool each_typed_port_has_one_connection = true; - DataType dt = guess_main_type(false); + DataType dt = DataType::AUDIO; boost::shared_ptr io = _route->output(); /* Fill in the tooltip. Also count: @@ -1004,13 +1111,6 @@ FoldbackStrip::setup_comment_button () } } -void -FoldbackStrip::show_passthru_color () -{ - //reset_strip_style (); -} - - void FoldbackStrip::help_count_plugins (boost::weak_ptr p) { @@ -1028,14 +1128,15 @@ FoldbackStrip::help_count_plugins (boost::weak_ptr p) ++_plugin_insert_cnt; } } -void + +Gtk::Menu* FoldbackStrip::build_route_ops_menu () { using namespace Menu_Helpers; - route_ops_menu = new Menu; - route_ops_menu->set_name ("ArdourContextMenu"); - MenuList& items = route_ops_menu->items(); + Menu* menu = manage (new Menu); + MenuList& items = menu->items (); + menu->set_name ("ArdourContextMenu"); items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor))); @@ -1061,16 +1162,18 @@ FoldbackStrip::build_route_ops_menu () items.push_back (SeparatorElem()); items.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &FoldbackStrip::remove_current_fb))); + return menu; } -void +Gtk::Menu* FoldbackStrip::build_route_select_menu () { using namespace Menu_Helpers; - route_select_menu = new Menu; - route_select_menu->set_name ("ArdourContextMenu"); - MenuList& items = route_select_menu->items(); + Menu* menu = manage (new Menu); + MenuList& items = menu->items (); + menu->set_name ("ArdourContextMenu"); + StripableList fb_list; _session->get_stripables (fb_list, PresentationInfo::FoldbackBus); for (StripableList::iterator s = fb_list.begin(); s != fb_list.end(); ++s) { @@ -1081,79 +1184,144 @@ FoldbackStrip::build_route_select_menu () } items.push_back (MenuElem (route->name (), sigc::bind (sigc::mem_fun (*this, &FoldbackStrip::set_route), route))); } - + return menu; } gboolean FoldbackStrip::name_button_button_press (GdkEventButton* ev) { - if (ev->button == 1 || ev->button == 3) { - list_route_operations (); + if (ev->button == 1) { + Menu* menu = build_route_select_menu (); - if (ev->button == 1) { - Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "", + Gtkmm2ext::anchored_menu_popup(menu, &name_button, "", 1, ev->time); - } else { - route_ops_menu->popup (3, ev->time); - } - + return true; + } else if (ev->button == 3) { + Menu* r_menu = build_route_ops_menu (); + r_menu->popup (3, ev->time); return true; } - return false; } -gboolean -FoldbackStrip::select_button_button_press (GdkEventButton* ev) +void +FoldbackStrip::previous_button_clicked () { - if (ev->button == 1 || ev->button == 3) { - list_fb_routes (); - - if (ev->button == 1) { - Gtkmm2ext::anchored_menu_popup(route_select_menu, &_select_button, "", - 1, ev->time); - } else { - route_select_menu->popup (3, ev->time); + bool past_current = false; + StripableList slist; + boost::shared_ptr previous = boost::shared_ptr (); + _session->get_stripables (slist, PresentationInfo::FoldbackBus); + if (slist.size () > 1) { + for (StripableList::iterator s = slist.begin(); s != slist.end(); ++s) { + if ((*s) == _route) { + past_current = true; + } + if (!past_current) { + previous = boost::dynamic_pointer_cast (*s); + } } + } else { + // only one route do nothing + return; + } + //use previous to set route + if (previous) { + set_route (previous); + } +} - return true; +void +FoldbackStrip::next_button_clicked () +{ + bool past_current = false; + StripableList slist; + boost::shared_ptr next = boost::shared_ptr (); + _session->get_stripables (slist, PresentationInfo::FoldbackBus); + if (slist.size () > 1) { + for (StripableList::iterator s = slist.begin(); s != slist.end(); ++s) { + if (past_current) { + next = boost::dynamic_pointer_cast (*s); + break; + } + if ((*s) == _route) { + past_current = true; + } + } + } else { + // only one route do nothing + return; + } + //use next to set route + if (next) { + set_route (next); } +} - return false; +void +FoldbackStrip::prev_next_changed () +{ + StripableList slist; + _session->get_stripables (slist, PresentationInfo::FoldbackBus); + if ((slist.size() < 2) || (boost::dynamic_pointer_cast (_route) == *(slist.begin()))) { + _previous_button.set_sensitive (false); + } else { + _previous_button.set_sensitive (true); + } + if ((slist.size () < 2) || boost::dynamic_pointer_cast (_route) == *(--slist.end())) { + _next_button.set_sensitive (false); + } else { + _next_button.set_sensitive (true); + } } void -FoldbackStrip::list_route_operations () +FoldbackStrip::hide_clicked() { - delete route_ops_menu; - build_route_ops_menu (); + _hide_button.set_sensitive(false); + ActionManager::get_toggle_action (X_("Mixer"), X_("ToggleFoldbackStrip"))->set_active (false); + _hide_button.set_sensitive(true); } void -FoldbackStrip::list_fb_routes () +FoldbackStrip::show_sends_clicked () { - delete route_select_menu; - build_route_select_menu (); + if (_showing_sends) { + BusSendDisplayChanged (boost::shared_ptr ()); /* EMIT SIGNAL */ + _showing_sends = false; + _show_sends_button.set_active (false); + send_blink_connection.disconnect (); + } else { + BusSendDisplayChanged (_route); /* EMIT SIGNAL */ + _showing_sends = true; + _show_sends_button.set_active (true); + send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &FoldbackStrip::send_blink)); + } } void -FoldbackStrip::set_selected (bool yn) +FoldbackStrip::send_blink (bool onoff) { - AxisView::set_selected (yn); + if (!(&_show_sends_button)) { + return; + } - if (selected()) { - global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT); - global_frame.set_name ("MixerStripSelectedFrame"); + if (onoff) { + _show_sends_button.set_active_state (Gtkmm2ext::ExplicitActive); } else { - global_frame.set_shadow_type (Gtk::SHADOW_IN); - global_frame.set_name ("MixerStripFrame"); + _show_sends_button.unset_active_state (); } +} + +void +FoldbackStrip::set_selected (bool yn) +{ + + global_frame.set_shadow_type (Gtk::SHADOW_IN); + global_frame.set_name ("MixerStripFrame"); global_frame.queue_draw (); -// if (!yn) -// processor_box.deselect_all_processors(); } void @@ -1167,32 +1335,11 @@ FoldbackStrip::route_property_changed (const PropertyChange& what_changed) void FoldbackStrip::name_changed () { - - name_button.set_text_ellipsize (Pango::ELLIPSIZE_END); name_button.set_text (_route->name()); set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name())); - -} -/* -void -FoldbackStrip::output_button_resized (Gtk::Allocation& alloc) -{ - //output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE); -} - -void -FoldbackStrip::name_button_resized (Gtk::Allocation& alloc) -{ - //name_button.set_layout_ellipsize_width (20); } -void -FoldbackStrip::comment_button_resized (Gtk::Allocation& alloc) -{ - //_comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE); -} -*/ void FoldbackStrip::set_embedded (bool yn) { @@ -1222,7 +1369,6 @@ FoldbackStrip::hide_processor_editor (boost::weak_ptr p) return; } -// Gtk::Window* w = processor_box.get_processor_ui (processor); Gtk::Window* w = insert_box->get_processor_ui (processor); if (w) { @@ -1234,7 +1380,7 @@ void FoldbackStrip::reset_strip_style () { if (_route->active()) { - set_name ("AudioBusStripBase"); + set_name ("FoldbackBusStripBase"); } else { set_name ("AudioBusStripBaseInactive"); } @@ -1263,7 +1409,6 @@ FoldbackStrip::drop_send () send_gone_connection.disconnect (); output_button.set_sensitive (true); set_invert_sensitive (true); - mute_button->set_sensitive (true); solo_button->set_sensitive (true); _comment_button.set_sensitive (true); fb_level_control->set_sensitive (true); @@ -1302,22 +1447,18 @@ void FoldbackStrip::set_button_names () { - mute_button->set_text (_("Mute")); - - if (_route && _route->solo_safe_control()->solo_safe()) { - solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive)); - } else { - solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive)); - } if (!Config->get_solo_control_is_listen_control()) { - solo_button->set_text (_("Solo")); + solo_button->hide (); } else { + solo_button->set_sensitive (true); + solo_button->show (); + UI::instance()->set_tip (solo_button, _("Listen on monitor"), ""); switch (Config->get_listen_position()) { case AfterFaderListen: - solo_button->set_text (_("AFL")); + solo_button->set_text (_("Listen")); break; case PreFaderListen: - solo_button->set_text (_("PFL")); + solo_button->set_text (_("Listen")); break; } } @@ -1329,18 +1470,6 @@ FoldbackStrip::plugin_selector() return _mixer.plugin_selector(); } -string -FoldbackStrip::state_id () const -{ - return string_compose ("strip %1", _route->id().to_s()); -} - -void -FoldbackStrip::add_output_port (DataType t) -{ - _route->output()->add_port ("", this, t); -} - void FoldbackStrip::route_active_changed () { @@ -1350,14 +1479,12 @@ FoldbackStrip::route_active_changed () void FoldbackStrip::copy_processors () { -// processor_box.processor_operation (ProcessorBox::ProcessorsCopy); insert_box->processor_operation (ProcessorBox::ProcessorsCopy); } void FoldbackStrip::cut_processors () { -// processor_box.processor_operation (ProcessorBox::ProcessorsCut); insert_box->processor_operation (ProcessorBox::ProcessorsCut); } @@ -1376,7 +1503,6 @@ FoldbackStrip::select_all_processors () void FoldbackStrip::deselect_all_processors () { -// processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone); insert_box->processor_operation (ProcessorBox::ProcessorsSelectNone); } @@ -1399,50 +1525,64 @@ FoldbackStrip::ab_plugins () } void -FoldbackStrip::build_sends_menu () +FoldbackStrip::create_selected_sends (bool include_buses) { - using namespace Menu_Helpers; + boost::shared_ptr slist (new StripableList); + PresentationInfo::Flag fl = PresentationInfo::AudioTrack; + if (include_buses) { + fl = PresentationInfo::MixerRoutes; + } + _session->get_stripables (*slist, fl); - sends_menu = new Menu; - sends_menu->set_name ("ArdourContextMenu"); - MenuList& items = sends_menu->items(); + for (StripableList::iterator i = (*slist).begin(); i != (*slist).end(); ++i) { + if ((*i)->is_selected() && !(*i)->is_master() && !(*i)->is_monitor()) { + boost::shared_ptr rt = boost::dynamic_pointer_cast(*i); + if (rt) { + rt->add_foldback_send (_route); + } + } + } - items.push_back ( - MenuElem(_("Assign all tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false)) - ); +} - items.push_back ( - MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true)) - ); +bool +FoldbackStrip::send_button_press_event (GdkEventButton *ev) +{ + if (ev->button == 3) { + Menu* menu = build_sends_menu (); + menu->popup (3, ev->time); + return true; + } + return false; +} + +Gtk::Menu* +FoldbackStrip::build_sends_menu () +{ + using namespace Menu_Helpers; + + Menu* menu = manage (new Menu); + MenuList& items = menu->items (); + menu->set_name ("ArdourContextMenu"); items.push_back ( - MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false)) + MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &FoldbackStrip::create_selected_sends), false)) ); items.push_back ( - MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true))); + MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &FoldbackStrip::create_selected_sends), true))); items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track))); items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero))); items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity))); + return menu; } -Gdk::Color -FoldbackStrip::color () const -{ - return route_color (); -} - -/*bool -FoldbackStrip::marked_for_display () const -{ - return !_route->presentation_info().hidden(); -}*/ - void FoldbackStrip::remove_current_fb () { + clear_send_box (); StripableList slist; boost::shared_ptr next = boost::shared_ptr (); boost::shared_ptr old_route = _route; @@ -1457,8 +1597,11 @@ FoldbackStrip::remove_current_fb () } if (next) { set_route (next); + _session->remove_route (old_route); + prev_next_changed (); + } else { + clear_send_box (); + RouteUI::self_delete (); + _session->remove_route (old_route); } - _session->remove_route (old_route); - - }