when moving tempo and metric sections around (or adding new ones), prevent the existe...
[ardour.git] / gtk2_ardour / automation_time_axis.cc
index e8b0d9b8ede180ddd225423100faaf9ef564c72a..e172f40fc98f4afa1b038dd527fcdbf4b9a0698f 100644 (file)
@@ -20,6 +20,8 @@
 #include <utility>
 #include <gtkmm2ext/barcontroller.h>
 #include <gtkmm2ext/utils.h>
+#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
 
 #include "pbd/memento_command.h"
 #include "pbd/stacktrace.h"
@@ -85,6 +87,7 @@ AutomationTimeAxisView::AutomationTimeAxisView (
        , _view (show_regions ? new AutomationStreamView (*this) : 0)
        , _name (nom)
        , auto_button (X_("")) /* force addition of a label */
+       , _show_regions (show_regions)
 {
        if (!have_name_font) {
                name_font = get_font_for_style (X_("AutomationTrackName"));
@@ -179,6 +182,8 @@ AutomationTimeAxisView::AutomationTimeAxisView (
        if (_controller) {
                /* add bar controller */
                controls_table.attach (*_controller.get(), 0, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
+               /* note that this handler connects *before* the default handler */
+               _controller->event_widget().signal_scroll_event().connect (mem_fun (*this, &AutomationTimeAxisView::controls_ebox_scroll), false);
        }
 
        controls_table.show_all ();
@@ -246,7 +251,7 @@ AutomationTimeAxisView::auto_clicked ()
                automation_menu->set_name ("ArdourContextMenu");
                MenuList& items (automation_menu->items());
 
-               items.push_back (MenuElem (_("Manual"), sigc::bind (sigc::mem_fun(*this,
+               items.push_back (MenuElem (S_("Automation|Manual"), sigc::bind (sigc::mem_fun(*this,
                                &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
                items.push_back (MenuElem (_("Play"), sigc::bind (sigc::mem_fun(*this,
                                &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
@@ -298,7 +303,7 @@ AutomationTimeAxisView::automation_state_changed ()
 
        switch (state & (Off|Play|Touch|Write)) {
        case Off:
-               auto_button.set_label (_("Manual"));
+               auto_button.set_label (S_("Automation|Manual"));
                if (auto_off_item) {
                        ignore_state_request = true;
                        auto_off_item->set_active (true);
@@ -498,7 +503,7 @@ AutomationTimeAxisView::build_display_menu ()
        auto_state_menu->set_name ("ArdourContextMenu");
        MenuList& as_items = auto_state_menu->items();
 
-       as_items.push_back (CheckMenuElem (_("Manual"), sigc::bind (
+       as_items.push_back (CheckMenuElem (S_("Automation|Manual"), sigc::bind (
                        sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
                        (AutoState) Off)));
        auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
@@ -555,7 +560,7 @@ AutomationTimeAxisView::build_display_menu ()
 }
 
 void
-AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/, framepos_t when, double y)
+AutomationTimeAxisView::add_automation_event (GdkEvent* event, framepos_t when, double y)
 {
        if (!_line) {
                return;
@@ -575,6 +580,8 @@ AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkE
 
        boost::shared_ptr<AutomationList> list = _line->the_list ();
 
+       _editor.snap_to_with_modifier (when, event);
+
        _session->begin_reversible_command (_("add automation event"));
        XMLNode& before = list->get_state();
 
@@ -942,9 +949,9 @@ AutomationTimeAxisView::set_state_2X (const XMLNode& node, int /*version*/)
                        if (yn) {
                                _canvas_display->show (); /* FIXME: necessary? show_at? */
                        }
-                       set_gui_property ("visible", (yn ? "yes" : "no"));
+                       set_gui_property ("visible", yn);
                } else {
-                       set_gui_property ("visible", "no");
+                       set_gui_property ("visible", false);
                }
        }
 
@@ -952,7 +959,7 @@ AutomationTimeAxisView::set_state_2X (const XMLNode& node, int /*version*/)
 }
 
 int
-AutomationTimeAxisView::set_state (const XMLNode& node, int /*version*/)
+AutomationTimeAxisView::set_state (const XMLNode&, int /*version*/)
 {
        return 0;
 }
@@ -1024,3 +1031,52 @@ AutomationTimeAxisView::state_id() const
                                       (int) _parameter.channel());
        }
 }
+
+/** Given a state id string, see if it is one generated by
+ *  this class.  If so, parse it into its components.
+ *  @param state_id State ID string to parse.
+ *  @param route_id Filled in with the route's ID if the state ID string is parsed.
+ *  @param has_parameter Filled in with true if the state ID has a parameter, otherwise false.
+ *  @param parameter Filled in with the state ID's parameter, if it has one.
+ *  @return true if this is a state ID generated by this class, otherwise false.
+ */
+
+bool
+AutomationTimeAxisView::parse_state_id (
+       string const & state_id,
+       PBD::ID & route_id,
+       bool & has_parameter,
+       Evoral::Parameter & parameter)
+{
+       stringstream s;
+       s << state_id;
+
+       string a, b, c;
+       s >> a >> b >> c;
+
+       if (a != X_("automation")) {
+               return false;
+       }
+
+       route_id = PBD::ID (b);
+
+       if (c.empty ()) {
+               has_parameter = false;
+               return true;
+       }
+
+       has_parameter = true;
+
+       vector<string> p;
+       boost::split (p, c, boost::is_any_of ("/"));
+
+       assert (p.size() == 3);
+
+       parameter = Evoral::Parameter (
+               boost::lexical_cast<int> (p[0]),
+               boost::lexical_cast<int> (p[2]),
+               boost::lexical_cast<int> (p[1])
+               );
+
+       return true;
+}