diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index b827ac0eb1..9ce693184a 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -335,6 +335,7 @@ Editor::Editor () , cd_mark_label (_("CD Markers")) , videotl_label (_("Video Timeline")) , videotl_group (0) + , snapped_cursor (0) , playhead_cursor (0) , edit_packer (4, 4, true) , vertical_adjustment (0.0, 0.0, 10.0, 400.0) @@ -367,7 +368,6 @@ Editor::Editor () , pending_keyboard_selection_start (0) , _snap_type (SnapToBeat) , _snap_mode (SnapOff) - , snap_threshold (5.0) , ignore_gui_changes (false) , _drags (new DragManager (this)) , lock_dialog (0) @@ -1406,8 +1406,13 @@ Editor::set_session (Session *t) _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context()); _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context()); + playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group()); playhead_cursor->show (); + snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group()); + snapped_cursor->set_color (UIConfiguration::instance().color ("edit point")); + snapped_cursor->show (); + boost::function pc (boost::bind (&Editor::parameter_changed, this, _1)); Config->map_parameters (pc); _session->config.map_parameters (pc); @@ -2287,6 +2292,7 @@ Editor::set_edit_point_preference (EditPoint ep, bool force) switch (_edit_point) { case EditAtPlayhead: +//ToDo: hide or show mouse_cursor action = "edit-at-playhead"; break; case EditAtSelectedMarker: @@ -2637,6 +2643,15 @@ Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const return std::make_pair ( (TimeAxisView *) 0, 0); } +void +Editor::set_snapped_cursor_position (samplepos_t pos) +{ + if ( _edit_point == EditAtMouse ) { + snapped_cursor->set_position(pos); + } +} + + /** Snap a position to the grid, if appropriate, taking into account current * grid settings and also the state of any snap modifier keys that may be pressed. * @param start Position to snap. @@ -2756,6 +2771,8 @@ Editor::snap_to_internal (MusicSample& start, RoundMode direction, bool for_mark samplepos_t before; samplepos_t after; + int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold()); + switch (_snap_type) { case SnapToTimecodeFrame: case SnapToTimecodeSeconds: @@ -2942,12 +2959,12 @@ Editor::snap_to_internal (MusicSample& start, RoundMode direction, bool for_mark } if (presnap > start.sample) { - if (presnap > (start.sample + pixel_to_sample(snap_threshold))) { + if (presnap > (start.sample + snap_threshold_s)) { start.set (presnap, 0); } } else if (presnap < start.sample) { - if (presnap < (start.sample - pixel_to_sample(snap_threshold))) { + if (presnap < (start.sample - snap_threshold_s)) { start.set (presnap, 0); } } @@ -5797,27 +5814,6 @@ Editor::super_rapid_screen_update () current_mixer_strip->fast_update (); } - /* PLAYHEAD AND VIEWPORT */ - - /* 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 - * when the editor requests a locate there is a chance that this method - * will move the playhead before the locate request is processed, causing - * a visual glitch. - * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere). - * 3. if we're still at the same sample that we were last time, there's nothing to do. - */ - if (_pending_locate_request || !_session->transport_rolling ()) { - _last_update_time = 0; - return; - } - - if (_dragging_playhead) { - _last_update_time = 0; - return; - } - bool latent_locate = false; samplepos_t sample = _session->audible_sample (&latent_locate); const int64_t now = g_get_monotonic_time (); @@ -5857,6 +5853,47 @@ Editor::super_rapid_screen_update () } else { _last_update_time = now; } + + //snapped cursor stuff ( the snapped_cursor shows where an operation is going to occur ) + bool ignored; + MusicSample where (sample, 0); + 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 (); + } 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. + MusicSample ms (selection->markers.front()->position(), 0); + snap_to (ms); // should use snap_to_with_modifier? + snapped_cursor->set_position ( ms.sample ); + snapped_cursor->show (); + } else if (mouse_sample (where.sample, ignored)) { //cursor is in the editing canvas. show it. + snapped_cursor->show (); + } else { //mouse is out of the editing canvas. hide the snapped_cursor + snapped_cursor->hide (); + } + + /* 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 + * when the editor requests a locate there is a chance that this method + * will move the playhead before the locate request is processed, causing + * a visual glitch. + * 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) { + _last_update_time = 0; + return; + } + + if (_dragging_playhead) { + _last_update_time = 0; + return; + } if (playhead_cursor->current_sample () == sample) { return; diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 498a4e0fe0..5829927d1a 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -169,7 +169,6 @@ public: void prev_snap_choice_music_and_time (); void set_snap_to (Editing::SnapType); void set_snap_mode (Editing::SnapMode); - void set_snap_threshold (double pixel_distance) {snap_threshold = pixel_distance;} Editing::SnapMode snap_mode () const; Editing::SnapType snap_type () const; @@ -472,6 +471,8 @@ public: ARDOUR::RoundMode direction = ARDOUR::RoundNearest, bool for_mark = false); + void set_snapped_cursor_position (samplepos_t pos); + void begin_selection_op_history (); void begin_reversible_selection_op (std::string cmd_name); void commit_reversible_selection_op (); @@ -533,6 +534,7 @@ public: ArdourCanvas::ScrollGroup* get_hscroll_group () const { return h_scroll_group; } ArdourCanvas::ScrollGroup* get_hvscroll_group () const { return hv_scroll_group; } ArdourCanvas::ScrollGroup* get_cursor_scroll_group () const { return cursor_scroll_group; } + ArdourCanvas::Container* get_drag_motion_group () const { return _drag_motion_group; } ArdourCanvas::GtkCanvasViewport* get_track_canvas () const; @@ -1032,6 +1034,8 @@ private: friend class EditorCursor; + EditorCursor* snapped_cursor; + EditorCursor* playhead_cursor; samplepos_t playhead_cursor_sample () const; @@ -1529,9 +1533,6 @@ private: Editing::SnapType _snap_type; Editing::SnapMode _snap_mode; - /// Snap threshold in pixels - double snap_threshold; - bool ignore_gui_changes; DragManager* _drags; diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc index 5aeed49f43..a60d3eab9c 100644 --- a/gtk2_ardour/editor_canvas.cc +++ b/gtk2_ardour/editor_canvas.cc @@ -217,6 +217,8 @@ Editor::initialize_canvas () playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event); + snapped_cursor = new EditorCursor (*this); + _canvas_drop_zone = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 0.0)); /* this thing is transparent */ _canvas_drop_zone->set_fill (false); diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 9d36b28e1b..0dab9d8d0f 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -719,6 +719,8 @@ RegionMotionDrag::compute_x_delta (GdkEvent const * event, MusicSample* pending_ } } + _editor->set_snapped_cursor_position(pending_region_position->sample); + return dx; } @@ -3320,6 +3322,7 @@ MeterMarkerDrag::motion (GdkEvent* event, bool first_move) _marker->set_position (adjusted_current_sample (event, false)); show_verbose_cursor_time (_real_section->sample()); + _editor->set_snapped_cursor_position(_real_section->sample()); } void @@ -3485,6 +3488,7 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move) map.gui_set_tempo_position (_real_section, pf, sub_num); show_verbose_cursor_time (_real_section->sample()); + _editor->set_snapped_cursor_position(_real_section->sample()); } _marker->set_position (adjusted_current_sample (event, false)); } @@ -4609,6 +4613,7 @@ MarkerDrag::motion (GdkEvent* event, bool) assert (!_copied_locations.empty()); show_verbose_cursor_time (newframe); + _editor->set_snapped_cursor_position(newframe); } void @@ -6144,6 +6149,8 @@ NoteDrag::motion (GdkEvent * event, bool first_move) uint8_t new_note = min (max (_primary->note()->note() + note_delta, 0), 127); _region->show_verbose_cursor_for_new_note_value (_primary->note(), new_note); + + _editor->set_snapped_cursor_position( _region->source_beats_to_absolute_samples(_primary->note()->time()) ); } } } @@ -6956,16 +6963,11 @@ CrossfadeEdgeDrag::aborted (bool) RegionCutDrag::RegionCutDrag (Editor* e, ArdourCanvas::Item* item, samplepos_t pos) : Drag (e, item, true) - , line (new EditorCursor (*e)) { - line->set_position (pos); - line->show (); - line->track_canvas_item().reparent (_editor->_drag_motion_group); } RegionCutDrag::~RegionCutDrag () { - delete line; } void @@ -6978,10 +6980,6 @@ RegionCutDrag::start_grab (GdkEvent* event, Gdk::Cursor* c) void RegionCutDrag::motion (GdkEvent* event, bool) { - MusicSample pos (_drags->current_pointer_sample(), 0); - _editor->snap_to_with_modifier (pos, event); - - line->set_position (pos.sample); } void @@ -6992,7 +6990,6 @@ RegionCutDrag::finished (GdkEvent* event, bool) MusicSample pos (_drags->current_pointer_sample(), 0); _editor->snap_to_with_modifier (pos, event); - line->hide (); RegionSelection rs = _editor->get_regions_from_selection_and_mouse (pos.sample); diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index 53006676be..3dde8d80ad 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -511,7 +511,6 @@ public: void aborted (bool); private: - EditorCursor* line; }; /** Drags to create regions */ diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 2509889853..bb8b2accae 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -2078,6 +2078,15 @@ Editor::motion_handler (ArdourCanvas::Item* /*item*/, GdkEvent* event, bool from update_join_object_range_location (event->motion.y); + //snapped_cursor stuff ( the snapped_cursor shows where an operation is going to occur ) + bool ignored; + MusicSample where (0, 0); + if (mouse_sample (where.sample, ignored)) { + snap_to_with_modifier (where, event); + set_snapped_cursor_position (where.sample); + } + + //drags might also change the snapped_cursor location, because we are snapping the thing being dragged, not the actual mouse cursor if (_drags->active ()) { return _drags->motion_handler (event, from_autoscroll); } diff --git a/gtk2_ardour/luainstance.cc b/gtk2_ardour/luainstance.cc index 361b1e238c..9fe03ea077 100644 --- a/gtk2_ardour/luainstance.cc +++ b/gtk2_ardour/luainstance.cc @@ -837,7 +837,6 @@ LuaInstance::register_classes (lua_State* L) .addFunction ("snap_type", &PublicEditor::snap_type) .addFunction ("snap_mode", &PublicEditor::snap_mode) .addFunction ("set_snap_mode", &PublicEditor::set_snap_mode) - .addFunction ("set_snap_threshold", &PublicEditor::set_snap_threshold) .addFunction ("undo", &PublicEditor::undo) .addFunction ("redo", &PublicEditor::redo) diff --git a/gtk2_ardour/marker.cc b/gtk2_ardour/marker.cc index 29acc70e5d..a5084bf2c9 100644 --- a/gtk2_ardour/marker.cc +++ b/gtk2_ardour/marker.cc @@ -348,7 +348,6 @@ ArdourMarker::setup_line () if (_track_canvas_line == 0) { _track_canvas_line = new ArdourCanvas::Line (editor.get_hscroll_group()); - _track_canvas_line->set_outline_color (UIConfiguration::instance().color ("edit point")); _track_canvas_line->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_marker_event), group, this)); } @@ -359,7 +358,7 @@ ArdourMarker::setup_line () _track_canvas_line->set_x1 (d.x); _track_canvas_line->set_y0 (d.y); _track_canvas_line->set_y1 (ArdourCanvas::COORD_MAX); - _track_canvas_line->set_outline_color (_selected ? UIConfiguration::instance().color ("edit point") : _color); + _track_canvas_line->set_outline_color ( _selected ? UIConfiguration::instance().color ("entered marker") : _color ); _track_canvas_line->raise_to_top (); _track_canvas_line->show (); diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 4a19a6697a..53b42b27f2 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -347,6 +347,9 @@ MidiRegionView::canvas_group_event(GdkEvent* ev) return RegionView::canvas_group_event (ev); } + //For now, move the snapped cursor aside so it doesn't bother you during internal editing + //trackview.editor().set_snapped_cursor_position(_region->position()); + bool r; switch (ev->type) { @@ -3035,6 +3038,7 @@ MidiRegionView::update_resizing (NoteBase* primary, bool at_front, double delta_ } else { snapped_x = trackview.editor ().pixel_to_sample (current_x); } + const Temporal::Beats beats = Temporal::Beats (tmap.exact_beat_at_sample (snapped_x + midi_region()->position(), divisions) - midi_region()->beat()) + midi_region()->start_beats(); @@ -3058,6 +3062,8 @@ MidiRegionView::update_resizing (NoteBase* primary, bool at_front, double delta_ show_verbose_cursor (buf, 0, 0); cursor_set = true; + + trackview.editor().set_snapped_cursor_position ( snapped_x + midi_region()->position() ); } } diff --git a/gtk2_ardour/mini_timeline.cc b/gtk2_ardour/mini_timeline.cc index 9d7dc61d73..b4652583ca 100644 --- a/gtk2_ardour/mini_timeline.cc +++ b/gtk2_ardour/mini_timeline.cc @@ -151,6 +151,7 @@ void MiniTimeline::set_colors () { // TODO UIConfiguration::instance().color & font + _phead_color = UIConfiguration::instance().color ("play head"); } void @@ -648,7 +649,8 @@ MiniTimeline::render (Cairo::RefPtr const& ctx, cairo_rectangle_ /* playhead on top */ int xc = width * 0.5f; cairo_set_line_width (cr, 1.0); - cairo_set_source_rgb (cr, 1, 0, 0); // playhead color + double r,g,b,a; Gtkmm2ext::color_to_rgba(_phead_color, r,g,b,a); + cairo_set_source_rgb (cr, r,g,b); // playhead color cairo_move_to (cr, xc - .5, 0); cairo_rel_line_to (cr, 0, height); cairo_stroke (cr); diff --git a/gtk2_ardour/mini_timeline.h b/gtk2_ardour/mini_timeline.h index 21b316df39..b0cb5ee8cd 100644 --- a/gtk2_ardour/mini_timeline.h +++ b/gtk2_ardour/mini_timeline.h @@ -101,6 +101,8 @@ private: Gtk::Menu* _minitl_context_menu; + uint32_t _phead_color; + struct JumpRange { JumpRange (int l, int r, samplepos_t t, bool p = false) : left (l), right (r), to (t), prelight (p) {} diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index 9fbdb106bc..6df7777818 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -143,11 +143,6 @@ public: */ virtual void set_snap_mode (Editing::SnapMode m) = 0; - /** Set the snap threshold. - * @param t Snap threshold in `units'. - */ - virtual void set_snap_threshold (double t) = 0; - /** * Snap a value according to the current snap setting. * ensure_snap overrides SnapOff and magnetic snap @@ -426,6 +421,7 @@ public: virtual ArdourCanvas::ScrollGroup* get_hscroll_group () const = 0; virtual ArdourCanvas::ScrollGroup* get_hvscroll_group () const = 0; virtual ArdourCanvas::ScrollGroup* get_cursor_scroll_group () const = 0; + virtual ArdourCanvas::Container* get_drag_motion_group () const = 0; virtual ArdourCanvas::GtkCanvasViewport* get_track_canvas() const = 0; @@ -467,6 +463,8 @@ public: ARDOUR::RoundMode direction = ARDOUR::RoundNearest, bool for_mark = false) = 0; + virtual void set_snapped_cursor_position (samplepos_t pos) = 0; + virtual void get_regions_at (RegionSelection &, samplepos_t where, TrackViewList const &) const = 0; virtual void get_regions_after (RegionSelection&, samplepos_t where, const TrackViewList& ts) const = 0; virtual RegionSelection get_regions_from_selection_and_mouse (samplepos_t) = 0; diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc index bef5780fad..ce099883fe 100644 --- a/gtk2_ardour/rc_option_editor.cc +++ b/gtk2_ardour/rc_option_editor.cc @@ -2490,6 +2490,26 @@ RCOptionEditor::RCOptionEditor () add_option (_("Editor"), rsas); + add_option (_("Editor/Snap"), new OptionEditorHeading (_("General Snap options:"))); + + add_option (_("Editor/Snap"), + new SpinOption ( + "snap-threshold", + _("Snap Threshold (pixels)"), + sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_snap_threshold), + sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_snap_threshold), + 10, 200, + 1, 10 + )); + + add_option (_("Editor/Snap"), + new BoolOption ( + "show-snapped-cursor", + _("Show Snapped Cursor"), + sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_snapped_cursor), + sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_snapped_cursor) + )); + add_option (_("Editor/Modifiers"), new OptionEditorHeading (_("Keyboard Modifiers"))); add_option (_("Editor/Modifiers"), new KeyboardOptions); add_option (_("Editor/Modifiers"), new OptionEditorBlank ()); diff --git a/gtk2_ardour/ui_config_vars.h b/gtk2_ardour/ui_config_vars.h index 50960d70bf..f4b516495c 100644 --- a/gtk2_ardour/ui_config_vars.h +++ b/gtk2_ardour/ui_config_vars.h @@ -100,3 +100,6 @@ UI_CONFIG_VARIABLE (bool, prefer_inline_over_gui, "prefer-inline-over-gui", true UI_CONFIG_VARIABLE (uint32_t, action_table_columns, "action-table-columns", 0) UI_CONFIG_VARIABLE (bool, use_wm_visibility, "use-wm-visibility", true) UI_CONFIG_VARIABLE (std::string, stripable_color_palette, "stripable-color-palette", "#AA3939:#FFAAAA:#D46A6A:#801515:#550000:#AA8E39:#FFEAAA:#D4BA6A:#806515:#554000:#343477:#8080B3:#565695:#1A1A59:#09093B:#2D882D:#88CC88:#55AA55:#116611:#004400") /* Gtk::ColorSelection::palette_to_string */ + +UI_CONFIG_VARIABLE (bool, show_snapped_cursor, "show-snapped-cursor", true) +UI_CONFIG_VARIABLE (uint32_t, snap_threshold, "snap-threshold", 25)