Editor zooming: Initialize leftmost_frame, for sessions that start at high timecodes.
[ardour.git] / gtk2_ardour / editor.cc
index 4a83bf65710ead1fe0e6112c8815c07aee25668d..d525761140384c43e4fa42f62ba05cf14d06d60e 100644 (file)
 #include <gtkmm/menuitem.h>
 
 #include "gtkmm2ext/bindings.h"
-#include "gtkmm2ext/eventboxext.h"
-#include "gtkmm2ext/grouped_buttons.h"
 #include "gtkmm2ext/gtk_ui.h"
-#include <gtkmm2ext/keyboard.h>
+#include "gtkmm2ext/keyboard.h"
 #include "gtkmm2ext/utils.h"
 #include "gtkmm2ext/window_title.h"
-#include "gtkmm2ext/choice.h"
 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
 
 #include "ardour/analysis_graph.h"
 #include "canvas/debug.h"
 #include "canvas/text.h"
 
+#include "widgets/ardour_spacer.h"
+#include "widgets/eventboxext.h"
+#include "widgets/tooltips.h"
+
 #include "control_protocol/control_protocol.h"
 
 #include "actions.h"
 #include "analysis_window.h"
-#include "ardour_spacer.h"
 #include "audio_clock.h"
 #include "audio_region_view.h"
 #include "audio_streamview.h"
 #include "time_axis_view.h"
 #include "time_info_box.h"
 #include "timers.h"
-#include "tooltips.h"
 #include "ui_config.h"
 #include "utils.h"
 #include "vca_time_axis.h"
 
 using namespace std;
 using namespace ARDOUR;
+using namespace ArdourWidgets;
 using namespace ARDOUR_UI_UTILS;
 using namespace PBD;
 using namespace Gtk;
@@ -302,9 +302,11 @@ Editor::Editor ()
        , minsec_mark_interval (0)
        , minsec_mark_modulo (0)
        , minsec_nmarks (0)
+       , timecode_ruler_scale (timecode_show_many_hours)
        , timecode_mark_modulo (0)
        , timecode_nmarks (0)
        , _samples_ruler_interval (0)
+       , bbt_ruler_scale (bbt_show_many)
        , bbt_bars (0)
        , bbt_nmarks (0)
        , bbt_bar_helper_on (0)
@@ -351,7 +353,7 @@ Editor::Editor ()
        , cut_buffer_start (0)
        , cut_buffer_length (0)
        , button_bindings (0)
-       , last_paste_pos (0)
+       , last_paste_pos (-1)
        , paste_count (0)
        , sfbrowser (0)
        , current_interthread_info (0)
@@ -684,33 +686,21 @@ Editor::Editor ()
        editor_summary_pane.set_check_divider_position (true);
        editor_summary_pane.add (edit_packer);
 
-       Button* summary_arrows_left_left = manage (new Button);
-       summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
-       summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
-       summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
+       Button* summary_arrow_left = manage (new Button);
+       summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
+       summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
+       summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
 
-       Button* summary_arrows_left_right = manage (new Button);
-       summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
-       summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
-       summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
+       Button* summary_arrow_right = manage (new Button);
+       summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
+       summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
+       summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
 
        VBox* summary_arrows_left = manage (new VBox);
-       summary_arrows_left->pack_start (*summary_arrows_left_left);
-       summary_arrows_left->pack_start (*summary_arrows_left_right);
-
-       Button* summary_arrows_right_up = manage (new Button);
-       summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
-       summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
-       summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
-
-       Button* summary_arrows_right_down = manage (new Button);
-       summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
-       summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
-       summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
+       summary_arrows_left->pack_start (*summary_arrow_left);
 
        VBox* summary_arrows_right = manage (new VBox);
-       summary_arrows_right->pack_start (*summary_arrows_right_up);
-       summary_arrows_right->pack_start (*summary_arrows_right_down);
+       summary_arrows_right->pack_start (*summary_arrow_right);
 
        Frame* summary_frame = manage (new Frame);
        summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
@@ -760,11 +750,11 @@ Editor::Editor ()
        ebox->set_name("EditorWindow");
        ebox->add (toolbar_hbox);
 
-       Gtk::EventBox* epane_box = manage (new Gtkmm2ext::EventBoxExt);  //a themeable box
+       Gtk::EventBox* epane_box = manage (new EventBoxExt);  //a themeable box
        epane_box->set_name("EditorWindow");
        epane_box->add (edit_pane);
 
-       Gtk::EventBox* epane_box2 = manage (new Gtkmm2ext::EventBoxExt);  //a themeable box
+       Gtk::EventBox* epane_box2 = manage (new EventBoxExt);  //a themeable box
        epane_box2->set_name("EditorWindow");
        epane_box2->add (global_vpacker);
 
@@ -845,16 +835,16 @@ Editor::Editor ()
 
        _show_marker_lines = false;
 
-        /* Button bindings */
+       /* Button bindings */
 
        button_bindings = new Bindings ("editor-mouse");
 
        XMLNode* node = button_settings();
-        if (node) {
-                for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
-                        button_bindings->load_operation (**i);
-                }
-        }
+       if (node) {
+               for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
+                       button_bindings->load_operation (**i);
+               }
+       }
 
        constructed = true;
 
@@ -1142,7 +1132,7 @@ Editor::deferred_control_scroll (framepos_t /*target*/)
 }
 
 void
-Editor::access_action (std::string action_group, std::string action_item)
+Editor::access_action (const std::string& action_group, const std::string& action_item)
 {
        if (!_session) {
                return;
@@ -1158,6 +1148,12 @@ Editor::access_action (std::string action_group, std::string action_item)
        }
 }
 
+void
+Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
+{
+       ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
+}
+
 void
 Editor::on_realize ()
 {
@@ -1323,6 +1319,10 @@ Editor::set_session (Session *t)
                return;
        }
 
+       //initialize leftmost_frame to the extents of the session
+       //this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost frame before the visible state has been loaded from instant.xml
+       leftmost_frame = session_gui_extents().first;
+       
        _playlist_selector->set_session (_session);
        nudge_clock->set_session (_session);
        _summary->set_session (_session);
@@ -1888,20 +1888,10 @@ Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::sha
 
        RegionSelection rs = get_regions_from_selection_and_entered ();
 
-       string::size_type pos = 0;
        string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
 
-       /* we have to hack up the region name because "_" has a special
-          meaning for menu titles.
-       */
-
-       while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
-               menu_item_name.replace (pos, 1, "__");
-               pos += 2;
-       }
-
        if (_popup_region_menu_item == 0) {
-               _popup_region_menu_item = new MenuItem (menu_item_name);
+               _popup_region_menu_item = new MenuItem (menu_item_name, false);
                _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
                _popup_region_menu_item->show ();
        } else {
@@ -3834,11 +3824,21 @@ Editor::set_visible_track_count (int32_t n)
                str = s.str();
        } else if (_visible_track_count == 0) {
                uint32_t n = 0;
-               for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+               for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
                        if ((*i)->marked_for_display()) {
                                ++n;
+                               TimeAxisView::Children cl ((*i)->get_child_list ());
+                               for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
+                                       if ((*j)->marked_for_display()) {
+                                               ++n;
+                                       }
+                               }
                        }
                }
+               if (n == 0) {
+                       visible_tracks_selector.set_text (X_("*"));
+                       return;
+               }
                h = trackviews_height() / n;
                str = _("All");
        } else {
@@ -4716,7 +4716,7 @@ Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_
        }
 
        if (entered_marker) {
-                DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
+               DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
                return entered_marker->position();
        }
 
@@ -4737,7 +4737,7 @@ Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_
                } else {
                        where = _session->audible_frame();
                }
-                DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
+               DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
                break;
 
        case EditAtSelectedMarker:
@@ -4750,7 +4750,7 @@ Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_
                                } else {
                                        where = loc->end();
                                }
-                                DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
+                               DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
                                break;
                        }
                }
@@ -4765,7 +4765,7 @@ Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_
                snap_mf.frame = where;
                snap_to (snap_mf);
                where = snap_mf.frame;
-                DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
+               DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
                break;
        }
 
@@ -5562,15 +5562,15 @@ Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
        }
 }
 
-/** Find a RouteTimeAxisView by the ID of its route */
-RouteTimeAxisView*
-Editor::get_route_view_by_route_id (const PBD::ID& id) const
+/** Find a StripableTimeAxisView by the ID of its stripable */
+StripableTimeAxisView*
+Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
 {
-       RouteTimeAxisView* v;
+       StripableTimeAxisView* v;
 
        for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
-               if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
-                       if(v->route()->id() == id) {
+               if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
+                       if(v->stripable()->id() == id) {
                                return v;
                        }
                }
@@ -5819,7 +5819,15 @@ Editor::super_rapid_screen_update ()
        const int64_t now = g_get_monotonic_time ();
        double err = 0;
 
+       if (_session->exporting ()) {
+               /* freewheel/export may be faster or slower than transport_speed() / SR.
+                * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
+                */
+               _last_update_time = 0;
+       }
+
        if (_last_update_time > 0) {
+               /* interpolate and smoothen playhead position */
                const double ds =  (now - _last_update_time) * _session->transport_speed() * _session->nominal_frame_rate () * 1e-6;
                framepos_t guess = playhead_cursor->current_frame () + rint (ds);
                err = frame - guess;
@@ -5841,6 +5849,7 @@ Editor::super_rapid_screen_update ()
        if (err > 8192 || latent_locate) {
                // in case of x-runs or freewheeling
                _last_update_time = 0;
+               frame = _session->audible_frame ();
        } else {
                _last_update_time = now;
        }