Use lwrcase_dirname for desktop file names and substitutions.
[ardour.git] / gtk2_ardour / automation_controller.cc
index 55670b280a011da4705f52504b64b50d11f222e6..dd2d71d9cd4d5c43f96650a3aa3ff4230dbf18c7 100644 (file)
 #include "ardour/session.h"
 #include "ardour/tempo.h"
 
-#include "ardour_ui.h"
+#include "ardour_button.h"
 #include "automation_controller.h"
 #include "gui_thread.h"
 #include "note_select_dialog.h"
+#include "timers.h"
 
 #include "i18n.h"
 
 using namespace ARDOUR;
 using namespace Gtk;
 
+AutomationBarController::AutomationBarController (
+               boost::shared_ptr<Automatable>       printer,
+               boost::shared_ptr<AutomationControl> ac,
+               Adjustment*                          adj)
+       : Gtkmm2ext::BarController(*adj, ac)
+       , _printer(printer)
+       , _controllable(ac)
+{
+}
+
+std::string
+AutomationBarController::get_label (double& xpos)
+{
+        xpos = 0.5;
+        return _printer->value_as_string (_controllable);
+}
+
+AutomationBarController::~AutomationBarController()
+{
+}
+
 AutomationController::AutomationController(boost::shared_ptr<Automatable>       printer,
                                            boost::shared_ptr<AutomationControl> ac,
                                            Adjustment*                          adj)
-       : BarController (*adj, ac)
-       , _ignore_change(false)
+       : _widget(NULL)
        , _printer (printer)
        , _controllable(ac)
        , _adjustment(adj)
+       , _ignore_change(false)
 {
        assert (_printer);
 
-       set_name (X_("ProcessorControlSlider"));
-
-       StartGesture.connect (sigc::mem_fun(*this, &AutomationController::start_touch));
-       StopGesture.connect (sigc::mem_fun(*this, &AutomationController::end_touch));
+       if (ac->toggled()) {
+               ArdourButton* but = manage(new ArdourButton());
 
-       signal_button_release_event().connect(
-               sigc::mem_fun(*this, &AutomationController::on_button_release));
+               // Apply styles for special types
+               if (ac->parameter().type() == MuteAutomation) {
+                       but->set_name("mute button");
+               } else if (ac->parameter().type() == SoloAutomation) {
+                       but->set_name("solo button");
+               } else {
+                       but->set_name("generic button");
+               }
+               but->set_controllable(ac);
+               but->signal_clicked.connect(
+                       sigc::mem_fun(*this, &AutomationController::toggled));
+               _widget = but;
+       } else {
+               AutomationBarController* bar = manage(new AutomationBarController(_printer, ac, adj));
+
+               bar->set_name(X_("ProcessorControlSlider"));
+               bar->StartGesture.connect(
+                       sigc::mem_fun(*this, &AutomationController::start_touch));
+               bar->StopGesture.connect(
+                       sigc::mem_fun(*this, &AutomationController::end_touch));
+               bar->signal_button_release_event().connect(
+                       sigc::mem_fun(*this, &AutomationController::on_button_release));
+
+               _widget = bar;
+       }
 
-       _adjustment->signal_value_changed().connect (
-                       sigc::mem_fun(*this, &AutomationController::value_adjusted));
+       _adjustment->signal_value_changed().connect(
+               sigc::mem_fun(*this, &AutomationController::value_adjusted));
 
-       _screen_update_connection = ARDOUR_UI::RapidScreenUpdate.connect (
+       _screen_update_connection = Timers::rapid_connect (
                        sigc::mem_fun (*this, &AutomationController::display_effective_value));
 
        ac->Changed.connect (_changed_connection, invalidator (*this), boost::bind (&AutomationController::value_changed, this), gui_context());
+
+       add(*_widget);
+       show_all();
 }
 
 AutomationController::~AutomationController()
@@ -80,16 +126,8 @@ AutomationController::create(boost::shared_ptr<Automatable>       printer,
        const double lo        = ac->internal_to_interface(desc.lower);
        const double up        = ac->internal_to_interface(desc.upper);
        const double normal    = ac->internal_to_interface(desc.normal);
-       double       smallstep = desc.smallstep;
-       double       largestep = desc.largestep;
-       if (smallstep == 0.0) {
-               smallstep = (up - lo) / 100;
-       }
-       if (largestep == 0.0) {
-               largestep = (up - lo) / 10;
-       }
-       smallstep = ac->internal_to_interface(smallstep);
-       largestep = ac->internal_to_interface(largestep);
+       const double smallstep = ac->internal_to_interface(desc.lower + desc.smallstep);
+       const double largestep = ac->internal_to_interface(desc.lower + desc.largestep);
 
        Gtk::Adjustment* adjustment = manage (
                new Gtk::Adjustment (normal, lo, up, smallstep, largestep));
@@ -99,13 +137,6 @@ AutomationController::create(boost::shared_ptr<Automatable>       printer,
        return boost::shared_ptr<AutomationController>(new AutomationController(printer, ac, adjustment));
 }
 
-std::string
-AutomationController::get_label (double& xpos)
-{
-        xpos = 0.5;
-        return _printer->value_as_string (_controllable);
-}
-
 void
 AutomationController::display_effective_value()
 {
@@ -124,18 +155,28 @@ AutomationController::value_adjusted ()
        if (!_ignore_change) {
                _controllable->set_value (_controllable->interface_to_internal(_adjustment->get_value()));
        }
+
+       /* A bar controller will automatically follow the adjustment, but for a
+          button we have to do it manually. */
+       ArdourButton* but = dynamic_cast<ArdourButton*>(_widget);
+       if (but) {
+               const bool active = _adjustment->get_value() >= 0.5;
+               if (but->get_active() != active) {
+                       but->set_active(active);
+               }
+       }
 }
 
 void
 AutomationController::start_touch()
 {
        _controllable->start_touch (_controllable->session().transport_frame());
+       StartGesture.emit();  /* EMIT SIGNAL */
 }
 
 void
 AutomationController::end_touch ()
 {
-       if (!_controllable->alist()) return;
        if (_controllable->automation_state() == Touch) {
 
                bool mark = false;
@@ -148,6 +189,36 @@ AutomationController::end_touch ()
 
                _controllable->stop_touch (mark, when);
        }
+       StopGesture.emit();  /* EMIT SIGNAL */
+}
+
+void
+AutomationController::toggled ()
+{
+       ArdourButton* but = dynamic_cast<ArdourButton*>(_widget);
+       const AutoState as = _controllable->automation_state ();
+       const double where = _controllable->session ().audible_frame ();
+       const bool to_list = _controllable->list () && _controllable->session().transport_rolling () && (as == Touch || as == Write);
+
+       if (but) {
+               if (to_list) {
+                       if (as == Touch && _controllable->list ()->in_new_write_pass ()) {
+                               _controllable->alist ()->start_write_pass (where);
+                       }
+                       _controllable->list ()->set_in_write_pass (true, false, where);
+               }
+               /* set to opposite value.*/
+               _controllable->set_double (but->get_active () ? 0.0 : 1.0, where, to_list);
+
+               const bool active = _controllable->get_double (to_list, where) >= 0.5;
+               if (active && !but->get_active ()) {
+                       _adjustment->set_value (1.0);
+                       but->set_active (true);
+               } else if (!active && but->get_active ()) {
+                       _adjustment->set_value (0.0);
+                       but->set_active (false);
+               }
+       }
 }
 
 static double
@@ -236,10 +307,10 @@ AutomationController::on_button_release(GdkEventButton* ev)
                                                 sigc::mem_fun(*this, &AutomationController::run_note_select_dialog)));
                }
                if (is_low) {
-                       for (double beats = 1.0; beats <= 16; ++beats) {
-                               items.push_back(MenuElem(string_compose(_("Set to %1 beat(s)"), (int)beats),
+                       for (int beats = 1; beats <= 16; ++beats) {
+                               items.push_back(MenuElem (string_compose(P_("Set to %1 beat", "Set to %1 beats", beats), beats),
                                                         sigc::bind(sigc::mem_fun(*this, &AutomationController::set_freq_beats),
-                                                                   beats)));
+                                                                   (double)beats)));
                        }
                }
                menu->popup(1, ev->time);
@@ -261,3 +332,14 @@ AutomationController::stop_updating ()
 {
        _screen_update_connection.disconnect ();
 }
+
+void
+AutomationController::disable_vertical_scroll ()
+{
+       AutomationBarController* bar = dynamic_cast<AutomationBarController*>(_widget);
+       if (bar) {
+               bar->set_tweaks (
+                       Gtkmm2ext::PixFader::Tweaks(bar->tweaks() |
+                                                   Gtkmm2ext::PixFader::NoVerticalScroll));
+       }
+}