remove assert()s from LocaleGuard
[ardour.git] / gtk2_ardour / route_ui.cc
index b05877346f14b7b80961c88ab482b46a7f030391..29ccc647be533535a6ce886f16c551db588a31ae 100644 (file)
@@ -17,6 +17,8 @@
 
 */
 
+#include <boost/algorithm/string.hpp>
+
 #include <gtkmm2ext/gtk_ui.h>
 #include <gtkmm2ext/choice.h>
 #include <gtkmm2ext/doi.h>
@@ -54,6 +56,7 @@
 #include "ardour/filename_extensions.h"
 #include "ardour/midi_track.h"
 #include "ardour/internal_send.h"
+#include "ardour/profile.h"
 #include "ardour/send.h"
 #include "ardour/route.h"
 #include "ardour/session.h"
@@ -70,6 +73,7 @@ using namespace std;
 uint32_t RouteUI::_max_invert_buttons = 3;
 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
+std::string RouteUI::program_port_prefix;
 
 RouteUI::RouteUI (ARDOUR::Session* sess)
        : AxisView(sess)
@@ -83,6 +87,12 @@ RouteUI::RouteUI (ARDOUR::Session* sess)
        , output_selector (0)
        , _invert_menu(0)
 {
+       if (program_port_prefix.empty()) {
+               // compare to gtk2_ardour/port_group.cc
+               string lpn (PROGRAM_NAME);
+               boost::to_lower (lpn);
+               program_port_prefix = lpn + ":"; // e.g. "ardour:"
+       }
        if (sess) init ();
 }
 
@@ -249,7 +259,7 @@ RouteUI::set_route (boost::shared_ptr<Route> rp)
        _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
        _route->mute_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
 
-       _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this, _1), gui_context());
+       _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
 
        _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
        _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
@@ -272,7 +282,7 @@ RouteUI::set_route (boost::shared_ptr<Route> rp)
                t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
 
                rec_enable_button->show();
-               rec_enable_button->set_controllable (t->rec_enable_control());
+               rec_enable_button->set_controllable (t->rec_enable_control());
 
                 if (is_midi_track()) {
                         midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
@@ -395,7 +405,16 @@ RouteUI::mute_press (GdkEventButton* ev)
 
                        } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
 
-                               /* Primary-button1 applies change to the mix group even if it is not active
+                               /* Primary-button1 inverts the implication of
+                                  the group being active. If the group is
+                                  active (for mute), then this modifier means
+                                  "do not apply to mute". If the group is
+                                  inactive (for mute), then this modifier
+                                  means "apply to route". This is all
+                                  accomplished by passing just the actual
+                                  route, along with the InverseGroup group
+                                  control disposition.
+
                                   NOTE: Primary-button2 is MIDI learn.
                                */
 
@@ -403,20 +422,15 @@ RouteUI::mute_press (GdkEventButton* ev)
 
                                if (ev->button == 1) {
 
-                                       if (_route->route_group()) {
-
-                                               rl = _route->route_group()->route_list();
+                                       rl.reset (new RouteList);
+                                       rl->push_back (_route);
 
-                                               if (_mute_release) {
-                                                       _mute_release->routes = rl;
-                                               }
-                                       } else {
-                                               rl.reset (new RouteList);
-                                               rl->push_back (_route);
+                                       if (_mute_release) {
+                                               _mute_release->routes = rl;
                                        }
 
                                        DisplaySuspender ds;
-                                       _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, true);
+                                       _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, Controllable::InverseGroup);
                                }
 
                        } else {
@@ -444,7 +458,7 @@ RouteUI::mute_release (GdkEventButton* /*ev*/)
 {
        if (_mute_release){
                DisplaySuspender ds;
-               _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
+               _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, Controllable::UseGroup);
                delete _mute_release;
                _mute_release = 0;
        }
@@ -545,9 +559,9 @@ RouteUI::solo_press(GdkEventButton* ev)
 
                                DisplaySuspender ds;
                                if (Config->get_solo_control_is_listen_control()) {
-                                       _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(),  Session::rt_cleanup, true);
+                                       _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(),  Session::rt_cleanup, Controllable::UseGroup);
                                } else {
-                                       _session->set_solo (_session->get_routes(), !_route->self_soloed(),  Session::rt_cleanup, true);
+                                       _session->set_solo (_session->get_routes(), !_route->self_soloed(),  Session::rt_cleanup, Controllable::UseGroup);
                                }
 
                        } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
@@ -579,7 +593,7 @@ RouteUI::solo_press(GdkEventButton* ev)
 
                                // shift-click: toggle solo isolated status
 
-                               _route->set_solo_isolated (!_route->solo_isolated(), this);
+                               _route->set_solo_isolated (!_route->solo_isolated(), Controllable::UseGroup);
                                delete _solo_release;
                                _solo_release = 0;
 
@@ -597,26 +611,38 @@ RouteUI::solo_press(GdkEventButton* ev)
 
                                if (ev->button == 1) {
 
-                                       if (_route->route_group()) {
+                                       /* Primary-button1 inverts the implication of
+                                          the group being active. If the group is
+                                          active (for solo), then this modifier means
+                                          "do not apply to solo". If the group is
+                                          inactive (for mute), then this modifier
+                                          means "apply to route". This is all
+                                          accomplished by passing just the actual
+                                          route, along with the InverseGroup group
+                                          control disposition.
 
-                                               rl = _route->route_group()->route_list();
+                                          NOTE: Primary-button2 is MIDI learn.
+                                       */
 
-                                               if (_solo_release) {
-                                                       _solo_release->routes = rl;
-                                               }
-                                       } else {
-                                               rl.reset (new RouteList);
-                                               rl->push_back (_route);
+                                       rl.reset (new RouteList);
+                                       rl->push_back (_route);
+
+                                       if (_solo_release) {
+                                               _solo_release->routes = rl;
                                        }
 
                                        DisplaySuspender ds;
+
                                        if (Config->get_solo_control_is_listen_control()) {
-                                               _session->set_listen (rl, !_route->listening_via_monitor(),  Session::rt_cleanup, true);
+                                               _session->set_listen (rl, !_route->listening_via_monitor(),  Session::rt_cleanup, Controllable::InverseGroup);
                                        } else {
-                                               _session->set_solo (rl, !_route->self_soloed(),  Session::rt_cleanup, true);
+                                               _session->set_solo (rl, !_route->self_soloed(),  Session::rt_cleanup, Controllable::InverseGroup);
                                        }
                                }
 
+                               delete _solo_release;
+                               _solo_release = 0;
+
                        } else {
 
                                /* click: solo this route */
@@ -651,9 +677,9 @@ RouteUI::solo_release (GdkEventButton* /*ev*/)
                } else {
                        DisplaySuspender ds;
                        if (Config->get_solo_control_is_listen_control()) {
-                               _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
+                               _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
                        } else {
-                               _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
+                               _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
                        }
                }
 
@@ -713,17 +739,11 @@ RouteUI::rec_enable_press(GdkEventButton* ev)
 
                                boost::shared_ptr<RouteList> rl;
 
-                               if (_route->route_group()) {
-
-                                       rl = _route->route_group()->route_list();
-
-                               } else {
-                                       rl.reset (new RouteList);
-                                       rl->push_back (_route);
-                               }
+                               rl.reset (new RouteList);
+                               rl->push_back (_route);
 
                                DisplaySuspender ds;
-                               _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, true);
+                               _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, Controllable::InverseGroup);
                        }
 
                } else if (Keyboard::is_context_menu_event (ev)) {
@@ -853,7 +873,7 @@ RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
        }
 
        DisplaySuspender ds;
-       _session->set_monitoring (rl, mc, Session::rt_cleanup, true);
+       _session->set_monitoring (rl, mc, Session::rt_cleanup, Controllable::UseGroup);
 
        return false;
 }
@@ -1425,11 +1445,11 @@ RouteUI::solo_isolate_button_release (GdkEventButton* ev)
                        if (model) {
                                /* disable isolate for all routes */
                                DisplaySuspender ds;
-                               _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
+                               _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
                        } else {
                                /* enable isolate for all routes */
                                DisplaySuspender ds;
-                               _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, true);
+                               _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
                        }
 
                } else {
@@ -1441,7 +1461,7 @@ RouteUI::solo_isolate_button_release (GdkEventButton* ev)
                                boost::shared_ptr<RouteList> rl (new RouteList);
                                rl->push_back (_route);
                                DisplaySuspender ds;
-                               _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
+                               _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
                        }
                }
        }
@@ -1466,20 +1486,20 @@ RouteUI::solo_safe_button_release (GdkEventButton* ev)
                                /* disable solo safe for all routes */
                                DisplaySuspender ds;
                                for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-                                       (*i)->set_solo_safe (false, this);
+                                       (*i)->set_solo_safe (false, Controllable::NoGroup);
                                }
                        } else {
                                /* enable solo safe for all routes */
                                DisplaySuspender ds;
                                for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-                                       (*i)->set_solo_safe (true, this);
+                                       (*i)->set_solo_safe (true, Controllable::NoGroup);
                                }
                        }
                }
                else {
                        if (model == view) {
                                /* flip just this route */
-                               _route->set_solo_safe (!view, this);
+                               _route->set_solo_safe (!view, Controllable::NoGroup);
                        }
                }
        }
@@ -1496,14 +1516,14 @@ RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
         /* called AFTER the view has changed */
 
         if (model != view) {
-                _route->set_solo_isolated (view, this);
+               _route->set_solo_isolated (view, Controllable::UseGroup);
         }
 }
 
 void
 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
 {
-       _route->set_solo_safe (check->get_active(), this);
+       _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
 }
 
 /** Ask the user to choose a colour, and then apply that color to my route
@@ -1690,17 +1710,13 @@ RouteUI::setup_comment_editor ()
 }
 
 void
-RouteUI::comment_changed (void *src)
+RouteUI::comment_changed ()
 {
-       ENSURE_GUI_THREAD (*this, &MixerStrip::comment_changed, src)
-
-       if (src != this) {
-               ignore_comment_edit = true;
-               if (comment_area) {
-                       comment_area->get_buffer()->set_text (_route->comment());
-               }
-               ignore_comment_edit = false;
+       ignore_comment_edit = true;
+       if (comment_area) {
+               comment_area->get_buffer()->set_text (_route->comment());
        }
+       ignore_comment_edit = false;
 }
 
 void
@@ -1726,6 +1742,12 @@ RouteUI::set_route_active (bool a, bool apply_to_selection)
        }
 }
 
+void
+RouteUI::duplicate_selected_routes ()
+{
+       ARDOUR_UI::instance()->start_duplicate_routes();
+}
+
 void
 RouteUI::toggle_denormal_protection ()
 {
@@ -1814,7 +1836,7 @@ RouteUI::map_frozen ()
 {
        ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
 
-       AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
+       AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
 
        if (at) {
                switch (at->freeze_state()) {
@@ -1834,41 +1856,64 @@ RouteUI::adjust_latency ()
        LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
 }
 
-void
-RouteUI::save_as_template ()
+bool
+RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
 {
        std::string path;
        std::string safe_name;
-       string name;
+       std::string name;
 
-       path = ARDOUR::user_route_template_directory ();
+       prompter.get_result (name, true);
 
-       if (g_mkdir_with_parents (path.c_str(), 0755)) {
-               error << string_compose (_("Cannot create route template directory %1"), path) << endmsg;
-               return;
+       safe_name = legalize_for_path (name);
+       safe_name += template_suffix;
+
+       path = Glib::build_filename (dir, safe_name);
+
+       if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
+               bool overwrite = overwrite_file_dialog (prompter,
+                                                       _("Confirm Template Overwrite"),
+                                                       _("A template already exists with that name. Do you want to overwrite it?"));
+
+               if (!overwrite) {
+                       return false;
+               }
        }
 
-       Prompter p (true); // modal
+       _route->save_as_template (path, name);
+
+       return true;
+}
+
+void
+RouteUI::save_as_template ()
+{
+       std::string dir;
+
+       dir = ARDOUR::user_route_template_directory ();
 
-       p.set_title (_("Save As Template"));
-       p.set_prompt (_("Template name:"));
-       p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
-       switch (p.run()) {
-       case RESPONSE_ACCEPT:
-               break;
-       default:
+       if (g_mkdir_with_parents (dir.c_str(), 0755)) {
+               error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
                return;
        }
 
-       p.hide ();
-       p.get_result (name, true);
+       ArdourPrompter prompter (true); // modal
 
-       safe_name = legalize_for_path (name);
-       safe_name += template_suffix;
+       prompter.set_title (_("Save As Template"));
+       prompter.set_prompt (_("Template name:"));
+       prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
 
-       path = Glib::build_filename (path, safe_name);
-
-       _route->save_as_template (path, name);
+       bool finished = false;
+       while (!finished) {
+               switch (prompter.run()) {
+               case RESPONSE_ACCEPT:
+                       finished = process_save_template_prompter (prompter, dir);
+                       break;
+               default:
+                       finished = true;
+                       break;
+               }
+       }
 }
 
 void
@@ -1908,25 +1953,25 @@ RouteUI::parameter_changed (string const & p)
 void
 RouteUI::step_gain_up ()
 {
-       _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
+       _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
 }
 
 void
 RouteUI::page_gain_up ()
 {
-       _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
+       _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
 }
 
 void
 RouteUI::step_gain_down ()
 {
-       _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
+       _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
 }
 
 void
 RouteUI::page_gain_down ()
 {
-       _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
+       _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
 }
 
 void
@@ -1958,7 +2003,7 @@ RouteUI::open_remote_control_id_dialog ()
                if (_route->is_master() || _route->is_monitor()) {
                        l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
                                                         "The remote control ID of %3 cannot be changed."),
-                                                      Glib::Markup::escape_text (_route->name()),
+                                                      Gtkmm2ext::markup_escape_text (_route->name()),
                                                       _route->remote_control_id(),
                                                       (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
                } else {
@@ -1969,7 +2014,7 @@ RouteUI::open_remote_control_id_dialog ()
                                                       _route->remote_control_id(),
                                                       "<span size=\"small\" style=\"italic\">",
                                                       "</span>",
-                                                      Glib::Markup::escape_text (_route->name()),
+                                                      Gtkmm2ext::markup_escape_text (_route->name()),
                                                       PROGRAM_NAME));
                }
                dialog.get_vbox()->pack_start (*l);