Add test_search_path to find test files in MidnamTest
[ardour.git] / gtk2_ardour / route_time_axis.cc
index b68e814fba131e48d508f6f13b5eeca0e45f903f..d741b70501047e07dfe1ff700fee1eee360f5f20 100644 (file)
@@ -45,6 +45,8 @@
 #include "ardour/amp.h"
 #include "ardour/meter.h"
 #include "ardour/event_type_map.h"
+#include "ardour/pannable.h"
+#include "ardour/panner.h"
 #include "ardour/processor.h"
 #include "ardour/profile.h"
 #include "ardour/route_group.h"
@@ -63,6 +65,7 @@
 #include "automation_time_axis.h"
 #include "enums.h"
 #include "gui_thread.h"
+#include "item_counts.h"
 #include "keyboard.h"
 #include "playlist_selector.h"
 #include "point_selection.h"
@@ -107,6 +110,9 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, ArdourCan
        , color_mode_menu (0)
        , gm (sess, true, 75, 14)
        , _ignore_set_layer_display (false)
+       , gain_automation_item(NULL)
+       , mute_automation_item(NULL)
+       , pan_automation_item(NULL)
 {
        number_label.set_name("tracknumber label");
        number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
@@ -505,6 +511,38 @@ RouteTimeAxisView::build_automation_action_menu (bool for_selection)
                items.push_back (MenuElem (_("Processor automation"), subplugin_menu));
                items.back().set_sensitive (!for_selection || _editor.get_selection().tracks.size() == 1);;
        }
+
+       /* Add any route automation */
+
+       if (gain_track) {
+               items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &RouteTimeAxisView::update_gain_track_visibility)));
+               gain_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
+               gain_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) && 
+                                                 (gain_track && string_is_affirmative (gain_track->gui_property ("visible"))));
+
+               _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
+       }
+
+       if (mute_track) {
+               items.push_back (CheckMenuElem (_("Mute"), sigc::mem_fun (*this, &RouteTimeAxisView::update_mute_track_visibility)));
+               mute_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
+               mute_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) && 
+                                                 (mute_track && string_is_affirmative (mute_track->gui_property ("visible"))));
+
+               _main_automation_menu_map[Evoral::Parameter(MuteAutomation)] = mute_automation_item;
+       }
+
+       if (!pan_tracks.empty()) {
+               items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &RouteTimeAxisView::update_pan_track_visibility)));
+               pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
+               pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
+                                                (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible"))));
+
+               set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
+               for (set<Evoral::Parameter>::const_iterator p = params.begin(); p != params.end(); ++p) {
+                       _main_automation_menu_map[*p] = pan_automation_item;
+               }
+       }
 }
 
 void
@@ -1534,20 +1572,20 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
 }
 
 bool
-RouteTimeAxisView::paste (framepos_t pos, float times, Selection& selection, size_t nth)
+RouteTimeAxisView::paste (framepos_t pos, unsigned paste_count, float times, const Selection& selection, ItemCounts& counts)
 {
        if (!is_track()) {
                return false;
        }
 
-       boost::shared_ptr<Playlist> pl = playlist ();
-       PlaylistSelection::iterator p;
-
-       for (p = selection.playlists.begin(); p != selection.playlists.end() && nth; ++p, --nth) {}
+       boost::shared_ptr<Playlist>       pl   = playlist ();
+       const ARDOUR::DataType            type = pl->data_type();
+       PlaylistSelection::const_iterator p    = selection.playlists.get_nth(type, counts.n_playlists(type));
 
        if (p == selection.playlists.end()) {
                return false;
        }
+       counts.increase_n_playlists(type);
 
         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos));
 
@@ -1556,6 +1594,11 @@ RouteTimeAxisView::paste (framepos_t pos, float times, Selection& selection, siz
                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("modified paste to %1\n", pos));
        }
 
+       /* add multi-paste offset if applicable */
+       std::pair<framepos_t, framepos_t> extent   = (*p)->get_extent();
+       const framecnt_t                  duration = extent.second - extent.first;
+       pos += _editor.get_paste_offset(pos, paste_count, duration);
+
        pl->clear_changes ();
        if (Config->get_edit_mode() == Ripple) {
                std::pair<framepos_t, framepos_t> extent = (*p)->get_extent_with_endspace();
@@ -1833,6 +1876,110 @@ RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param)
        }
 }
 
+void
+RouteTimeAxisView::update_gain_track_visibility ()
+{
+       bool const showit = gain_automation_item->get_active();
+
+       if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) {
+               gain_track->set_marked_for_display (showit);
+
+               /* now trigger a redisplay */
+
+               if (!no_redraw) {
+                        _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
+               }
+       }
+}
+
+void
+RouteTimeAxisView::update_mute_track_visibility ()
+{
+       bool const showit = mute_automation_item->get_active();
+
+       if (showit != string_is_affirmative (mute_track->gui_property ("visible"))) {
+               mute_track->set_marked_for_display (showit);
+
+               /* now trigger a redisplay */
+
+               if (!no_redraw) {
+                        _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
+               }
+       }
+}
+
+void
+RouteTimeAxisView::update_pan_track_visibility ()
+{
+       bool const showit = pan_automation_item->get_active();
+       bool changed = false;
+
+       for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
+               if ((*i)->set_marked_for_display (showit)) {
+                       changed = true;
+               }
+       }
+
+       if (changed) {
+               _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
+       }
+}
+
+void
+RouteTimeAxisView::ensure_pan_views (bool show)
+{
+       bool changed = false;
+       for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
+               changed = true;
+               (*i)->set_marked_for_display (false);
+       }
+       if (changed) {
+               _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
+       }
+       pan_tracks.clear();
+
+       if (!_route->panner()) {
+               return;
+       }
+
+       set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
+       set<Evoral::Parameter>::iterator p;
+
+       for (p = params.begin(); p != params.end(); ++p) {
+               boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
+
+               if (pan_control->parameter().type() == NullAutomation) {
+                       error << "Pan control has NULL automation type!" << endmsg;
+                       continue;
+               }
+
+               if (automation_child (pan_control->parameter ()).get () == 0) {
+
+                       /* we don't already have an AutomationTimeAxisView for this parameter */
+
+                       std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
+
+                       boost::shared_ptr<AutomationTimeAxisView> t (
+                                       new AutomationTimeAxisView (_session,
+                                               _route,
+                                               _route->pannable(),
+                                               pan_control,
+                                               pan_control->parameter (),
+                                               _editor,
+                                               *this,
+                                               false,
+                                               parent_canvas,
+                                               name)
+                                       );
+
+                       pan_tracks.push_back (t);
+                       add_automation_child (*p, t, show);
+               } else {
+                       pan_tracks.push_back (automation_child (pan_control->parameter ()));
+               }
+       }
+}
+
 
 void
 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
@@ -2015,7 +2162,7 @@ RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor>
                      << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
                                          processor->name(), what.type(), (int) what.channel(), what.id() )
                      << endmsg;
-               /*NOTREACHED*/
+               abort(); /*NOTREACHED*/
                return;
        }
 
@@ -2103,7 +2250,7 @@ RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_
                request_redraw ();
        }
 
-       if (!EventTypeMap::instance().is_midi_parameter(param)) {
+       if (!ARDOUR::parameter_is_midi((AutomationType)param.type())) {
                /* MIDI-related parameters are always in the menu, there's no
                   reason to rebuild the menu just because we added a automation
                   lane for one of them. But if we add a non-MIDI automation
@@ -2481,7 +2628,7 @@ RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
        if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
                if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
                        fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
-                       /*NOTREACHED*/
+                       abort(); /*NOTREACHED*/
                }
 
                _underlay_streams.push_back(v);
@@ -2518,7 +2665,7 @@ RouteTimeAxisView::remove_underlay (StreamView* v)
 
                if (gm == other._underlay_mirrors.end()) {
                        fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
-                       /*NOTREACHED*/
+                       abort(); /*NOTREACHED*/
                }
 
                v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));