add method (taken from GTK GUI) to goto_nth_marker() to BasicUI
[ardour.git] / libs / surfaces / control_protocol / basic_ui.cc
index fc48b401755cb86a1b2edd7ab16c8afca90c00ff..dd18702d4c4d3110c479cb60f6a901fd63bca445 100644 (file)
 #include "ardour/session.h"
 #include "ardour/location.h"
 #include "ardour/tempo.h"
+#include "ardour/utils.h"
 
 #include "control_protocol/basic_ui.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace ARDOUR;
 
@@ -70,14 +71,39 @@ BasicUI::access_action ( std::string action_path )
 void
 BasicUI::loop_toggle ()
 {
+       if (!session) {
+               return;
+       }
+
+       Location * looploc = session->locations()->auto_loop_location();
+
+       if (!looploc) {
+               return;
+       }
+
        if (session->get_play_loop()) {
+
+               /* looping enabled, our job is to disable it */
+
                session->request_play_loop (false);
+
        } else {
-               session->request_play_loop (true);
-               if (!session->transport_rolling()) {
-                       session->request_transport_speed (1.0);
+
+               /* looping not enabled, our job is to enable it.
+
+                  loop-is-NOT-mode: this action always starts the transport rolling.
+                  loop-IS-mode:     this action simply sets the loop play mechanism, but
+                                       does not start transport.
+               */
+               if (Config->get_loop_is_mode()) {
+                       session->request_play_loop (true, false);
+               } else {
+                       session->request_play_loop (true, true);
                }
        }
+
+       //show the loop markers
+       looploc->set_hidden (false, this);
 }
 
 void
@@ -174,22 +200,56 @@ BasicUI::transport_stop ()
 void
 BasicUI::transport_play (bool from_last_start)
 {
-       bool rolling = session->transport_rolling ();
+       if (!session) {
+               return;
+       }
 
-       if (session->get_play_loop()) {
-               session->request_play_loop (false);
+       if (session->is_auditioning()) {
+               return;
        }
 
-       if (session->get_play_range ()) {
-               session->request_play_range (0);
+#if 0
+       if (session->config.get_external_sync()) {
+               switch (Config->get_sync_source()) {
+               case Engine:
+                       break;
+               default:
+                       /* transport controlled by the master */
+                       return;
+               }
        }
+#endif
+
+       bool rolling = session->transport_rolling();
 
-       if (from_last_start && rolling) {
-               session->request_locate (session->last_transport_start(), true);
+       if (session->get_play_loop()) {
+
+               /* If loop playback is not a mode, then we should cancel
+                  it when this action is requested. If it is a mode
+                  we just leave it in place.
+               */
 
+               if (!Config->get_loop_is_mode()) {
+                       /* XXX it is not possible to just leave seamless loop and keep
+                          playing at present (nov 4th 2009)
+                       */
+                       if (!Config->get_seamless_loop()) {
+                               /* stop loop playback and stop rolling */
+                               session->request_play_loop (false, true);
+                       } else if (rolling) {
+                               /* stop loop playback but keep rolling */
+                               session->request_play_loop (false, false);
+                       }
+               }
+
+       } else if (session->get_play_range () ) {
+               /* stop playing a range if we currently are */
+               session->request_play_range (0, true);
        }
 
-       session->request_transport_speed (1.0f);
+       if (!rolling) {
+               session->request_transport_speed (1.0f);
+       }
 }
 
 void
@@ -332,28 +392,27 @@ BasicUI::jump_by_seconds (double secs)
 {
        framepos_t current = session->transport_frame();
        double s = (double) current / (double) session->nominal_frame_rate();
-       
+
        s+= secs;
        if (s < 0) current = 0;
        s = s * session->nominal_frame_rate();
-       
+
        session->request_locate ( floor(s) );
 }
 
 void
 BasicUI::jump_by_bars (double bars)
 {
-       Timecode::BBT_Time bbt;
        TempoMap& tmap (session->tempo_map());
-       tmap.bbt_time (session->transport_frame(), bbt);
+       Timecode::BBT_Time bbt (tmap.bbt_at_frame (session->transport_frame()));
 
        bars += bbt.bars;
        if (bars < 0) bars = 0;
-       
+
        AnyTime any;
        any.type = AnyTime::BBT;
        any.bbt.bars = bars;
-       
+
        session->request_locate ( session->convert_to_frames (any) );
 }
 
@@ -437,6 +496,80 @@ BasicUI::sample_to_timecode (framepos_t sample, Timecode::Time& timecode, bool u
        session->sample_to_timecode (sample, *((Timecode::Time*)&timecode), use_offset, use_subframes);
 }
 
+void
+BasicUI::toggle_selection (PresentationInfo::order_t o, PresentationInfo::Flag flags)
+{
+       boost::shared_ptr<Stripable> s = session->get_remote_nth_stripable (o, flags);
+
+       if (s) {
+               s->presentation_info().set_selected (!s->presentation_info().selected());
+       }
+}
+
+void
+BasicUI::clear_stripable_selection ()
+{
+       session->clear_stripable_selection ();
+}
+
+void
+BasicUI::toggle_stripable_selection (boost::shared_ptr<Stripable> s)
+{
+       session->toggle_stripable_selection (s);
+}
+
+void
+BasicUI::add_stripable_selection (boost::shared_ptr<Stripable> s)
+{
+       session->add_stripable_selection (s);
+}
+
+void
+BasicUI::set_stripable_selection (boost::shared_ptr<Stripable> s)
+{
+       session->set_stripable_selection (s);
+}
+
+
+void
+BasicUI::cancel_all_solo ()
+{
+       if (session) {
+               session->cancel_all_solo ();
+       }
+}
+
+struct SortLocationsByPosition {
+    bool operator() (Location* a, Location* b) {
+           return a->start() < b->start();
+    }
+};
+
+void
+BasicUI::goto_nth_marker (int n)
+{
+       if (!session) {
+               return;
+       }
+
+       const Locations::LocationList& l (session->locations()->list());
+       Locations::LocationList ordered;
+       ordered = l;
+
+       SortLocationsByPosition cmp;
+       ordered.sort (cmp);
+
+       for (Locations::LocationList::iterator i = ordered.begin(); n >= 0 && i != ordered.end(); ++i) {
+               if ((*i)->is_mark() && !(*i)->is_hidden() && !(*i)->is_session_range()) {
+                       if (n == 0) {
+                               session->request_locate ((*i)->start(), session->transport_rolling());
+                               break;
+                       }
+                       --n;
+               }
+       }
+}
+
 #if 0
 this stuff is waiting to go in so that all UIs can offer complex solo/mute functionality