scale peak-meter reset button
[ardour.git] / gtk2_ardour / route_time_axis.cc
index b44728856632a96a8898751ac62de8cfe9f8a570..c0dedb895bfbcd10b3fef558940b439ea6e47757 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,7 +65,9 @@
 #include "automation_time_axis.h"
 #include "enums.h"
 #include "gui_thread.h"
+#include "item_counts.h"
 #include "keyboard.h"
+#include "paste_context.h"
 #include "playlist_selector.h"
 #include "point_selection.h"
 #include "prompter.h"
@@ -96,9 +100,9 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, ArdourCan
        , parent_canvas (canvas)
        , no_redraw (false)
        , button_table (3, 3)
-       , route_group_button (_("G"))
-       , playlist_button (_("P"))
-       , automation_button (_("A"))
+       , route_group_button (S_("RTAV|G"))
+       , playlist_button (S_("RTAV|P"))
+       , automation_button (S_("RTAV|A"))
        , automation_action_menu (0)
        , plugins_submenu_item (0)
        , route_group_menu (0)
@@ -107,6 +111,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));
@@ -149,9 +156,6 @@ RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
                set_gui_property ("visible", false);
        }
 
-       mute_changed (0);
-       update_solo_display ();
-
        timestretch_rect = 0;
        no_redraw = false;
 
@@ -316,8 +320,8 @@ RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
 
 RouteTimeAxisView::~RouteTimeAxisView ()
 {
-       CatchDeletion (this);
-
+       cleanup_gui_properties ();
+       
        for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
                delete *i;
        }
@@ -331,6 +335,7 @@ RouteTimeAxisView::~RouteTimeAxisView ()
        _automation_tracks.clear ();
 
        delete route_group_menu;
+       CatchDeletion (this);
 }
 
 void
@@ -505,6 +510,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
@@ -752,7 +789,7 @@ RouteTimeAxisView::build_display_menu ()
                        i->set_active (normal == 0 && tape == 0 && non_layered != 0);
                        i->set_inconsistent (non_layered != 0 && (normal != 0 || tape != 0));
 
-                       items.push_back (MenuElem (_("Mode"), *mode_menu));
+                       items.push_back (MenuElem (_("Record Mode"), *mode_menu));
                }
 
 
@@ -815,12 +852,8 @@ RouteTimeAxisView::build_display_menu ()
 
        items.push_back (SeparatorElem());
        items.push_back (MenuElem (_("Hide"), sigc::bind (sigc::mem_fun(_editor, &PublicEditor::hide_track_in_display), this, true)));
-       if (!Profile->get_sae()) {
-               items.push_back (MenuElem (_("Remove"), sigc::bind (sigc::mem_fun(*this, &RouteUI::remove_this_route), true)));
-       } else {
-               items.push_front (SeparatorElem());
-               items.push_front (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun(*this, &RouteUI::remove_this_route), true)));
-       }
+       items.push_front (SeparatorElem());
+       items.push_front (MenuElem (_("Remove"), sigc::mem_fun(_editor, &PublicEditor::remove_tracks)));
 }
 
 void
@@ -878,8 +911,8 @@ RouteTimeAxisView::show_timestretch (framepos_t start, framepos_t end, int layer
 
        if (timestretch_rect == 0) {
                timestretch_rect = new ArdourCanvas::Rectangle (canvas_display ());
-               timestretch_rect->set_fill_color (ARDOUR_UI::config()->get_TimeStretchFill());
-               timestretch_rect->set_outline_color (ARDOUR_UI::config()->get_TimeStretchOutline());
+               timestretch_rect->set_fill_color (ArdourCanvas::HSV (ARDOUR_UI::config()->color ("time stretch fill")).mod (ARDOUR_UI::config()->modifier ("time stretch fill")).color());
+               timestretch_rect->set_outline_color (ARDOUR_UI::config()->color ("time stretch outline"));
        }
 
        timestretch_rect->show ();
@@ -923,7 +956,7 @@ RouteTimeAxisView::show_selection (TimeSelection& ts)
 }
 
 void
-RouteTimeAxisView::set_height (uint32_t h)
+RouteTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
 {
        int gmlen = h - 9;
        bool height_changed = (height == 0) || (h != height);
@@ -934,7 +967,7 @@ RouteTimeAxisView::set_height (uint32_t h)
        }
        gm.get_level_meter().setup_meters (gmlen, meter_width);
 
-       TimeAxisView::set_height (h);
+       TimeAxisView::set_height (h, m);
 
        if (_view) {
                _view->set_height ((double) current_height());
@@ -1256,15 +1289,22 @@ RouteTimeAxisView::selection_click (GdkEventButton* ev)
        if (Keyboard::modifier_state_equals (ev->state, (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier))) {
 
                /* special case: select/deselect all tracks */
+
+               _editor.begin_reversible_selection_op (X_("Selection Click"));
+
                if (_editor.get_selection().selected (this)) {
                        _editor.get_selection().clear_tracks ();
                } else {
                        _editor.select_all_tracks ();
                }
 
+               _editor.commit_reversible_selection_op ();
+
                return;
        }
 
+       _editor.begin_reversible_selection_op (X_("Selection Click"));
+
        switch (ArdourKeyboard::selection_type (ev->state)) {
        case Selection::Toggle:
                _editor.get_selection().toggle (this);
@@ -1282,6 +1322,8 @@ RouteTimeAxisView::selection_click (GdkEventButton* ev)
                _editor.get_selection().add (this);
                break;
        }
+
+       _editor.commit_reversible_selection_op ();
 }
 
 void
@@ -1304,7 +1346,7 @@ RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
  * @param results List to add things to.
  */
 void
-RouteTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results)
+RouteTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results, bool within)
 {
        double speed = 1.0;
 
@@ -1316,14 +1358,14 @@ RouteTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top
        framepos_t const end_adjusted   = session_frame_to_track_frame(end, speed);
 
        if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) {
-               _view->get_selectables (start_adjusted, end_adjusted, top, bot, results);
+               _view->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
        }
 
        /* pick up visible automation tracks */
 
        for (Children::iterator i = children.begin(); i != children.end(); ++i) {
                if (!(*i)->hidden()) {
-                       (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results);
+                       (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
                }
        }
 }
@@ -1534,20 +1576,20 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
 }
 
 bool
-RouteTimeAxisView::paste (framepos_t pos, unsigned paste_count, float times, Selection& selection, size_t nth)
+RouteTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx)
 {
        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, ctx.counts.n_playlists(type));
 
        if (p == selection.playlists.end()) {
                return false;
        }
+       ctx.counts.increase_n_playlists(type);
 
         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos));
 
@@ -1559,15 +1601,15 @@ RouteTimeAxisView::paste (framepos_t pos, unsigned paste_count, float times, Sel
        /* 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);
+       pos += _editor.get_paste_offset(pos, ctx.count, duration);
 
        pl->clear_changes ();
        if (Config->get_edit_mode() == Ripple) {
                std::pair<framepos_t, framepos_t> extent = (*p)->get_extent_with_endspace();
                framecnt_t amount = extent.second - extent.first;
-               pl->ripple(pos, amount * times, boost::shared_ptr<Region>());
+               pl->ripple(pos, amount * ctx.times, boost::shared_ptr<Region>());
        }
-       pl->paste (*p, pos, times);
+       pl->paste (*p, pos, ctx.times);
 
        vector<Command*> cmds;
        pl->rdiff (cmds);
@@ -1776,11 +1818,11 @@ RouteTimeAxisView::color_handler ()
 {
        //case cTimeStretchOutline:
        if (timestretch_rect) {
-               timestretch_rect->set_outline_color (ARDOUR_UI::config()->get_TimeStretchOutline());
+               timestretch_rect->set_outline_color (ARDOUR_UI::config()->color ("time stretch outline"));
        }
        //case cTimeStretchFill:
        if (timestretch_rect) {
-               timestretch_rect->set_fill_color (ARDOUR_UI::config()->get_TimeStretchFill());
+               timestretch_rect->set_fill_color (ARDOUR_UI::config()->color ("time stretch fill"));
        }
 
        reset_meter();
@@ -1838,6 +1880,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)
@@ -2383,7 +2529,7 @@ RouteTimeAxisView::show_meter ()
 void
 RouteTimeAxisView::reset_meter ()
 {
-       if (Config->get_show_track_meters()) {
+       if (ARDOUR_UI::config()->get_show_track_meters()) {
                int meter_width = 3;
                if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
                        meter_width = 6;
@@ -2548,19 +2694,19 @@ RouteTimeAxisView::set_button_names ()
        if (Config->get_solo_control_is_listen_control()) {
                switch (Config->get_listen_position()) {
                        case AfterFaderListen:
-                               solo_button->set_text (_("A"));
+                               solo_button->set_text (S_("AfterFader|A"));
                                ARDOUR_UI::instance()->set_tip (*solo_button, _("After-fade listen (AFL)"));
                                break;
                        case PreFaderListen:
-                               solo_button->set_text (_("P"));
+                               solo_button->set_text (S_("PreFader|P"));
                                ARDOUR_UI::instance()->set_tip (*solo_button, _("Pre-fade listen (PFL)"));
                        break;
                }
        } else {
-               solo_button->set_text (_("S"));
+               solo_button->set_text (S_("Solo|S"));
                ARDOUR_UI::instance()->set_tip (*solo_button, _("Solo"));
        }
-       mute_button->set_text (_("M"));
+       mute_button->set_text (S_("Mute|M"));
 }
 
 Gtk::CheckMenuItem*