X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor.cc;h=9b7f112edaebd9cca4b7f1b8c4a0edbef533ff9a;hb=735d791e420c3e4944fdbc8ac7f6a26251d90d87;hp=e4d2a126a1c9b1ccabfede99d55236b14d85da47;hpb=8eff36913c91bfd5731b6d1cdaa7f0250de7b6e6;p=ardour.git diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index e4d2a126a1..9b7f112eda 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -57,12 +57,10 @@ #include #include "gtkmm2ext/bindings.h" -#include "gtkmm2ext/grouped_buttons.h" #include "gtkmm2ext/gtk_ui.h" -#include +#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" @@ -83,11 +81,14 @@ #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" @@ -97,6 +98,7 @@ #include "crossfade_edit.h" #include "debug.h" #include "editing.h" +#include "editing_convert.h" #include "editor.h" #include "editor_cursors.h" #include "editor_drag.h" @@ -107,12 +109,12 @@ #include "editor_routes.h" #include "editor_snapshots.h" #include "editor_summary.h" +#include "enums_convert.h" #include "export_report.h" #include "global_port_matrix.h" #include "gui_object.h" #include "gui_thread.h" #include "keyboard.h" -#include "keyeditor.h" #include "luainstance.h" #include "marker.h" #include "midi_region_view.h" @@ -135,7 +137,6 @@ #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" @@ -145,6 +146,7 @@ using namespace std; using namespace ARDOUR; +using namespace ArdourWidgets; using namespace ARDOUR_UI_UTILS; using namespace PBD; using namespace Gtk; @@ -300,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) @@ -343,11 +347,13 @@ Editor::Editor () , _full_canvas_height (0) , edit_controls_left_menu (0) , edit_controls_right_menu (0) - , last_update_frame (0) + , visual_change_queued(false) + , _last_update_time (0) + , _err_screen_engine (0) , 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) @@ -387,12 +393,13 @@ Editor::Editor () , _visible_track_count (-1) , toolbar_selection_clock_table (2,3) , automation_mode_button (_("mode")) - , selection (new Selection (this)) - , cut_buffer (new Selection (this)) + , selection (new Selection (this, true)) + , cut_buffer (new Selection (this, false)) , _selection_memento (new SelectionMemento()) , _all_region_actions_sensitized (false) , _ignore_region_action (false) , _last_region_menu_was_main (false) + , _track_selection_change_without_scroll (false) , cd_marker_bar_drag_rect (0) , range_bar_drag_rect (0) , transport_bar_drag_rect (0) @@ -487,7 +494,7 @@ Editor::Editor () location_loop_color = UIConfiguration::instance().color ("location loop"); location_punch_color = UIConfiguration::instance().color ("location punch"); - timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale)); + timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale())); TimeAxisView::setup_sizes (); ArdourMarker::setup_sizes (timebar_height); @@ -638,12 +645,14 @@ Editor::Editor () bottom_hbox.set_border_width (2); bottom_hbox.set_spacing (3); + PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context()); + _route_groups = new EditorRouteGroups (this); _routes = new EditorRoutes (this); _regions = new EditorRegions (this); _snapshots = new EditorSnapshots (this); _locations = new EditorLocations (this); - _time_info_box = new TimeInfoBox (true); + _time_info_box = new TimeInfoBox ("EditorTimeInfo", true); /* these are static location signals */ @@ -669,42 +678,29 @@ Editor::Editor () /* Pick up some settings we need to cache, early */ XMLNode* settings = ARDOUR_UI::instance()->editor_settings(); - XMLProperty* prop; - if (settings && (prop = settings->property ("notebook-shrunk"))) { - _notebook_shrunk = string_is_affirmative (prop->value ()); + if (settings) { + settings->get_property ("notebook-shrunk", _notebook_shrunk); } 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); @@ -733,25 +729,17 @@ Editor::Editor () editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down); float fract; + if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) { + /* initial allocation is 90% to canvas, 10% to notebook */ + fract = 0.90; + } + edit_pane.set_divider (0, fract); - { - LocaleGuard lg; - - if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) { - /* initial allocation is 90% to canvas, 10% to notebook */ - edit_pane.set_divider (0, 0.90); - } else { - edit_pane.set_divider (0, fract); - } - - if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) { - /* initial allocation is 90% to canvas, 10% to summary */ - editor_summary_pane.set_divider (0, 0.90); - } else { - - editor_summary_pane.set_divider (0, fract); - } + if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) { + /* initial allocation is 90% to canvas, 10% to summary */ + fract = 0.90; } + editor_summary_pane.set_divider (0, fract); global_vpacker.set_spacing (2); global_vpacker.set_border_width (0); @@ -762,11 +750,11 @@ Editor::Editor () ebox->set_name("EditorWindow"); ebox->add (toolbar_hbox); - Gtk::EventBox* epane_box = manage (new Gtk::EventBox); //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 Gtk::EventBox); //a themeable box + Gtk::EventBox* epane_box2 = manage (new EventBoxExt); //a themeable box epane_box2->set_name("EditorWindow"); epane_box2->add (global_vpacker); @@ -828,8 +816,6 @@ Editor::Editor () BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context()); - PresentationInfo::Change.connect (*this, invalidator (*this), boost::bind (&Editor::presentation_info_changed, this, _1), gui_context()); - /* handle escape */ ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context()); @@ -849,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; @@ -868,9 +854,6 @@ Editor::Editor () setup_fade_images (); - LuaInstance::instance(); // instantiate - LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name)); - instant_save (); } @@ -908,14 +891,6 @@ Editor::~Editor() } } -void -Editor::presentation_info_changed (PropertyChange const & what_changed) -{ - if (what_changed.contains (Properties::selected)) { - track_selection_changed (); - } -} - XMLNode* Editor::button_settings () const { @@ -1051,7 +1026,7 @@ Editor::control_unselect () void Editor::control_select (boost::shared_ptr s, Selection::Operation op) { - TimeAxisView* tav = axis_view_from_stripable (s); + TimeAxisView* tav = time_axis_view_from_stripable (s); if (tav) { switch (op) { @@ -1157,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; @@ -1173,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 () { @@ -1384,6 +1365,12 @@ Editor::set_session (Session *t) XMLNode* node = ARDOUR_UI::instance()->editor_settings(); set_state (*node, Stateful::loading_state_version); + /* catch up on selection state, etc. */ + + PropertyChange sc; + sc.add (Properties::selected); + presentation_info_changed (sc); + /* catch up with the playhead */ _session->request_locate (playhead_cursor->current_frame ()); @@ -1399,6 +1386,7 @@ Editor::set_session (Session *t) _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context()); _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context()); + _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context()); _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context()); _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context()); _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context()); @@ -1443,53 +1431,15 @@ Editor::set_session (Session *t) break; } - /* catch up on selection of stripables (other selection state is lost - * when a session is closed - */ - - StripableList sl; - TrackViewList tl; - _session->get_stripables (sl); - for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) { - if ((*s)->presentation_info().selected()) { - RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id()); - if (rtav) { - tl.push_back (rtav); - } - } - } - if (!tl.empty()) { - selection->set (tl); - } - /* register for undo history */ _session->register_with_memento_command_factory(id(), this); _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento); - ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated)); - LuaInstance::instance()->set_session(_session); start_updating_meters (); } -void -Editor::action_pre_activated (Glib::RefPtr const & a) -{ - if (a->get_name() == "RegionMenu") { - /* When the main menu's region menu is opened, we setup the actions so that they look right - in the menu. I can't find a way of getting a signal when this menu is subsequently closed, - so we resensitize all region actions when the entered regionview or the region selection - changes. HOWEVER we can't always resensitize on entered_regionview change because that - happens after the region context menu is opened. So we set a flag here, too. - - What a carry on :( - */ - sensitize_the_right_region_actions (); - _last_region_menu_was_main = true; - } -} - void Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start) { @@ -1717,7 +1667,7 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, /* When the region menu is opened, we setup the actions so that they look right in the menu. */ - sensitize_the_right_region_actions (); + sensitize_the_right_region_actions (false); _last_region_menu_was_main = false; menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true)); @@ -1934,27 +1884,17 @@ 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 (ActionManager::get_widget (X_("/PopupRegionMenu")))); _popup_region_menu_item->show (); } else { _popup_region_menu_item->set_label (menu_item_name); } - /* No latering allowed in later is higher layering model */ + /* No layering allowed in later is higher layering model */ RefPtr act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering")); if (act && Config->get_layer_model() == LaterHigher) { act->set_sensitive (false); @@ -2365,6 +2305,7 @@ Editor::set_edit_point_preference (EditPoint ep, bool force) } reset_canvas_action_sensitivity (in_track_canvas); + sensitize_the_right_region_actions (false); instant_save (); } @@ -2372,18 +2313,16 @@ Editor::set_edit_point_preference (EditPoint ep, bool force) int Editor::set_state (const XMLNode& node, int version) { - XMLProperty const * prop; set_id (node); PBD::Unwinder nsi (no_save_instant, true); - LocaleGuard lg; + bool yn; Tabbable::set_state (node, version); - if (_session && (prop = node.property ("playhead"))) { - framepos_t pos; - sscanf (prop->value().c_str(), "%" PRIi64, &pos); - if (pos >= 0) { - playhead_cursor->set_position (pos); + framepos_t ph_pos; + if (_session && node.get_property ("playhead", ph_pos)) { + if (ph_pos >= 0) { + playhead_cursor->set_position (ph_pos); } else { warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg; playhead_cursor->set_position (0); @@ -2392,86 +2331,70 @@ Editor::set_state (const XMLNode& node, int version) playhead_cursor->set_position (0); } - if ((prop = node.property ("mixer-width"))) { - editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width)); - } + node.get_property ("mixer-width", editor_mixer_strip_width); - if ((prop = node.property ("zoom-focus"))) { - zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus)); - } else { - zoom_focus_selection_done (zoom_focus); - } + node.get_property ("zoom-focus", zoom_focus); + zoom_focus_selection_done (zoom_focus); - if ((prop = node.property ("zoom"))) { + double z; + if (node.get_property ("zoom", z)) { /* older versions of ardour used floating point samples_per_pixel */ - double f = PBD::atof (prop->value()); - reset_zoom (llrintf (f)); + reset_zoom (llrintf (z)); } else { reset_zoom (samples_per_pixel); } - if ((prop = node.property ("visible-track-count"))) { - set_visible_track_count (PBD::atoi (prop->value())); + int32_t cnt; + if (node.get_property ("visible-track-count", cnt)) { + set_visible_track_count (cnt); } - if ((prop = node.property ("snap-to"))) { - snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type)); - set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type)); - } else { - set_snap_to (_snap_type); + SnapType snap_type; + if (!node.get_property ("snap-to", snap_type)) { + snap_type = _snap_type; } + set_snap_to (snap_type); - if ((prop = node.property ("snap-mode"))) { - snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode)); + SnapMode sm; + if (node.get_property ("snap-mode", sm)) { + snap_mode_selection_done(sm); /* set text of Dropdown. in case _snap_mode == SnapOff (default) * snap_mode_selection_done() will only mark an already active item as active * which does not trigger set_text(). */ - set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode)); + set_snap_mode (sm); } else { set_snap_mode (_snap_mode); } - if ((prop = node.property ("internal-snap-to"))) { - internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type); - } - - if ((prop = node.property ("internal-snap-mode"))) { - internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode); - } - - if ((prop = node.property ("pre-internal-snap-to"))) { - pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type); - } + node.get_property ("internal-snap-to", internal_snap_type); + node.get_property ("internal-snap-mode", internal_snap_mode); + node.get_property ("pre-internal-snap-to", pre_internal_snap_type); + node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode); - if ((prop = node.property ("pre-internal-snap-mode"))) { - pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode); - } - - if ((prop = node.property ("mouse-mode"))) { - MouseMode m = str2mousemode(prop->value()); + std::string mm_str; + if (node.get_property ("mouse-mode", mm_str)) { + MouseMode m = str2mousemode(mm_str); set_mouse_mode (m, true); } else { set_mouse_mode (MouseObject, true); } - if ((prop = node.property ("left-frame")) != 0) { - framepos_t pos; - if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) { - if (pos < 0) { - pos = 0; - } - reset_x_origin (pos); + framepos_t lf_pos; + if (node.get_property ("left-frame", lf_pos)) { + if (lf_pos < 0) { + lf_pos = 0; } + reset_x_origin (lf_pos); } - if ((prop = node.property ("y-origin")) != 0) { - reset_y_origin (atof (prop->value ())); + double y_origin; + if (node.get_property ("y-origin", y_origin)) { + reset_y_origin (y_origin); } - if ((prop = node.property ("join-object-range"))) { + if (node.get_property ("join-object-range", yn)) { RefPtr act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range")); - bool yn = string_is_affirmative (prop->value()); if (act) { RefPtr tact = RefPtr::cast_dynamic(act); tact->set_active (!yn); @@ -2480,39 +2403,34 @@ Editor::set_state (const XMLNode& node, int version) set_mouse_mode(mouse_mode, true); } - if ((prop = node.property ("edit-point"))) { - set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true); + EditPoint ep; + if (node.get_property ("edit-point", ep)) { + set_edit_point_preference (ep, true); } else { set_edit_point_preference (_edit_point); } - if ((prop = node.property ("show-measures"))) { - bool yn = string_is_affirmative (prop->value()); - _show_measures = yn; - } + node.get_property ("show-measures", _show_measures); - if ((prop = node.property ("follow-playhead"))) { - bool yn = string_is_affirmative (prop->value()); + if (node.get_property ("follow-playhead", yn)) { set_follow_playhead (yn); } - if ((prop = node.property ("stationary-playhead"))) { - bool yn = string_is_affirmative (prop->value()); + if (node.get_property ("stationary-playhead", yn)) { set_stationary_playhead (yn); } - if ((prop = node.property ("region-list-sort-type"))) { - RegionListSortType st; - _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true); + RegionListSortType sort_type; + if (node.get_property ("region-list-sort-type", sort_type)) { + _regions->reset_sort_type (sort_type, true); } - if ((prop = node.property ("show-editor-mixer"))) { + if (node.get_property ("show-editor-mixer", yn)) { Glib::RefPtr act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer")); assert (act); Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); - bool yn = string_is_affirmative (prop->value()); /* do it twice to force the change */ @@ -2520,13 +2438,12 @@ Editor::set_state (const XMLNode& node, int version) tact->set_active (yn); } - if ((prop = node.property ("show-editor-list"))) { + if (node.get_property ("show-editor-list", yn)) { Glib::RefPtr act = ActionManager::get_action (X_("Editor"), X_("show-editor-list")); assert (act); Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); - bool yn = string_is_affirmative (prop->value()); /* do it twice to force the change */ @@ -2534,15 +2451,15 @@ Editor::set_state (const XMLNode& node, int version) tact->set_active (yn); } - if ((prop = node.property (X_("editor-list-page")))) { - _the_notebook.set_current_page (atoi (prop->value ())); + int32_t el_page; + if (node.get_property (X_("editor-list-page"), el_page)) { + _the_notebook.set_current_page (el_page); } - if ((prop = node.property (X_("show-marker-lines")))) { + if (node.get_property (X_("show-marker-lines"), yn)) { Glib::RefPtr act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines")); assert (act); Glib::RefPtr tact = Glib::RefPtr::cast_dynamic (act); - bool yn = string_is_affirmative (prop->value ()); tact->set_active (!yn); tact->set_active (yn); @@ -2555,8 +2472,7 @@ Editor::set_state (const XMLNode& node, int version) _locations->set_state (**i); } - if ((prop = node.property ("maximised"))) { - bool yn = string_is_affirmative (prop->value()); + if (node.get_property ("maximised", yn)) { Glib::RefPtr act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor")); assert (act); Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); @@ -2566,10 +2482,9 @@ Editor::set_state (const XMLNode& node, int version) } } - if ((prop = node.property ("nudge-clock-value"))) { - framepos_t f; - sscanf (prop->value().c_str(), "%" PRId64, &f); - nudge_clock->set (f); + framepos_t nudge_clock_value; + if (node.get_property ("nudge-clock-value", nudge_clock_value)) { + nudge_clock->set (nudge_clock_value); } else { nudge_clock->set_mode (AudioClock::Timecode); nudge_clock->set (_session->frame_rate() * 5, true); @@ -2581,7 +2496,6 @@ Editor::set_state (const XMLNode& node, int version) * those that are linked to a private variable may need changing */ RefPtr act; - bool yn; act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility")); if (act) { @@ -2618,79 +2532,67 @@ XMLNode& Editor::get_state () { XMLNode* node = new XMLNode (X_("Editor")); - char buf[32]; - LocaleGuard lg; - id().print (buf, sizeof (buf)); - node->add_property ("id", buf); + node->set_property ("id", id().to_s ()); node->add_child_nocopy (Tabbable::get_state()); - snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ()); - node->add_property("edit-horizontal-pane-pos", string(buf)); - node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0"); - snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider()); - node->add_property("edit-vertical-pane-pos", string(buf)); + node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ()); + node->set_property("notebook-shrunk", _notebook_shrunk); + node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider()); maybe_add_mixer_strip_width (*node); - node->add_property ("zoom-focus", enum_2_string (zoom_focus)); - - snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel); - node->add_property ("zoom", buf); - node->add_property ("snap-to", enum_2_string (_snap_type)); - node->add_property ("snap-mode", enum_2_string (_snap_mode)); - node->add_property ("internal-snap-to", enum_2_string (internal_snap_type)); - node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode)); - node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type)); - node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode)); - node->add_property ("edit-point", enum_2_string (_edit_point)); - snprintf (buf, sizeof(buf), "%d", _visible_track_count); - node->add_property ("visible-track-count", buf); - - snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ()); - node->add_property ("playhead", buf); - snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame); - node->add_property ("left-frame", buf); - snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ()); - node->add_property ("y-origin", buf); - - node->add_property ("show-measures", _show_measures ? "yes" : "no"); - node->add_property ("maximised", _maximised ? "yes" : "no"); - node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no"); - node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no"); - node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ())); - node->add_property ("mouse-mode", enum2str(mouse_mode)); - node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no"); + node->set_property ("zoom-focus", zoom_focus); + + node->set_property ("zoom", samples_per_pixel); + node->set_property ("snap-to", _snap_type); + node->set_property ("snap-mode", _snap_mode); + node->set_property ("internal-snap-to", internal_snap_type); + node->set_property ("internal-snap-mode", internal_snap_mode); + node->set_property ("pre-internal-snap-to", pre_internal_snap_type); + node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode); + node->set_property ("edit-point", _edit_point); + node->set_property ("visible-track-count", _visible_track_count); + + node->set_property ("playhead", playhead_cursor->current_frame ()); + node->set_property ("left-frame", leftmost_frame); + node->set_property ("y-origin", vertical_adjustment.get_value ()); + + node->set_property ("show-measures", _show_measures); + node->set_property ("maximised", _maximised); + node->set_property ("follow-playhead", _follow_playhead); + node->set_property ("stationary-playhead", _stationary_playhead); + node->set_property ("region-list-sort-type", _regions->sort_type ()); + node->set_property ("mouse-mode", mouse_mode); + node->set_property ("join-object-range", smart_mode_action->get_active ()); Glib::RefPtr act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer")); if (act) { Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); - node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no"); + node->set_property (X_("show-editor-mixer"), tact->get_active()); } act = ActionManager::get_action (X_("Editor"), X_("show-editor-list")); if (act) { Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); - node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no"); + node->set_property (X_("show-editor-list"), tact->get_active()); } - snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ()); - node->add_property (X_("editor-list-page"), buf); + node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ()); - if (button_bindings) { - XMLNode* bb = new XMLNode (X_("Buttons")); - button_bindings->save (*bb); - node->add_child_nocopy (*bb); - } + if (button_bindings) { + XMLNode* bb = new XMLNode (X_("Buttons")); + button_bindings->save (*bb); + node->add_child_nocopy (*bb); + } - node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no"); + node->set_property (X_("show-marker-lines"), _show_marker_lines); node->add_child_nocopy (selection->get_state ()); node->add_child_nocopy (_regions->get_state ()); - snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration()); - node->add_property ("nudge-clock-value", buf); + node->set_property ("nudge-clock-value", nudge_clock->current_duration()); node->add_child_nocopy (LuaInstance::instance()->get_action_state()); node->add_child_nocopy (LuaInstance::instance()->get_hook_state()); @@ -3477,6 +3379,15 @@ Editor::map_transport_state () update_loop_range_view (); } +void +Editor::transport_looped () +{ + /* reset Playhead position interpolation. + * see Editor::super_rapid_screen_update + */ + _last_update_time = 0; +} + /* UNDO/REDO */ void @@ -3909,11 +3820,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 { @@ -4585,9 +4506,13 @@ Editor::set_samples_per_pixel (framecnt_t spp) } samples_per_pixel = spp; +} +void +Editor::on_samples_per_pixel_changed () +{ if (tempo_lines) { - tempo_lines->tempo_map_changed(); + tempo_lines->tempo_map_changed(_session->tempo_map().music_origin()); } bool const showing_time_selection = selection->time.length() > 0; @@ -4628,13 +4553,7 @@ Editor::playhead_cursor_sample () const void Editor::queue_visual_videotimeline_update () { - /* TODO: - * pending_visual_change.add (VisualChange::VideoTimeline); - * or maybe even more specific: which videotimeline-image - * currently it calls update_video_timeline() to update - * _all outdated_ images on the video-timeline. - * see 'exposeimg()' in video_image_frame.cc - */ + pending_visual_change.add (VisualChange::VideoTimeline); ensure_visual_change_idle_handler (); } @@ -4654,9 +4573,25 @@ Editor::_idle_visual_changer (void* arg) return static_cast(arg)->idle_visual_changer (); } +void +Editor::pre_render () +{ + visual_change_queued = false; + + if (pending_visual_change.pending != 0) { + ensure_visual_change_idle_handler(); + } +} + int Editor::idle_visual_changer () { + pending_visual_change.idle_handler_id = -1; + + if (pending_visual_change.pending == 0) { + return 0; + } + /* set_horizontal_position() below (and maybe other calls) call gtk_main_iteration(), so it's possible that a signal will be handled half-way through this method. If this signal wants an @@ -4667,7 +4602,10 @@ Editor::idle_visual_changer () the last one. */ - pending_visual_change.idle_handler_id = -1; + if (visual_change_queued) { + return 0; + } + pending_visual_change.being_handled = true; VisualChange vc = pending_visual_change; @@ -4678,40 +4616,63 @@ Editor::idle_visual_changer () pending_visual_change.being_handled = false; + visual_change_queued = true; + return 0; /* this is always a one-shot call */ } void Editor::visual_changer (const VisualChange& vc) { - double const last_time_origin = horizontal_position (); - + /** + * Changed first so the correct horizontal canvas position is calculated in + * Editor::set_horizontal_position + */ if (vc.pending & VisualChange::ZoomLevel) { set_samples_per_pixel (vc.samples_per_pixel); - - compute_fixed_ruler_scale (); - - compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples()); - update_tempo_based_rulers (); - - update_video_timeline(); } if (vc.pending & VisualChange::TimeOrigin) { - set_horizontal_position (vc.time_origin / samples_per_pixel); + double new_time_origin = sample_to_pixel_unrounded (vc.time_origin); + set_horizontal_position (new_time_origin); } if (vc.pending & VisualChange::YOrigin) { vertical_adjustment.set_value (vc.y_origin); } - if (last_time_origin == horizontal_position ()) { - /* changed signal not emitted */ - update_fixed_rulers (); - redisplay_tempo (true); + /** + * Now the canvas is in the final state before render the canvas items that + * support the Item::prepare_for_render interface can calculate the correct + * item to visible canvas intersection. + */ + if (vc.pending & VisualChange::ZoomLevel) { + on_samples_per_pixel_changed (); + + compute_fixed_ruler_scale (); + + compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples()); + update_tempo_based_rulers (); } if (!(vc.pending & VisualChange::ZoomLevel)) { + /** + * If the canvas is not being zoomed then the canvas items will not change + * and cause Item::prepare_for_render to be called so do it here manually. + * + * Not ideal, but I can't think of a better solution atm. + */ + _track_canvas->prepare_for_render(); + } + + // If we are only scrolling vertically there is no need to update these + if (vc.pending != VisualChange::YOrigin) { + update_fixed_rulers (); + redisplay_tempo (true); + + /* video frames & position need to be updated for zoom, horiz-scroll + * and (explicitly) VisualChange::VideoTimeline. + */ update_video_timeline(); } @@ -4747,11 +4708,11 @@ Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_ if (from_outside_canvas && (ep == EditAtMouse)) { ep = EditAtPlayhead; } else if (from_context_menu && (ep == EditAtMouse)) { - return canvas_event_sample (&context_click_event, 0, 0); + return canvas_event_sample (&context_click_event, 0, 0); } 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(); } @@ -4767,12 +4728,12 @@ Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_ switch (ep) { case EditAtPlayhead: - if (_dragging_playhead) { + if (_dragging_playhead && _control_scroll_target) { where = *_control_scroll_target; } 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: @@ -4785,7 +4746,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; } } @@ -4800,7 +4761,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; } @@ -4949,7 +4910,7 @@ Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackVie */ RegionSelection -Editor::get_regions_from_selection_and_edit_point () +Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas) { RegionSelection regions; @@ -4966,7 +4927,7 @@ Editor::get_regions_from_selection_and_edit_point () /* no region selected or entered, but some selected tracks: * act on all regions on the selected tracks at the edit point */ - framepos_t const where = get_preferred_edit_position (); + framepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas); get_regions_at(regions, where, tracks); } } @@ -5108,6 +5069,38 @@ Editor::get_regions_corresponding_to (boost::shared_ptr region, vector region) const +{ + for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) { + RouteTimeAxisView* tatv; + if ((tatv = dynamic_cast (*i)) != 0) { + if (!tatv->track()) { + continue; + } + RegionView* marv = tatv->view()->find_view (region); + if (marv) { + return marv; + } + } + } + return NULL; +} + +RouteTimeAxisView* +Editor::rtav_from_route (boost::shared_ptr route) const +{ + for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) { + RouteTimeAxisView* rtav; + if ((rtav = dynamic_cast (*i)) != 0) { + if (rtav->route() == route) { + return rtav; + } + } + } + return NULL; +} + void Editor::show_rhythm_ferret () { @@ -5139,6 +5132,17 @@ Editor::first_idle () (*t)->first_idle(); } + /* now that all regionviews should exist, setup region selection */ + + RegionSelection rs; + + for (list::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) { + /* this is cumulative: rs is NOT cleared each time */ + get_regionviews_by_id (*pr, rs); + } + + selection->set (rs); + // first idle adds route children (automation tracks), so we need to redisplay here _routes->redisplay (); @@ -5234,19 +5238,12 @@ Editor::located () _pending_locate_request = false; _pending_initial_locate = false; + _last_update_time = 0; } void Editor::region_view_added (RegionView * rv) { - for (list::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) { - if (rv->region ()->id () == (*pr)) { - selection->add (rv); - selection->regions.pending.erase (pr); - break; - } - } - MidiRegionView* mrv = dynamic_cast (rv); if (mrv) { list > >::iterator rnote; @@ -5268,8 +5265,8 @@ Editor::region_view_removed () _summary->set_background_dirty (); } -TimeAxisView* -Editor::axis_view_from_stripable (boost::shared_ptr s) const +AxisView* +Editor::axis_view_by_stripable (boost::shared_ptr s) const { for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) { if ((*j)->stripable() == s) { @@ -5280,6 +5277,25 @@ Editor::axis_view_from_stripable (boost::shared_ptr s) const return 0; } +AxisView* +Editor::axis_view_by_control (boost::shared_ptr c) const +{ + for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) { + if ((*j)->control() == c) { + return *j; + } + + TimeAxisView::Children kids = (*j)->get_child_list (); + + for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) { + if ((*k)->control() == c) { + return (*k).get(); + } + } + } + + return 0; +} TrackViewList Editor::axis_views_from_routes (boost::shared_ptr r) const @@ -5287,7 +5303,7 @@ Editor::axis_views_from_routes (boost::shared_ptr r) const TrackViewList t; for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) { - TimeAxisView* tv = axis_view_from_stripable (*i); + TimeAxisView* tv = time_axis_view_from_stripable (*i); if (tv) { t.push_back (tv); } @@ -5346,7 +5362,7 @@ Editor::add_stripables (StripableList& sl) TrackViewList new_selection; bool from_scratch = (track_views.size() == 0); - sl.sort (StripablePresentationInfoSorter()); + sl.sort (Stripable::Sorter()); for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) { @@ -5396,8 +5412,7 @@ Editor::add_stripables (StripableList& sl) */ if (!from_scratch && !new_selection.empty()) { - selection->tracks.clear(); - selection->add (new_selection); + selection->set (new_selection); begin_selection_op_history(); } @@ -5487,6 +5502,9 @@ Editor::timeaxisview_deleted (TimeAxisView *tv) void Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection) { + if (!tv) { + return; + } if (apply_to_selection) { for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) { @@ -5509,6 +5527,18 @@ Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection) } } +void +Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view) +{ + if (!tv) { + return; + } + _routes->show_track_in_display (*tv); + if (move_into_view) { + ensure_time_axis_view_is_visible (*tv, false); + } +} + bool Editor::sync_track_view_list_and_routes () { @@ -5528,15 +5558,15 @@ Editor::foreach_time_axis_view (sigc::slot 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(*i)) != 0) { - if(v->route()->id() == id) { + if((v = dynamic_cast(*i)) != 0) { + if(v->stripable()->id() == id) { return v; } } @@ -5761,8 +5791,6 @@ Editor::super_rapid_screen_update () /* PLAYHEAD AND VIEWPORT */ - framepos_t const frame = _session->audible_frame(); - /* There are a few reasons why we might not update the playhead / viewport stuff: * * 1. we don't update things when there's a pending locate request, otherwise @@ -5772,46 +5800,92 @@ Editor::super_rapid_screen_update () * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere). * 3. if we're still at the same frame that we were last time, there's nothing to do. */ + if (_pending_locate_request || !_session->transport_rolling ()) { + _last_update_time = 0; + return; + } - if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) { + if (_dragging_playhead) { + _last_update_time = 0; + return; + } - last_update_frame = frame; + bool latent_locate = false; + framepos_t frame = _session->audible_frame (&latent_locate); + const int64_t now = g_get_monotonic_time (); + double err = 0; - if (!_dragging_playhead) { - playhead_cursor->set_position (frame); - } + 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 (!_stationary_playhead) { + 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; - if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) { - /* We only do this if we aren't already - handling a visual change (ie if - pending_visual_change.being_handled is - false) so that these requests don't stack - up there are too many of them to handle in - time. - */ - reset_x_origin_to_follow_playhead (); - } + guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update) + _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2 - } else { +#if 0 // DEBUG + printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n", + frame, guess, ds, + err, _err_screen_engine); +#endif - if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) { - framepos_t const frame = playhead_cursor->current_frame (); - double target = ((double)frame - (double)current_page_samples()/2.0); - if (target <= 0.0) { - target = 0.0; - } - // compare to EditorCursor::set_position() - double const old_pos = sample_to_pixel_unrounded (leftmost_frame); - double const new_pos = sample_to_pixel_unrounded (target); - if (rint (new_pos) != rint (old_pos)) { - reset_x_origin (pixel_to_sample (floor (new_pos))); - } - } + frame = guess; + } else { + _err_screen_engine = 0; + } - } + 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; + } + + if (playhead_cursor->current_frame () == frame) { + return; + } + + playhead_cursor->set_position (frame); + + if (_session->requested_return_frame() >= 0) { + _last_update_time = 0; + return; + } + + if (!_follow_playhead || pending_visual_change.being_handled) { + /* We only do this if we aren't already + * handling a visual change (ie if + * pending_visual_change.being_handled is + * false) so that these requests don't stack + * up there are too many of them to handle in + * time. + */ + return; + } + if (!_stationary_playhead) { + reset_x_origin_to_follow_playhead (); + } else { + framepos_t const frame = playhead_cursor->current_frame (); + double target = ((double)frame - (double)current_page_samples() / 2.0); + if (target <= 0.0) { + target = 0.0; + } + // compare to EditorCursor::set_position() + double const old_pos = sample_to_pixel_unrounded (leftmost_frame); + double const new_pos = sample_to_pixel_unrounded (target); + if (rint (new_pos) != rint (old_pos)) { + reset_x_origin (pixel_to_sample (new_pos)); + } } } @@ -5833,7 +5907,7 @@ Editor::session_going_away () clicked_routeview = 0; entered_regionview = 0; entered_track = 0; - last_update_frame = 0; + _last_update_time = 0; _drags->abort (); playhead_cursor->hide (); @@ -5873,6 +5947,9 @@ Editor::session_going_away () hide_measures (); clear_marker_display (); + delete tempo_lines; + tempo_lines = 0; + stop_step_editing (); if (own_window()) { @@ -5894,24 +5971,6 @@ Editor::trigger_script (int i) LuaInstance::instance()-> call_action (i); } -void -Editor::set_script_action_name (int i, const std::string& n) -{ - string const a = string_compose (X_("script-action-%1"), i + 1); - Glib::RefPtr act = ActionManager::get_action(X_("Editor"), a.c_str()); - assert (act); - if (n.empty ()) { - act->set_label (string_compose (_("Unset #%1"), i + 1)); - act->set_tooltip (_("no action bound")); - act->set_sensitive (false); - } else { - act->set_label (n); - act->set_tooltip (n); - act->set_sensitive (true); - } - KeyEditor::UpdateBindings (); -} - void Editor::show_editor_list (bool yn) {