Fix --template commandline option
[ardour.git] / gtk2_ardour / editor.cc
index 60e0ab4a9748fbc132cb64d5643e970b26b61bca..ff587b2fc14683886a363d346e6e0ffeaa3fe3a0 100644 (file)
@@ -79,6 +79,7 @@
 #include "ardour/vca.h"
 
 #include "canvas/debug.h"
+#include "canvas/note.h"
 #include "canvas/text.h"
 
 #include "widgets/ardour_spacer.h"
@@ -261,11 +262,6 @@ Editor::Editor ()
        , clicked_control_point (0)
        , button_release_can_deselect (true)
        , _mouse_changed_selection (false)
-       , region_edit_menu_split_item (0)
-       , region_edit_menu_split_multichannel_item (0)
-       , track_region_edit_playlist_menu (0)
-       , track_edit_playlist_submenu (0)
-       , track_selection_edit_playlist_submenu (0)
        , _popup_region_menu_item (0)
        , _track_canvas (0)
        , _track_canvas_viewport (0)
@@ -374,9 +370,7 @@ Editor::Editor ()
        , meter_marker_menu (0)
        , marker_menu (0)
        , range_marker_menu (0)
-       , transport_marker_menu (0)
        , new_transport_marker_menu (0)
-       , cd_marker_menu (0)
        , marker_menu_item (0)
        , bbt_beat_subdivision (4)
        , _visible_track_count (-1)
@@ -447,7 +441,6 @@ Editor::Editor ()
        , _stepping_axis_view (0)
        , quantize_dialog (0)
        , _main_menu_disabler (0)
-       , myactions (X_("editor"))
 {
        /* we are a singleton */
 
@@ -698,14 +691,14 @@ Editor::Editor ()
        VBox* summary_arrows_right = manage (new VBox);
        summary_arrows_right->pack_start (*summary_arrow_right);
 
-       Frame* summary_sample = manage (new Frame);
-       summary_sample->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
+       Frame* summary_frame = manage (new Frame);
+       summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
 
-       summary_sample->add (*_summary);
-       summary_sample->show ();
+       summary_frame->add (*_summary);
+       summary_frame->show ();
 
        _summary_hbox.pack_start (*summary_arrows_left, false, false);
-       _summary_hbox.pack_start (*summary_sample, true, true);
+       _summary_hbox.pack_start (*summary_frame, true, true);
        _summary_hbox.pack_start (*summary_arrows_right, false, false);
 
        if (!ARDOUR::Profile->get_trx()) {
@@ -774,8 +767,8 @@ Editor::Editor ()
 
        /* register actions now so that set_state() can find them and set toggles/checks etc */
 
-       register_actions ();
        load_bindings ();
+       register_actions ();
 
        setup_toolbar ();
 
@@ -836,7 +829,6 @@ Editor::Editor ()
 
        _ignore_region_action = false;
        _last_region_menu_was_main = false;
-       _popup_region_menu_item = 0;
 
        _show_marker_lines = false;
 
@@ -860,12 +852,18 @@ Editor::Editor ()
        setup_fade_images ();
 
        set_grid_to (GridTypeNone);
-
-       instant_save ();
 }
 
 Editor::~Editor()
 {
+       delete tempo_marker_menu;
+       delete meter_marker_menu;
+       delete marker_menu;
+       delete range_marker_menu;
+       delete new_transport_marker_menu;
+       delete editor_ruler_menu;
+       delete _popup_region_menu_item;
+
        delete button_bindings;
        delete _routes;
        delete _route_groups;
@@ -983,15 +981,11 @@ Editor::set_entered_track (TimeAxisView* tav)
 void
 Editor::instant_save ()
 {
-       if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
+       if (!constructed || !_session || no_save_instant) {
                return;
        }
 
-       if (_session) {
-               _session->add_instant_xml(get_state());
-       } else {
-               Config->add_instant_xml(get_state());
-       }
+       _session->add_instant_xml(get_state());
 }
 
 void
@@ -1148,10 +1142,13 @@ Editor::access_action (const std::string& action_group, const std::string& actio
        ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
 
        RefPtr<Action> act;
-       act = ActionManager::get_action (action_group.c_str(), action_item.c_str());
-
-       if (act) {
-               act->activate();
+       try {
+               act = ActionManager::get_action (action_group.c_str(), action_item.c_str());
+               if (act) {
+                       act->activate();
+               }
+       } catch ( ActionManager::MissingActionException const& e) {
+               cerr << "MissingActionException:" << e.what () << endl;
        }
 }
 
@@ -1611,22 +1608,6 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type,
        case RegionViewNameHighlight:
        case LeftFrameHandle:
        case RightFrameHandle:
-               if (!with_selection) {
-                       if (region_edit_menu_split_item) {
-                               if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
-                                       ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
-                               } else {
-                                       ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
-                               }
-                       }
-                       if (region_edit_menu_split_multichannel_item) {
-                               if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
-                                       region_edit_menu_split_multichannel_item->set_sensitive (true);
-                               } else {
-                                       region_edit_menu_split_multichannel_item->set_sensitive (false);
-                               }
-                       }
-               }
                break;
 
        case SelectionItem:
@@ -1713,9 +1694,6 @@ Editor::build_track_region_context_menu ()
        /* we've just cleared the track region context menu, so the menu that these
           two items were on will have disappeared; stop them dangling.
        */
-       region_edit_menu_split_item = 0;
-       region_edit_menu_split_multichannel_item = 0;
-
        RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
 
        if (rtv) {
@@ -2111,7 +2089,7 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
        edit_items.push_back (MenuElem (_("Select"), *select_menu));
 
        /* Cut-n-Paste */
-
+#if 0 // unused, why?
        Menu *cutnpaste_menu = manage (new Menu);
        MenuList& cutnpaste_items = cutnpaste_menu->items();
        cutnpaste_menu->set_name ("ArdourContextMenu");
@@ -2119,6 +2097,7 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
        cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
        cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
        cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
+#endif
 
        Menu *nudge_menu = manage (new Menu());
        MenuList& nudge_items = nudge_menu->items();
@@ -2206,6 +2185,54 @@ Editor::snap_mode() const
        return _snap_mode;
 }
 
+void
+Editor::show_rulers_for_grid ()
+{
+       /* show appropriate rulers for this grid setting. */
+       if (grid_musical()) {
+               ruler_tempo_action->set_active(true);
+               ruler_meter_action->set_active(true);
+               ruler_bbt_action->set_active(true);
+
+               if (UIConfiguration::instance().get_rulers_follow_grid()) {
+                       ruler_timecode_action->set_active(false);
+                       ruler_minsec_action->set_active(false);
+                       ruler_samples_action->set_active(false);
+               }
+       } else if (_grid_type == GridTypeTimecode) {
+               ruler_timecode_action->set_active(true);
+
+               if (UIConfiguration::instance().get_rulers_follow_grid()) {
+                       ruler_tempo_action->set_active(false);
+                       ruler_meter_action->set_active(false);
+                       ruler_bbt_action->set_active(false);
+                       ruler_minsec_action->set_active(false);
+                       ruler_samples_action->set_active(false);
+               }
+       } else if (_grid_type == GridTypeMinSec) {
+               ruler_minsec_action->set_active(true);
+
+               if (UIConfiguration::instance().get_rulers_follow_grid()) {
+                       ruler_tempo_action->set_active(false);
+                       ruler_meter_action->set_active(false);
+                       ruler_bbt_action->set_active(false);
+                       ruler_timecode_action->set_active(false);
+                       ruler_samples_action->set_active(false);
+               }
+       } else if (_grid_type == GridTypeCDFrame) {
+               ruler_cd_marker_action->set_active(true);
+               ruler_minsec_action->set_active(true);
+
+               if (UIConfiguration::instance().get_rulers_follow_grid()) {
+                       ruler_tempo_action->set_active(false);
+                       ruler_meter_action->set_active(false);
+                       ruler_bbt_action->set_active(false);
+                       ruler_timecode_action->set_active(false);
+                       ruler_samples_action->set_active(false);
+               }
+       }
+}
+
 void
 Editor::set_grid_to (GridType gt)
 {
@@ -2215,7 +2242,7 @@ Editor::set_grid_to (GridType gt)
 
        unsigned int grid_ind = (unsigned int)gt;
 
-       if (internal_editing()) {
+       if (internal_editing() && UIConfiguration::instance().get_grid_follows_internal()) {
                internal_grid_type = gt;
        } else {
                pre_internal_grid_type = gt;
@@ -2234,44 +2261,8 @@ Editor::set_grid_to (GridType gt)
                grid_type_selector.set_text (str);
        }
 
-       /* show appropriate rulers for this grid setting.
-        * TODO: perhaps make this optional.
-        * Currently this is 'required' because the RULER calculates the grid_marks which will be used by grid_lines
-        */
-       if (grid_musical()) {
-               ruler_tempo_action->set_active(true);
-               ruler_meter_action->set_active(true);
-
-               ruler_bbt_action->set_active(true);
-               ruler_timecode_action->set_active(false);
-               ruler_minsec_action->set_active(false);
-               ruler_samples_action->set_active(false);
-       } else if (_grid_type == GridTypeTimecode) {
-               ruler_tempo_action->set_active(false);
-               ruler_meter_action->set_active(false);
-
-               ruler_bbt_action->set_active(false);
-               ruler_timecode_action->set_active(true);
-               ruler_minsec_action->set_active(false);
-               ruler_samples_action->set_active(false);
-       } else if (_grid_type == GridTypeMinSec) {
-               ruler_tempo_action->set_active(false);
-               ruler_meter_action->set_active(false);
-
-               ruler_bbt_action->set_active(false);
-               ruler_timecode_action->set_active(false);
-               ruler_minsec_action->set_active(true);
-               ruler_samples_action->set_active(false);
-       } else if (_grid_type == GridTypeCDFrame) {
-               ruler_tempo_action->set_active(false);
-               ruler_meter_action->set_active(false);
-
-               ruler_bbt_action->set_active(false);
-               ruler_timecode_action->set_active(false);
-               ruler_minsec_action->set_active(true);
-
-               ruler_cd_marker_action->set_active(true);
-               ruler_samples_action->set_active(false);
+       if (UIConfiguration::instance().get_show_grids_ruler()) {
+               show_rulers_for_grid ();
        }
 
        instant_save ();
@@ -2311,12 +2302,15 @@ Editor::set_snap_mode (SnapMode mode)
 void
 Editor::set_edit_point_preference (EditPoint ep, bool force)
 {
+       if (Profile->get_mixbus()) {
+               if (ep == EditAtSelectedMarker) {
+                       ep = EditAtPlayhead;
+               }
+       }
+
        bool changed = (_edit_point != ep);
 
        _edit_point = ep;
-       if (Profile->get_mixbus())
-               if (ep == EditAtSelectedMarker)
-                       ep = EditAtPlayhead;
 
        string str = edit_point_strings[(int)ep];
        if (str != edit_point_selector.get_text ()) {
@@ -2336,17 +2330,15 @@ Editor::set_edit_point_preference (EditPoint ep, bool force)
                action = "edit-at-playhead";
                break;
        case EditAtSelectedMarker:
-               action = "edit-at-marker";
+               action = "edit-at-selected-marker";
                break;
        case EditAtMouse:
                action = "edit-at-mouse";
                break;
        }
 
-       Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
-       if (act) {
-               Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
-       }
+       Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("Editor", action);
+       tact->set_active (true);
 
        samplepos_t foo;
        bool in_track_canvas;
@@ -2444,13 +2436,13 @@ Editor::set_state (const XMLNode& node, int version)
                reset_y_origin (y_origin);
        }
 
-       if (node.get_property ("join-object-range", yn)) {
-               RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
-               if (act) {
-                       RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
-                       tact->set_active (!yn);
-                       tact->set_active (yn);
-               }
+       yn = false;
+       node.get_property ("join-object-range", yn);
+       {
+               RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
+               /* do it twice to force the change */
+               tact->set_active (!yn);
+               tact->set_active (yn);
                set_mouse_mode(mouse_mode, true);
        }
 
@@ -2474,28 +2466,20 @@ Editor::set_state (const XMLNode& node, int version)
                _regions->reset_sort_type (sort_type, true);
        }
 
-       if (node.get_property ("show-editor-mixer", yn)) {
-
-               Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
-               assert (act);
-
-               Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
-
+       yn = false;
+       node.get_property ("show-editor-mixer", yn);
+       {
+               Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-mixer"));
                /* do it twice to force the change */
-
                tact->set_active (!yn);
                tact->set_active (yn);
        }
 
-       if (node.get_property ("show-editor-list", yn)) {
-
-               Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
-               assert (act);
-
-               Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
-
+       yn = false;
+       node.get_property ("show-editor-list", yn);
+       {
+               Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list"));
                /* do it twice to force the change */
-
                tact->set_active (!yn);
                tact->set_active (yn);
        }
@@ -2505,11 +2489,11 @@ Editor::set_state (const XMLNode& node, int version)
                _the_notebook.set_current_page (el_page);
        }
 
-       if (node.get_property (X_("show-marker-lines"), yn)) {
-               Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
-               assert (act);
-               Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
-
+       yn = false;
+       node.get_property (X_("show-marker-lines"), yn);
+       {
+               Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-marker-lines"));
+               /* do it twice to force the change */
                tact->set_active (!yn);
                tact->set_active (yn);
        }
@@ -2522,10 +2506,8 @@ Editor::set_state (const XMLNode& node, int version)
        }
 
        if (node.get_property ("maximised", yn)) {
-               Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
-               assert (act);
-               Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
-               bool fs = tact && tact->get_active();
+               Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Common"), X_("ToggleMaximalEditor"));
+               bool fs = tact->get_active();
                if (yn ^ fs) {
                        ActionManager::do_action ("Common", "ToggleMaximalEditor");
                }
@@ -2544,28 +2526,22 @@ Editor::set_state (const XMLNode& node, int version)
                 * Not all properties may have been in XML, but
                 * those that are linked to a private variable may need changing
                 */
-               RefPtr<Action> act;
+               RefPtr<ToggleAction> tact;
 
-               act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
+               tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-follow-playhead"));
                yn = _follow_playhead;
-               if (act) {
-                       RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
-                       if (tact->get_active() != yn) {
-                               tact->set_active (yn);
-                       }
+               if (tact->get_active() != yn) {
+                       tact->set_active (yn);
                }
 
-               act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
+               tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead"));
                yn = _stationary_playhead;
-               if (act) {
-                       RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
-                       if (tact->get_active() != yn) {
-                               tact->set_active (yn);
-                       }
+               if (tact->get_active() != yn) {
+                       tact->set_active (yn);
                }
        }
 
-       return LuaInstance::instance()->set_state(node);
+       return 0;
 }
 
 XMLNode&
@@ -2606,17 +2582,11 @@ Editor::get_state ()
        node->set_property ("mouse-mode", mouse_mode);
        node->set_property ("join-object-range", smart_mode_action->get_active ());
 
-       Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
-       if (act) {
-               Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
-               node->set_property (X_("show-editor-mixer"), tact->get_active());
-       }
+       Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-mixer"));
+       node->set_property (X_("show-editor-mixer"), tact->get_active());
 
-       act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
-       if (act) {
-               Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
-               node->set_property (X_("show-editor-list"), tact->get_active());
-       }
+       tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list"));
+       node->set_property (X_("show-editor-list"), tact->get_active());
 
        node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
 
@@ -2633,8 +2603,6 @@ Editor::get_state ()
 
        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());
        node->add_child_nocopy (_locations->get_state ());
 
        return *node;
@@ -2686,7 +2654,7 @@ Editor::set_snapped_cursor_position (samplepos_t pos)
  *  @param event Event to get current key modifier information from, or 0.
  */
 void
-Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref, bool for_mark)
+Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref)
 {
        if (!_session || !event) {
                return;
@@ -2694,16 +2662,16 @@ Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, Round
 
        if (ArdourKeyboard::indicates_snap (event->button.state)) {
                if (_snap_mode == SnapOff) {
-                       snap_to_internal (start, direction, pref, for_mark);
+                       snap_to_internal (start, direction, pref);
                } else {
                        start.set (start.sample, 0);
                }
        } else {
                if (_snap_mode != SnapOff) {
-                       snap_to_internal (start, direction, pref, for_mark);
+                       snap_to_internal (start, direction, pref);
                } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
                        /* SnapOff, but we pressed the snap_delta modifier */
-                       snap_to_internal (start, direction, pref, for_mark);
+                       snap_to_internal (start, direction, pref);
                } else {
                        start.set (start.sample, 0);
                }
@@ -2711,14 +2679,14 @@ Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, Round
 }
 
 void
-Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
+Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
 {
        if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
                start.set (start.sample, 0);
                return;
        }
 
-       snap_to_internal (start, direction, pref, for_mark, ensure_snap);
+       snap_to_internal (start, direction, pref, ensure_snap);
 }
 
 void
@@ -2733,61 +2701,239 @@ check_best_snap (samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samp
        test = max_samplepos; // reset this so it doesn't get accidentally reused
 }
 
-samplepos_t
-Editor::snap_to_grid (vector<ArdourCanvas::Ruler::Mark> marks, samplepos_t presnap, RoundMode direction)
+MusicSample
+Editor::snap_to_timecode (MusicSample presnap, RoundMode direction, SnapPref gpref)
 {
-       if (marks.empty()) return presnap;
+       samplepos_t start = presnap.sample;
+       const samplepos_t one_timecode_second = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
+       samplepos_t one_timecode_minute = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
 
-       samplepos_t before;
-       samplepos_t after;
-       samplepos_t test = presnap;
+       TimecodeRulerScale scale = (gpref != SnapToGrid_Unscaled) ? timecode_ruler_scale : timecode_show_samples;
+
+       switch (scale) {
+       case timecode_show_bits:
+       case timecode_show_samples:
+               if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+                   fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
+                       /* start is already on a whole timecode frame, do nothing */
+               } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
+                       start = (samplepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
+               } else {
+                       start = (samplepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) *  _session->samples_per_timecode_frame());
+               }
+               break;
 
-       before = after = max_samplepos;
+       case timecode_show_seconds:
+               if (_session->config.get_timecode_offset_negative()) {
+                       start += _session->config.get_timecode_offset ();
+               } else {
+                       start -= _session->config.get_timecode_offset ();
+               }
+               if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+                   (start % one_timecode_second == 0)) {
+                       /* start is already on a whole second, do nothing */
+               } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
+                       start = (samplepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
+               } else {
+                       start = (samplepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
+               }
 
-       /* get marks to either side of presnap */
-       vector<ArdourCanvas::Ruler::Mark>::const_iterator m = marks.begin();
-       while (m != marks.end() && (m->position < presnap)) {
-               ++m;
-       }
+               if (_session->config.get_timecode_offset_negative()) {
+                       start -= _session->config.get_timecode_offset ();
+               } else {
+                       start += _session->config.get_timecode_offset ();
+               }
+               break;
 
-       if (m == marks.end ()) {
-               /* ran out of marks */
-               before = marks.back().position;
+       case timecode_show_minutes:
+       case timecode_show_hours:
+       case timecode_show_many_hours:
+               if (_session->config.get_timecode_offset_negative()) {
+                       start += _session->config.get_timecode_offset ();
+               } else {
+                       start -= _session->config.get_timecode_offset ();
+               }
+               if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+                   (start % one_timecode_minute == 0)) {
+                       /* start is already on a whole minute, do nothing */
+               } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
+                       start = (samplepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
+               } else {
+                       start = (samplepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
+               }
+               if (_session->config.get_timecode_offset_negative()) {
+                       start -= _session->config.get_timecode_offset ();
+               } else {
+                       start += _session->config.get_timecode_offset ();
+               }
+               break;
+       default:
+               fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
        }
 
-       after = m->position;
+       MusicSample ret(start,0);
+       return ret;
+}
 
-       if (m != marks.begin ()) {
-               --m;
-               before = m->position;
-       }
+MusicSample
+Editor::snap_to_minsec (MusicSample presnap, RoundMode direction, SnapPref gpref)
+{
+       MusicSample ret(presnap);
 
-       if (before == max_samplepos && after == max_samplepos) {
-               /* No grid to snap to, so just don't snap */
-               return presnap;
-       } else if (before == max_samplepos) {
-               test = after;
-       } else if (after == max_samplepos) {
-               test = before;
-       } else  {
-               if ((direction == RoundUpMaybe || direction == RoundUpAlways))
-                       test = after;
-               else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
-                       test = before;
-               else if (direction ==  0) {
-                       if ((presnap - before) < (after - presnap)) {
-                               test = before;
+       const samplepos_t one_second = _session->sample_rate();
+       const samplepos_t one_minute = one_second * 60;
+       const samplepos_t one_hour = one_minute * 60;
+
+       MinsecRulerScale scale = (gpref != SnapToGrid_Unscaled) ? minsec_ruler_scale : minsec_show_seconds;
+
+       switch (scale) {
+               case minsec_show_msecs:
+               case minsec_show_seconds: {
+                       if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+                               presnap.sample % one_second == 0) {
+                               /* start is already on a whole second, do nothing */
+                       } else if (((direction == 0) && (presnap.sample % one_second > one_second / 2)) || (direction > 0)) {
+                               ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_second) * one_second;
                        } else {
-                               test = after;
+                               ret.sample = (samplepos_t) floor ((double) presnap.sample / one_second) * one_second;
+                       }
+               } break;
+
+               case minsec_show_minutes: {
+                       if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+                               presnap.sample % one_minute == 0) {
+                               /* start is already on a whole minute, do nothing */
+                       } else if (((direction == 0) && (presnap.sample % one_minute > one_minute / 2)) || (direction > 0)) {
+                               ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_minute) * one_minute;
+                       } else {
+                               ret.sample = (samplepos_t) floor ((double) presnap.sample / one_minute) * one_minute;
                        }
+               } break;
+
+               default: {
+                       if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+                               presnap.sample % one_hour == 0) {
+                               /* start is already on a whole hour, do nothing */
+                       } else if (((direction == 0) && (presnap.sample % one_hour > one_hour / 2)) || (direction > 0)) {
+                               ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_hour) * one_hour;
+                       } else {
+                               ret.sample = (samplepos_t) floor ((double) presnap.sample / one_hour) * one_hour;
+                       }
+               } break;
+       }
+
+       return ret;
+}
+
+MusicSample
+Editor::snap_to_cd_frames (MusicSample presnap, RoundMode direction, SnapPref gpref)
+{
+       if ((gpref != SnapToGrid_Unscaled) && (minsec_ruler_scale != minsec_show_msecs)) {
+               return snap_to_minsec (presnap, direction, gpref);
+       }
+
+       const samplepos_t one_second = _session->sample_rate();
+
+       MusicSample ret(presnap);
+
+       if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+               presnap.sample % (one_second/75) == 0) {
+               /* start is already on a whole CD sample, do nothing */
+       } else if (((direction == 0) && (presnap.sample % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
+               ret.sample = (samplepos_t) ceil ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
+       } else {
+               ret.sample = (samplepos_t) floor ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
+       }
+
+       return ret;
+}
+
+MusicSample
+Editor::snap_to_bbt (MusicSample presnap, RoundMode direction, SnapPref gpref)
+{
+       MusicSample ret(presnap);
+
+       if (gpref != SnapToGrid_Unscaled) { // use the visual grid lines which are limited by the zoom scale that the user selected
+
+               int divisor = 2;
+               switch (_grid_type) {
+               case GridTypeBeatDiv3:
+               case GridTypeBeatDiv6:
+               case GridTypeBeatDiv12:
+               case GridTypeBeatDiv24:
+                       divisor = 3;
+                       break;
+               case GridTypeBeatDiv5:
+               case GridTypeBeatDiv10:
+               case GridTypeBeatDiv20:
+                       divisor = 5;
+                       break;
+               case GridTypeBeatDiv7:
+               case GridTypeBeatDiv14:
+               case GridTypeBeatDiv28:
+                       divisor = 7;
+                       break;
+               default:
+                       divisor = 2;
+               };
+
+               BBTRulerScale scale = bbt_ruler_scale;
+               switch (scale) {
+                       case bbt_show_many:
+                       case bbt_show_64:
+                       case bbt_show_16:
+                       case bbt_show_4:
+                       case bbt_show_1:
+                               ret = _session->tempo_map().round_to_bar (presnap.sample, direction);
+                               break;
+                       case bbt_show_quarters:
+                               ret = _session->tempo_map().round_to_beat (presnap.sample, direction);
+                               break;
+                       case bbt_show_eighths:
+                               ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 1 * divisor, direction);
+                               break;
+                       case bbt_show_sixteenths:
+                               ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 2 * divisor, direction);
+                               break;
+                       case bbt_show_thirtyseconds:
+                               ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 4 * divisor, direction);
+                               break;
                }
+       } else {
+               ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, get_grid_beat_divisions(_grid_type), direction);
        }
 
-       return test;
+       return ret;
+}
+
+ARDOUR::MusicSample
+Editor::snap_to_grid (MusicSample presnap, RoundMode direction, SnapPref gpref)
+{
+       MusicSample ret(presnap);
+
+       if (grid_musical()) {
+               ret = snap_to_bbt (presnap, direction, gpref);
+       }
+
+       switch (_grid_type) {
+               case GridTypeTimecode:
+                       ret = snap_to_timecode(presnap, direction, gpref);
+                       break;
+               case GridTypeMinSec:
+                       ret = snap_to_minsec(presnap, direction, gpref);
+                       break;
+               case GridTypeCDFrame:
+                       ret = snap_to_cd_frames(presnap, direction, gpref);
+                       break;
+               default:
+                       {}
+       };
+
+       return ret;
 }
 
 samplepos_t
-Editor::marker_snap_to_internal (samplepos_t presnap, RoundMode direction)
+Editor::snap_to_marker (samplepos_t presnap, RoundMode direction)
 {
        samplepos_t before;
        samplepos_t after;
@@ -2820,7 +2966,7 @@ Editor::marker_snap_to_internal (samplepos_t presnap, RoundMode direction)
 }
 
 void
-Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
+Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
 {
        const samplepos_t presnap = start.sample;
 
@@ -2829,41 +2975,37 @@ Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref
        samplepos_t best = max_samplepos; // this records the best snap-result we've found so far
 
        /* check snap-to-marker */
-       if (UIConfiguration::instance().get_snap_to_marks()) {
-               if (for_mark) {
-                       return;
-               }
-
-               test = marker_snap_to_internal (presnap, direction);
+       if ((pref == SnapToAny_Visual) && UIConfiguration::instance().get_snap_to_marks()) {
+               test = snap_to_marker (presnap, direction);
                check_best_snap(presnap, test, dist, best);
        }
 
        /* check snap-to-region-{start/end/sync} */
-       if (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync()) {
+       if (
+               (pref == SnapToAny_Visual) &&
+               (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync())
+               ) {
                if (!region_boundary_cache.empty()) {
 
-                       vector<samplepos_t>::iterator prev = region_boundary_cache.end ();
-                       vector<samplepos_t>::iterator next = region_boundary_cache.end ();
-
-                       if (direction > 0) {
-                               next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
-                       } else {
-                               next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
-                       }
-
+                       vector<samplepos_t>::iterator prev = region_boundary_cache.begin();
+                       vector<samplepos_t>::iterator next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
                        if (next != region_boundary_cache.begin ()) {
                                prev = next;
                                prev--;
                        }
 
-                       samplepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
-                       samplepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
-
-                       if (presnap > (p + n) / 2) {
-                               test = n;
-                       } else {
-                               test = p;
+                       if ((direction == RoundUpMaybe || direction == RoundUpAlways))
+                               test = *next;
+                       else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
+                               test = *prev;
+                       else if (direction ==  0) {
+                               if ((presnap - *prev) < (*next - presnap)) {
+                                       test = *prev;
+                               } else {
+                                       test = *next;
+                               }
                        }
+
                }
 
                check_best_snap(presnap, test, dist, best);
@@ -2871,8 +3013,9 @@ Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref
 
        /* check Grid */
        if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone)) {
-               test = snap_to_grid (grid_marks, presnap, direction);
-               check_best_snap(presnap, test, dist, best);
+               MusicSample pre(presnap, 0);
+               MusicSample post = snap_to_grid (pre, direction, pref);
+               check_best_snap(presnap, post.sample, dist, best);
        }
 
        /* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
@@ -2912,10 +3055,14 @@ Editor::setup_toolbar ()
        Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
        mouse_mode_size_group->add_widget (smart_mode_button);
        mouse_mode_size_group->add_widget (mouse_move_button);
-       mouse_mode_size_group->add_widget (mouse_cut_button);
+       if (!Profile->get_mixbus()) {
+               mouse_mode_size_group->add_widget (mouse_cut_button);
+       }
        mouse_mode_size_group->add_widget (mouse_select_button);
        mouse_mode_size_group->add_widget (mouse_timefx_button);
-       mouse_mode_size_group->add_widget (mouse_audition_button);
+       if (!Profile->get_mixbus()) {
+               mouse_mode_size_group->add_widget (mouse_audition_button);
+       }
        mouse_mode_size_group->add_widget (mouse_draw_button);
        mouse_mode_size_group->add_widget (mouse_content_button);
 
@@ -3197,8 +3344,6 @@ Editor::build_grid_type_menu ()
        grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeTimecode], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeTimecode)));
        grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
        grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeCDFrame)));
-
-       set_size_request_to_display_given_text (grid_type_selector, _("Long Grid"), COMBO_TRIANGLE_WIDTH, 2); // problem: some of the rarely-used grid names are very long.  Just do something arbitary, translators: rename this if needed
 }
 
 void
@@ -3897,11 +4042,8 @@ Editor::update_grid ()
 void
 Editor::toggle_follow_playhead ()
 {
-       RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
-       if (act) {
-               RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
-               set_follow_playhead (tact->get_active());
-       }
+       RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-follow-playhead"));
+       set_follow_playhead (tact->get_active());
 }
 
 /** @param yn true to follow playhead, otherwise false.
@@ -3922,11 +4064,8 @@ Editor::set_follow_playhead (bool yn, bool catch_up)
 void
 Editor::toggle_stationary_playhead ()
 {
-       RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
-       if (act) {
-               RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
-               set_stationary_playhead (tact->get_active());
-       }
+       RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead"));
+       set_stationary_playhead (tact->get_active());
 }
 
 void
@@ -3985,6 +4124,8 @@ Editor::get_grid_beat_divisions(samplepos_t position)
        case GridTypeBeatDiv4:   return 4;
        case GridTypeBeatDiv3:   return 3;
        case GridTypeBeatDiv2:   return 2;
+       case GridTypeBeat:       return 1;
+       case GridTypeBar:        return 1;
 
        case GridTypeNone:       return 0;
        case GridTypeTimecode:   return 0;
@@ -4238,7 +4379,7 @@ Editor::new_playlists (TimeAxisView* v)
 {
        begin_reversible_command (_("new playlists"));
        vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
-       _session->playlists->get (playlists);
+       _session->playlists()->get (playlists);
        mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
        commit_reversible_command ();
 }
@@ -4254,7 +4395,7 @@ Editor::copy_playlists (TimeAxisView* v)
 {
        begin_reversible_command (_("copy playlists"));
        vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
-       _session->playlists->get (playlists);
+       _session->playlists()->get (playlists);
        mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
        commit_reversible_command ();
 }
@@ -4269,7 +4410,7 @@ Editor::clear_playlists (TimeAxisView* v)
 {
        begin_reversible_command (_("clear playlists"));
        vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
-       _session->playlists->get (playlists);
+       _session->playlists()->get (playlists);
        mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
        commit_reversible_command ();
 }
@@ -4674,8 +4815,9 @@ Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_
 
        switch (ep) {
        case EditAtPlayhead:
-               if (_dragging_playhead && _control_scroll_target) {
-                       where = *_control_scroll_target;
+               if (_dragging_playhead) {
+                       /* NOTE: since the user is dragging with the mouse, this operation will implicitly be Snapped */
+                       where = playhead_cursor->current_sample();
                } else {
                        where = _session->audible_sample();
                }
@@ -5442,7 +5584,7 @@ Editor::timeaxisview_deleted (TimeAxisView *tv)
                         * button to inactive (which also unticks the menu option)
                         */
 
-                       ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
+                       ActionManager::uncheck_toggleaction ("Editor/show-editor-mixer");
                }
        }
 }
@@ -5753,7 +5895,7 @@ Editor::super_rapid_screen_update ()
                _last_update_time = 0;
        }
 
-       if (!_session->transport_rolling ()) {
+       if (!_session->transport_rolling () || _session->is_auditioning ()) {
                /* Do not interpolate the playhead position; just set it */
                _last_update_time = 0;
        }
@@ -5792,9 +5934,7 @@ Editor::super_rapid_screen_update ()
        if (!UIConfiguration::instance().get_show_snapped_cursor()) {
                snapped_cursor->hide ();
        } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
-               snap_to (where);  // can't use snap_to_with_modifier?
-               snapped_cursor->set_position (where.sample);
-               snapped_cursor->show ();
+               /* EditAtPlayhead does not snap */
        } else if (_edit_point == EditAtSelectedMarker) {
                /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
                 * however, the current editing code -does- snap so I'll draw it that way for now.
@@ -6166,6 +6306,11 @@ Editor::ui_parameter_changed (string parameter)
                if (_verbose_cursor) {
                        playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
                }
+       } else if (parameter == "use-note-bars-for-velocity") {
+               ArdourCanvas::Note::set_show_velocity_bars (UIConfiguration::instance().get_use_note_bars_for_velocity());
+               _track_canvas->request_redraw (_track_canvas->visible_area());
+       } else if (parameter == "use-note-color-for-velocity") {
+               /* handled individually by each MidiRegionView */
        }
 }