add back-pointer to TempoMap from points, and push dirty=true into map
[ardour.git] / gtk2_ardour / automation_time_axis.cc
index a0052032b008d76552281bad7aeba55478a30ff4..8e74774e79cc30d9cf699b7ac67608ad4675bd35 100644 (file)
 */
 
 #include <utility>
-#include <gtkmm2ext/barcontroller.h>
-#include <gtkmm2ext/utils.h>
+
 #include <boost/algorithm/string.hpp>
 
+#include <gtkmm/separator.h>
+
 #include "pbd/error.h"
 #include "pbd/memento_command.h"
 #include "pbd/stacktrace.h"
@@ -37,6 +38,8 @@
 #include "ardour/route.h"
 #include "ardour/session.h"
 
+#include "gtkmm2ext/utils.h"
+
 #include "canvas/debug.h"
 
 #include "widgets/tooltips.h"
@@ -135,6 +138,7 @@ AutomationTimeAxisView::AutomationTimeAxisView (
 
        auto_off_item = 0;
        auto_touch_item = 0;
+       auto_latch_item = 0;
        auto_write_item = 0;
        auto_play_item = 0;
        mode_discrete_item = 0;
@@ -158,14 +162,17 @@ AutomationTimeAxisView::AutomationTimeAxisView (
 
        using namespace Menu_Helpers;
 
-       auto_dropdown.AddMenuElem (MenuElem (S_("Automation|Manual"), sigc::bind (sigc::mem_fun(*this,
+       auto_dropdown.AddMenuElem (MenuElem (automation_state_off_string(), sigc::bind (sigc::mem_fun(*this,
                                                &AutomationTimeAxisView::set_automation_state), (AutoState) ARDOUR::Off)));
        auto_dropdown.AddMenuElem (MenuElem (_("Play"), sigc::bind (sigc::mem_fun(*this,
                                                &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
-       auto_dropdown.AddMenuElem (MenuElem (_("Write"), sigc::bind (sigc::mem_fun(*this,
-                                               &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
-       auto_dropdown.AddMenuElem (MenuElem (_("Touch"), sigc::bind (sigc::mem_fun(*this,
-                                               &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
+
+       if (!(_parameter.type() >= MidiCCAutomation &&
+             _parameter.type() <= MidiChannelPressureAutomation)) {
+               auto_dropdown.AddMenuElem (MenuElem (_("Write"), sigc::bind (sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
+               auto_dropdown.AddMenuElem (MenuElem (_("Touch"), sigc::bind (sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
+               auto_dropdown.AddMenuElem (MenuElem (_("Latch"), sigc::bind (sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Latch)));
+       }
 
        /* XXX translators: use a string here that will be at least as long
           as the longest automation label (see ::automation_state_changed()
@@ -310,13 +317,16 @@ AutomationTimeAxisView::AutomationTimeAxisView (
 
 AutomationTimeAxisView::~AutomationTimeAxisView ()
 {
-       cleanup_gui_properties ();
+       if (_stripable) {
+               cleanup_gui_properties ();
+       }
        delete _view;
 }
 
 void
 AutomationTimeAxisView::route_going_away ()
 {
+       cleanup_gui_properties ();
        _stripable.reset ();
 }
 
@@ -332,6 +342,7 @@ AutomationTimeAxisView::set_automation_state (AutoState state)
        }
        else if (_control) {
                _control->set_automation_state (state);
+               _session->set_dirty ();
        }
 
        if (_view) {
@@ -360,50 +371,76 @@ AutomationTimeAxisView::automation_state_changed ()
                state = ARDOUR::Off;
        }
 
-       switch (state & (ARDOUR::Off|Play|Touch|Write)) {
+       switch (state & (ARDOUR::Off|Play|Touch|Write|Latch)) {
        case ARDOUR::Off:
-               auto_dropdown.set_text (S_("Automation|Manual"));
+               auto_dropdown.set_text (automation_state_off_string());
+               ignore_state_request = true;
                if (auto_off_item) {
-                       ignore_state_request = true;
                        auto_off_item->set_active (true);
                        auto_play_item->set_active (false);
+               }
+               if (auto_touch_item) {
                        auto_touch_item->set_active (false);
+                       auto_latch_item->set_active (false);
                        auto_write_item->set_active (false);
-                       ignore_state_request = false;
                }
+               ignore_state_request = false;
                break;
        case Play:
                auto_dropdown.set_text (_("Play"));
-               if (auto_play_item) {
-                       ignore_state_request = true;
+               ignore_state_request = true;
+               if (auto_off_item) {
                        auto_play_item->set_active (true);
                        auto_off_item->set_active (false);
+               }
+               if (auto_touch_item) {
                        auto_touch_item->set_active (false);
+                       auto_latch_item->set_active (false);
                        auto_write_item->set_active (false);
-                       ignore_state_request = false;
                }
+               ignore_state_request = false;
                break;
        case Write:
                auto_dropdown.set_text (_("Write"));
-               if (auto_write_item) {
-                       ignore_state_request = true;
-                       auto_write_item->set_active (true);
+               ignore_state_request = true;
+               if (auto_off_item) {
                        auto_off_item->set_active (false);
                        auto_play_item->set_active (false);
+               }
+               if (auto_touch_item) {
+                       auto_write_item->set_active (true);
                        auto_touch_item->set_active (false);
-                       ignore_state_request = false;
+                       auto_latch_item->set_active (false);
                }
+               ignore_state_request = false;
                break;
        case Touch:
                auto_dropdown.set_text (_("Touch"));
+               ignore_state_request = true;
+               if (auto_off_item) {
+                       auto_off_item->set_active (false);
+                       auto_play_item->set_active (false);
+               }
                if (auto_touch_item) {
-                       ignore_state_request = true;
                        auto_touch_item->set_active (true);
+                       auto_write_item->set_active (false);
+                       auto_latch_item->set_active (false);
+               }
+               ignore_state_request = false;
+               break;
+       case Latch:
+               auto_dropdown.set_text (_("Latch"));
+               ignore_state_request = true;
+               if (auto_off_item) {
                        auto_off_item->set_active (false);
                        auto_play_item->set_active (false);
+               }
+               if (auto_touch_item) {
+                       auto_latch_item->set_active (true);
+                       auto_touch_item->set_active (false);
                        auto_write_item->set_active (false);
-                       ignore_state_request = false;
                }
+               ignore_state_request = false;
                break;
        default:
                auto_dropdown.set_text (_("???"));
@@ -473,7 +510,9 @@ AutomationTimeAxisView::clear_clicked ()
        } else if (_view) {
                _view->clear ();
        }
-       set_automation_state ((AutoState) ARDOUR::Off);
+       if (!EventTypeMap::instance().type_is_midi (_control->parameter().type())) {
+               set_automation_state ((AutoState) ARDOUR::Off);
+       }
        _editor.commit_reversible_command ();
        _session->set_dirty ();
 }
@@ -503,10 +542,7 @@ AutomationTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
                first_call_to_set_height = false;
 
                if (h >= preset_height (HeightNormal)) {
-                       if (!(_parameter.type() >= MidiCCAutomation &&
-                             _parameter.type() <= MidiChannelPressureAutomation)) {
-                               auto_dropdown.show();
-                       }
+                       auto_dropdown.show();
                        name_label.show();
                        hide_button.show();
 
@@ -544,13 +580,23 @@ AutomationTimeAxisView::hide_clicked ()
 {
        hide_button.set_sensitive(false);
        set_marked_for_display (false);
-       RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(parent);
-       if (rtv) {
-               rtv->request_redraw ();
+       StripableTimeAxisView* stv = dynamic_cast<StripableTimeAxisView*>(parent);
+       if (stv) {
+               stv->request_redraw ();
        }
        hide_button.set_sensitive(true);
 }
 
+string
+AutomationTimeAxisView::automation_state_off_string () const
+{
+       if (_parameter.type() >= MidiCCAutomation && _parameter.type() <= MidiChannelPressureAutomation) {
+               return S_("Automation|Off");
+       }
+
+       return S_("Automation|Manual");
+}
+
 void
 AutomationTimeAxisView::build_display_menu ()
 {
@@ -575,7 +621,7 @@ AutomationTimeAxisView::build_display_menu ()
        auto_state_menu->set_name ("ArdourContextMenu");
        MenuList& as_items = auto_state_menu->items();
 
-       as_items.push_back (CheckMenuElem (S_("Automation|Manual"), sigc::bind (
+       as_items.push_back (CheckMenuElem (automation_state_off_string(), sigc::bind (
                        sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
                        (AutoState) ARDOUR::Off)));
        auto_off_item = dynamic_cast<Gtk::CheckMenuItem*>(&as_items.back());
@@ -585,21 +631,26 @@ AutomationTimeAxisView::build_display_menu ()
                        (AutoState) Play)));
        auto_play_item = dynamic_cast<Gtk::CheckMenuItem*>(&as_items.back());
 
-       as_items.push_back (CheckMenuElem (_("Write"), sigc::bind (
-                       sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
-                       (AutoState) Write)));
-       auto_write_item = dynamic_cast<Gtk::CheckMenuItem*>(&as_items.back());
+       if (!(_parameter.type() >= MidiCCAutomation &&
+             _parameter.type() <= MidiChannelPressureAutomation)) {
+               as_items.push_back (CheckMenuElem (_("Write"), sigc::bind (
+                                                          sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
+                                                          (AutoState) Write)));
+               auto_write_item = dynamic_cast<Gtk::CheckMenuItem*>(&as_items.back());
 
-       as_items.push_back (CheckMenuElem (_("Touch"), sigc::bind (
-                       sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
+               as_items.push_back (CheckMenuElem (_("Touch"), sigc::bind (
+                                                          sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
                        (AutoState) Touch)));
-       auto_touch_item = dynamic_cast<Gtk::CheckMenuItem*>(&as_items.back());
+               auto_touch_item = dynamic_cast<Gtk::CheckMenuItem*>(&as_items.back());
 
-       if (!(_parameter.type() >= MidiCCAutomation &&
-             _parameter.type() <= MidiChannelPressureAutomation)) {
-               items.push_back (MenuElem (_("State"), *auto_state_menu));
+               as_items.push_back (CheckMenuElem (_("Latch"), sigc::bind (
+                                               sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
+                                               (AutoState) Latch)));
+               auto_latch_item = dynamic_cast<Gtk::CheckMenuItem*>(&as_items.back());
        }
 
+       items.push_back (MenuElem (_("State"), *auto_state_menu));
+
        /* mode menu */
 
        /* current interpolation state */
@@ -626,7 +677,7 @@ AutomationTimeAxisView::build_display_menu ()
                items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
 
        } else {
-#ifdef XXX_NEW_INTERPOLATON__BREAK_SESSION_FORMAT_XXX
+
                Menu* auto_mode_menu = manage (new Menu);
                auto_mode_menu->set_name ("ArdourContextMenu");
                MenuList& am_items = auto_mode_menu->items();
@@ -666,7 +717,6 @@ AutomationTimeAxisView::build_display_menu ()
                        delete auto_mode_menu;
                        auto_mode_menu = 0;
                }
-#endif
        }
 
        /* make sure the automation menu state is correct */
@@ -885,6 +935,19 @@ AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
        line->add_visibility (AutomationLine::Line);
 }
 
+bool
+AutomationTimeAxisView::propagate_time_selection () const
+{
+       /* MIDI automation is part of the MIDI region. It is always
+        * implicily selected with the parent, regardless of TAV selection
+        */
+       if (_parameter.type() >= MidiCCAutomation &&
+           _parameter.type() <= MidiChannelPressureAutomation) {
+               return true;
+       }
+       return false;
+}
+
 void
 AutomationTimeAxisView::entered()
 {
@@ -1134,4 +1197,3 @@ AutomationTimeAxisView::color () const
 {
        return gdk_color_from_rgb (_stripable->presentation_info().color());
 }
-