new_grid: Rewrite of Snap and Grid. (squashed commit)
[ardour.git] / gtk2_ardour / ardour_ui.cc
index 600480572befea9c72e737c35f682f108fcf1d68..37474b498fde13e37451109bbb7715db1277419d 100644 (file)
 #undef check
 #endif
 
-#include "timecode/time.h"
+#include "temporal/time.h"
 
 typedef uint64_t microseconds_t;
 
@@ -138,6 +138,7 @@ typedef uint64_t microseconds_t;
 #include "audio_clock.h"
 #include "audio_region_view.h"
 #include "big_clock_window.h"
+#include "big_transport_window.h"
 #include "bundle_manager.h"
 #include "duplicate_routes_dialog.h"
 #include "debug.h"
@@ -202,7 +203,7 @@ using namespace Editing;
 
 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
 
-sigc::signal<void, samplepos_t, bool, samplepos_t> ARDOUR_UI::Clock;
+sigc::signal<void, samplepos_t> ARDOUR_UI::Clock;
 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
 
 static bool
@@ -285,13 +286,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        , _initial_verbose_plugin_scan (false)
        , first_time_engine_run (true)
        , secondary_clock_spacer (0)
-       , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
-       , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
-       , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
-       , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
-       , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
-       , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
-       , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
        , auto_input_button (ArdourButton::led_default_elements)
        , time_info_box (0)
        , auto_return_button (ArdourButton::led_default_elements)
@@ -323,6 +317,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
        , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
        , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
+       , big_transport_window (X_("big-transport"), _("Transport Controls"), boost::bind (&ARDOUR_UI::create_big_transport_window, this))
        , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
        , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
        , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
@@ -380,22 +375,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
        UIConfiguration::instance().map_parameters (pc);
 
-       roll_button.set_controllable (roll_controllable);
-       stop_button.set_controllable (stop_controllable);
-       goto_start_button.set_controllable (goto_start_controllable);
-       goto_end_button.set_controllable (goto_end_controllable);
-       auto_loop_button.set_controllable (auto_loop_controllable);
-       play_selection_button.set_controllable (play_selection_controllable);
-       rec_button.set_controllable (rec_controllable);
-
-       roll_button.set_name ("transport button");
-       stop_button.set_name ("transport button");
-       goto_start_button.set_name ("transport button");
-       goto_end_button.set_name ("transport button");
-       auto_loop_button.set_name ("transport button");
-       play_selection_button.set_name ("transport button");
-       rec_button.set_name ("transport recenable button");
-       midi_panic_button.set_name ("transport button");
+       transport_ctrl.setup (this);
 
        ARDOUR::DiskWriter::Overrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
        ARDOUR::DiskReader::Underrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
@@ -486,6 +466,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
                bundle_manager.set_state (*ui_xml, 0);
                location_ui.set_state (*ui_xml, 0);
                big_clock_window.set_state (*ui_xml, 0);
+               big_transport_window.set_state (*ui_xml, 0);
                audio_port_matrix.set_state (*ui_xml, 0);
                midi_port_matrix.set_state (*ui_xml, 0);
                export_video_dialog.set_state (*ui_xml, 0);
@@ -508,6 +489,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        WM::Manager::instance().register_window (&bundle_manager);
        WM::Manager::instance().register_window (&location_ui);
        WM::Manager::instance().register_window (&big_clock_window);
+       WM::Manager::instance().register_window (&big_transport_window);
        WM::Manager::instance().register_window (&audio_port_matrix);
        WM::Manager::instance().register_window (&midi_port_matrix);
        WM::Manager::instance().register_window (&idleometer);
@@ -544,7 +526,7 @@ release software. So, a few guidelines:\n\
 2) Please wait for a helpful writeup of new features.\n\
 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
-   making sure to note the product version number as 5.0-pre.\n\
+   making sure to note the product version number as 6.0-pre.\n\
 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
    can get there directly from within the program via the Help->Chat menu option.\n\
@@ -680,6 +662,8 @@ ARDOUR_UI::post_engine ()
                throw failed_constructor ();
        }
 
+       transport_ctrl.map_actions ();
+
        /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
        XMLNode* n = Config->extra_xml (X_("UI"));
        if (n) {
@@ -1107,7 +1091,7 @@ ARDOUR_UI::starting ()
                         * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
                         */
                        const char *process_name = g_getenv ("ARDOUR_SELF");
-                       nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
+                       nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour6");
 
                        unsigned int i = 0;
                        // wait for announce reply from nsm server
@@ -1190,15 +1174,13 @@ ARDOUR_UI::starting ()
                        Searchpath ds (ARDOUR::ardour_data_search_path());
                        ds.add_subdirectory_to_paths ("sessions");
                        vector<string> demos;
-                       find_files_matching_pattern (demos, ds, "*.tar.xz");
+                       find_files_matching_pattern (demos, ds, ARDOUR::session_archive_suffix);
 
                        ARDOUR::RecentSessions rs;
                        ARDOUR::read_recent_sessions (rs);
 
                        for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
-                               /* "demo-session" must be inside "demo-session.tar.xz"
-                                * strip ".tar.xz"
-                                */
+                               /* "demo-session" must be inside "demo-session.<session_archive_suffix>" */
                                std::string name = basename_nosuffix (basename_nosuffix (*i));
                                std::string path = Glib::build_filename (dspd, name);
                                /* skip if session-dir already exists */
@@ -1549,8 +1531,7 @@ ARDOUR_UI::every_second ()
 void
 ARDOUR_UI::every_point_one_seconds ()
 {
-       // TODO get rid of this..
-       // ShuttleControl is updated directly via TransportStateChange signal
+       if (editor) editor->build_region_boundary_cache();
 }
 
 void
@@ -1705,6 +1686,7 @@ ARDOUR_UI::update_xrun_count ()
 
        if (_session) {
                const unsigned int x = _session->get_xrun_count ();
+               dsp_load_indicator.set_xrun_count (x);
                if (x > 9999) {
                        snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">&gt;10K</span>"), X_("red"));
                } else {
@@ -1712,6 +1694,7 @@ ARDOUR_UI::update_xrun_count ()
                }
        } else {
                snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
+               dsp_load_indicator.set_xrun_count (UINT_MAX);
        }
        xrun_label.set_markup (buf);
        set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
@@ -1727,6 +1710,7 @@ ARDOUR_UI::update_cpu_load ()
        */
 
        double const c = AudioEngine::instance()->get_dsp_load ();
+       dsp_load_indicator.set_dsp_load (c);
        snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
        cpu_load_label.set_markup (buf);
 }
@@ -1786,6 +1770,7 @@ void
 ARDOUR_UI::update_disk_space()
 {
        if (_session == 0) {
+               disk_space_indicator.set_available_disk_sec (-1);
                return;
        }
 
@@ -1795,14 +1780,17 @@ ARDOUR_UI::update_disk_space()
 
        if (fr == 0) {
                /* skip update - no SR available */
+               disk_space_indicator.set_available_disk_sec (-1);
                return;
        }
 
        if (!opt_samples) {
                /* Available space is unknown */
                snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
+               disk_space_indicator.set_available_disk_sec (-1);
        } else if (opt_samples.get_value_or (0) == max_samplecnt) {
                snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
+               disk_space_indicator.set_available_disk_sec (max_samplecnt);
        } else {
                rec_enabled_streams = 0;
                _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
@@ -1817,6 +1805,8 @@ ARDOUR_UI::update_disk_space()
                int mins;
                int secs;
 
+               disk_space_indicator.set_available_disk_sec (samples / (float)fr);
+
                hrs  = samples / (fr * 3600);
 
                if (hrs > 24) {
@@ -1971,7 +1961,7 @@ ARDOUR_UI::open_session ()
                string default_session_folder = Config->get_default_session_parent_dir();
                open_session_selector.add_shortcut_folder (default_session_folder);
        }
-       catch (Glib::Error & e) {
+       catch (Glib::Error const& e) {
                std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
        }
 
@@ -1981,7 +1971,7 @@ ARDOUR_UI::open_session ()
        open_session_selector.add_filter (session_filter);
 
        FileFilter archive_filter;
-       archive_filter.add_pattern (X_("*.tar.xz"));
+       archive_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::session_archive_suffix));
        archive_filter.set_name (_("Session Archives"));
 
        open_session_selector.add_filter (archive_filter);
@@ -2622,10 +2612,6 @@ void
 ARDOUR_UI::map_transport_state ()
 {
        if (!_session) {
-               auto_loop_button.unset_active_state ();
-               play_selection_button.unset_active_state ();
-               roll_button.unset_active_state ();
-               stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
                layered_button.set_sensitive (false);
                return;
        }
@@ -2635,52 +2621,9 @@ ARDOUR_UI::map_transport_state ()
        float sp = _session->transport_speed();
 
        if (sp != 0.0f) {
-
-               /* we're rolling */
-
-               if (_session->get_play_range()) {
-
-                       play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
-                       roll_button.unset_active_state ();
-                       auto_loop_button.unset_active_state ();
-
-               } else if (_session->get_play_loop ()) {
-
-                       auto_loop_button.set_active (true);
-                       play_selection_button.set_active (false);
-                       if (Config->get_loop_is_mode()) {
-                               roll_button.set_active (true);
-                       } else {
-                               roll_button.set_active (false);
-                       }
-
-               } else {
-
-                       roll_button.set_active (true);
-                       play_selection_button.set_active (false);
-                       auto_loop_button.set_active (false);
-               }
-
-               if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
-                       /* light up both roll and play-selection if they are joined */
-                       roll_button.set_active (true);
-                       play_selection_button.set_active (true);
-               }
                layered_button.set_sensitive (!_session->actively_recording ());
-
-               stop_button.set_active (false);
-
        } else {
-
                layered_button.set_sensitive (true);
-               stop_button.set_active (true);
-               roll_button.set_active (false);
-               play_selection_button.set_active (false);
-               if (Config->get_loop_is_mode ()) {
-                       auto_loop_button.set_active (_session->get_play_loop());
-               } else {
-                       auto_loop_button.set_active (false);
-               }
                update_disk_space ();
        }
 }
@@ -2688,7 +2631,6 @@ ARDOUR_UI::map_transport_state ()
 void
 ARDOUR_UI::blink_handler (bool blink_on)
 {
-       transport_rec_enable_blink (blink_on);
        sync_blink (blink_on);
 
        if (!UIConfiguration::instance().get_blink_alert_indicators()) {
@@ -2706,7 +2648,7 @@ ARDOUR_UI::update_clocks ()
        if (!_session) return;
 
        if (editor && !editor->dragging_playhead()) {
-               Clock (_session->audible_sample(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
+               Clock (_session->audible_sample()); /* EMIT_SIGNAL */
        }
 }
 
@@ -2877,7 +2819,7 @@ ARDOUR_UI::archive_session ()
                return;
        }
 
-       if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
+       if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) {
                MessageDialog msg (_("Session Archiving failed."));
                msg.run ();
        }
@@ -3132,34 +3074,6 @@ ARDOUR_UI::secondary_clock_value_changed ()
                _session->request_locate (secondary_clock->current_time ());
        }
 }
-
-void
-ARDOUR_UI::transport_rec_enable_blink (bool onoff)
-{
-       if (_session == 0) {
-               return;
-       }
-
-       if (_session->step_editing()) {
-               return;
-       }
-
-       Session::RecordState const r = _session->record_status ();
-       bool const h = _session->have_rec_enabled_track ();
-
-       if (r == Session::Enabled || (r == Session::Recording && !h)) {
-               if (onoff) {
-                       rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
-               } else {
-                       rec_button.set_active_state (Gtkmm2ext::Off);
-               }
-       } else if (r == Session::Recording && h) {
-               rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
-       } else {
-               rec_button.unset_active_state ();
-       }
-}
-
 void
 ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
 {
@@ -3644,7 +3558,7 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
 
        /* this one is special */
 
-       catch (AudioEngine::PortRegistrationFailure& err) {
+       catch (AudioEngine::PortRegistrationFailure const& err) {
 
                MessageDialog msg (err.what(),
                                   true,
@@ -3669,7 +3583,7 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
                }
                goto out;
        }
-       catch (SessionException e) {
+       catch (SessionException const& e) {
                MessageDialog msg (string_compose(
                                           _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
                                           path, snap_name, e.what()),
@@ -3805,7 +3719,7 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name,
                new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
        }
 
-       catch (SessionException e) {
+       catch (SessionException const& e) {
                cerr << "Here are the errors associated with this failed session:\n";
                dump_errors (cerr);
                cerr << "---------\n";
@@ -5288,16 +5202,34 @@ ARDOUR_UI::use_config ()
 void
 ARDOUR_UI::update_transport_clocks (samplepos_t pos)
 {
-       if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
-               primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
-       } else {
-               primary_clock->set (pos);
+       switch (UIConfiguration::instance().get_primary_clock_delta_mode()) {
+               case NoDelta:
+                       primary_clock->set (pos);
+                       break;
+               case DeltaEditPoint:
+                       primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
+                       break;
+               case DeltaOriginMarker:
+                       {
+                               Location* loc = _session->locations()->clock_origin_location ();
+                               primary_clock->set (pos, false, loc ? loc->start() : 0);
+                       }
+                       break;
        }
 
-       if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
-               secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
-       } else {
-               secondary_clock->set (pos);
+       switch (UIConfiguration::instance().get_secondary_clock_delta_mode()) {
+               case NoDelta:
+                       secondary_clock->set (pos);
+                       break;
+               case DeltaEditPoint:
+                       secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
+                       break;
+               case DeltaOriginMarker:
+                       {
+                               Location* loc = _session->locations()->clock_origin_location ();
+                               secondary_clock->set (pos, false, loc ? loc->start() : 0);
+                       }
+                       break;
        }
 
        if (big_clock_window) {
@@ -5306,20 +5238,6 @@ ARDOUR_UI::update_transport_clocks (samplepos_t pos)
        ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
 }
 
-void
-ARDOUR_UI::step_edit_status_change (bool yn)
-{
-       // XXX should really store pre-step edit status of things
-       // we make insensitive
-
-       if (yn) {
-               rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
-               rec_button.set_sensitive (false);
-       } else {
-               rec_button.unset_active_state ();;
-               rec_button.set_sensitive (true);
-       }
-}
 
 void
 ARDOUR_UI::record_state_changed ()
@@ -5386,86 +5304,6 @@ ARDOUR_UI::store_clock_modes ()
        _session->set_dirty ();
 }
 
-ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
-       : Controllable (name), ui (u), type(tp)
-{
-
-}
-
-void
-ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
-{
-       if (val < 0.5) {
-               /* do nothing: these are radio-style actions */
-               return;
-       }
-
-       const char *action = 0;
-
-       switch (type) {
-       case Roll:
-               action = X_("Roll");
-               break;
-       case Stop:
-               action = X_("Stop");
-               break;
-       case GotoStart:
-               action = X_("GotoStart");
-               break;
-       case GotoEnd:
-               action = X_("GotoEnd");
-               break;
-       case AutoLoop:
-               action = X_("Loop");
-               break;
-       case PlaySelection:
-               action = X_("PlaySelection");
-               break;
-       case RecordEnable:
-               action = X_("Record");
-               break;
-       default:
-               break;
-       }
-
-       if (action == 0) {
-               return;
-       }
-
-       Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
-
-       if (act) {
-               act->activate ();
-       }
-}
-
-double
-ARDOUR_UI::TransportControllable::get_value (void) const
-{
-       float val = 0.0;
-
-       switch (type) {
-       case Roll:
-               break;
-       case Stop:
-               break;
-       case GotoStart:
-               break;
-       case GotoEnd:
-               break;
-       case AutoLoop:
-               break;
-       case PlaySelection:
-               break;
-       case RecordEnable:
-               break;
-       default:
-               break;
-       }
-
-       return val;
-}
-
 void
 ARDOUR_UI::setup_profile ()
 {