X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_drag.cc;h=02f827b5792874ffada6eb70dc335899c2aa514e;hb=0e9dab6aabc2efddc957c7c71bc55354c16626ed;hp=3787db10a806dc6ac87d8234618fb9f543c8640a;hpb=211226983df8e46e8849dd0aeca422b89d3d4d79;p=ardour.git diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 3787db10a8..02f827b579 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -40,6 +40,7 @@ #include "ardour/profile.h" #include "ardour/region_factory.h" #include "ardour/session.h" +#include "ardour/session_playlists.h" #include "canvas/canvas.h" #include "canvas/scroll_group.h" @@ -545,9 +546,11 @@ Drag::add_midi_region (MidiTimeAxisView* view, bool commit) return boost::shared_ptr(); } -struct PresentationInfoTimeAxisViewSorter { - bool operator() (TimeAxisView* a, TimeAxisView* b) { - return a->stripable()->presentation_info().order() < b->stripable()->presentation_info().order(); +struct TimeAxisViewStripableSorter { + bool operator() (TimeAxisView* tav_a, TimeAxisView* tav_b) { + boost::shared_ptr const& a = tav_a->stripable (); + boost::shared_ptr const& b = tav_b->stripable (); + return ARDOUR::Stripable::Sorter () (a, b); } }; @@ -563,7 +566,7 @@ RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, listtrack_views; - track_views.sort (PresentationInfoTimeAxisViewSorter ()); + track_views.sort (TimeAxisViewStripableSorter ()); for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { _time_axis_views.push_back (*i); @@ -662,6 +665,11 @@ RegionMotionDrag::compute_x_delta (GdkEvent const * event, MusicFrame* pending_r /* compute the amount of pointer motion in frames, and where the region would be if we moved it by that much. */ + if (_x_constrained) { + *pending_region_position = _last_position; + return 0.0; + } + *pending_region_position = adjusted_frame (_drags->current_pointer_frame (), event, false); framecnt_t sync_offset; @@ -1437,7 +1445,7 @@ RegionMoveDrag::create_destination_time_axis (boost::shared_ptr region, output_chan = _editor->session()->master_out()->n_inputs().n_audio(); } audio_tracks = _editor->session()->new_audio_track (region->n_channels(), output_chan, 0, 1, region->name(), PresentationInfo::max_order); - tav =_editor->axis_view_from_stripable (audio_tracks.front()); + tav =_editor->time_axis_view_from_stripable (audio_tracks.front()); } else { ChanCount one_midi_port (DataType::MIDI, 1); list > midi_tracks; @@ -1446,7 +1454,7 @@ RegionMoveDrag::create_destination_time_axis (boost::shared_ptr region, boost::shared_ptr(), (ARDOUR::Plugin::PresetRecord*) 0, (ARDOUR::RouteGroup*) 0, 1, region->name(), PresentationInfo::max_order); - tav = _editor->axis_view_from_stripable (midi_tracks.front()); + tav = _editor->time_axis_view_from_stripable (midi_tracks.front()); } if (tav) { @@ -1586,7 +1594,7 @@ RegionMoveDrag::finished_no_copy ( PlaylistSet frozen_playlists; set views_to_update; RouteTimeAxisView* new_time_axis_view = 0; - framecnt_t const drag_delta = _primary->region()->position() - _last_position.frame; + framecnt_t const drag_delta = _primary->region()->position() - last_position.frame; typedef map, RouteTimeAxisView*> PlaylistMapping; PlaylistMapping playlist_mapping; @@ -2420,14 +2428,16 @@ RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisVi void RegionCreateDrag::motion (GdkEvent* event, bool first_move) { + if (first_move) { _editor->begin_reversible_command (_("create region")); _region = add_midi_region (_view, false); _view->playlist()->freeze (); } else { + if (_region) { framepos_t const f = adjusted_current_frame (event); - if (f < grab_frame()) { + if (f <= grab_frame()) { _region->set_initial_position (f); } @@ -2437,9 +2447,10 @@ RegionCreateDrag::motion (GdkEvent* event, bool first_move) a bit confusing as if a region starts 1 frame after a snap point, one cannot place snapped notes at the start of the region. */ - - framecnt_t const len = (framecnt_t) fabs ((double)(f - grab_frame () - 1)); - _region->set_length (len < 1 ? 1 : len, _editor->get_grid_music_divisions (event->button.state)); + if (f != grab_frame()) { + framecnt_t const len = (framecnt_t) fabs ((double)(f - grab_frame () - 1)); + _region->set_length (len < 1 ? 1 : len, _editor->get_grid_music_divisions (event->button.state)); + } } } } @@ -2988,6 +2999,24 @@ TrimDrag::motion (GdkEvent* event, bool first_move) if (insert_result.second) { pl->freeze(); } + + MidiRegionView* const mrv = dynamic_cast (rv); + /* a MRV start trim may change the source length. ensure we cover all playlists here */ + if (mrv && _operation == StartTrim) { + vector > all_playlists; + _editor->session()->playlists->get (all_playlists); + for (vector >::iterator x = all_playlists.begin(); x != all_playlists.end(); ++x) { + + if ((*x)->uses_source (rv->region()->source(0))) { + insert_result = _editor->motion_frozen_playlists.insert (*x); + if (insert_result.second) { + (*x)->clear_owned_changes (); + (*x)->freeze(); + } + + } + } + } } } @@ -3136,29 +3165,22 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred) if (!_editor->selection->selected (_primary)) { _primary->thaw_after_trim (); } else { - - set > diffed_playlists; - for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { i->view->thaw_after_trim (); i->view->enable_display (true); - - /* Trimming one region may affect others on the playlist, so we need - to get undo Commands from the whole playlist rather than just the - region. Use diffed_playlists to make sure we don't diff a given - playlist more than once. - */ - boost::shared_ptr p = i->view->region()->playlist (); - if (diffed_playlists.find (p) == diffed_playlists.end()) { - vector cmds; - p->rdiff (cmds); - _editor->session()->add_commands (cmds); - diffed_playlists.insert (p); - } } } for (set >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) { + /* Trimming one region may affect others on the playlist, so we need + to get undo Commands from the whole playlist rather than just the + region. Use motion_frozen_playlists (a set) to make sure we don't + diff a given playlist more than once. + */ + + vector cmds; + (*p)->rdiff (cmds); + _editor->session()->add_commands (cmds); (*p)->thaw (); } @@ -3286,10 +3308,9 @@ MeterMarkerDrag::motion (GdkEvent* event, bool first_move) } else { --bbt.bars; } - const double beat = map.beat_at_bbt (bbt); - const framepos_t frame = map.frame_at_beat (beat); + const framepos_t frame = map.frame_at_bbt (bbt); _real_section = map.add_meter (Meter (_marker->meter().divisions_per_bar(), _marker->meter().note_divisor()) - , beat, bbt, frame, _real_section->position_lock_style()); + , bbt, frame, _real_section->position_lock_style()); if (!_real_section) { aborted (true); return; @@ -3364,7 +3385,7 @@ TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c) , _copy (c) , _grab_bpm (120.0, 4.0) , _grab_qn (0.0) - , before_state (0) + , _before_state (0) { DEBUG_TRACE (DEBUG::Drags, "New TempoMarkerDrag\n"); @@ -3423,7 +3444,7 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move) _marker->hide(); /* get current state */ - before_state = &map.get_state(); + _before_state = &map.get_state(); if (!_copy) { _editor->begin_reversible_command (_("move tempo mark")); @@ -3451,7 +3472,7 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move) if (ArdourKeyboard::indicates_constraint (event->button.state) && ArdourKeyboard::indicates_copy (event->button.state)) { double new_bpm = max (1.5, _grab_bpm.end_note_types_per_minute() + ((grab_y() - min (-1.0, current_pointer_y())) / 5.0)); stringstream strs; - _editor->session()->tempo_map().gui_change_tempo (_real_section, Tempo (new_bpm, _real_section->note_type()), true); + _editor->session()->tempo_map().gui_change_tempo (_real_section, Tempo (_real_section->note_types_per_minute(), _real_section->note_type(), new_bpm)); strs << "end:" << fixed << setprecision(3) << new_bpm; show_verbose_cursor_text (strs.str()); @@ -3459,7 +3480,7 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move) /* use vertical movement to alter tempo .. should be log */ double new_bpm = max (1.5, _grab_bpm.note_types_per_minute() + ((grab_y() - min (-1.0, current_pointer_y())) / 5.0)); stringstream strs; - _editor->session()->tempo_map().gui_change_tempo (_real_section, Tempo (new_bpm, _real_section->note_type()), false); + _editor->session()->tempo_map().gui_change_tempo (_real_section, Tempo (new_bpm, _real_section->note_type(), _real_section->end_note_types_per_minute())); strs << "start:" << fixed << setprecision(3) << new_bpm; show_verbose_cursor_text (strs.str()); @@ -3501,7 +3522,7 @@ TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred) TempoMap& map (_editor->session()->tempo_map()); XMLNode &after = map.get_state(); - _editor->session()->add_command (new MementoCommand(map, before_state, &after)); + _editor->session()->add_command (new MementoCommand(map, _before_state, &after)); _editor->commit_reversible_command (); // delete the dummy marker we used for visual representation while moving. @@ -3515,7 +3536,7 @@ TempoMarkerDrag::aborted (bool moved) _marker->set_position (_marker->tempo().frame()); if (moved) { TempoMap& map (_editor->session()->tempo_map()); - map.set_state (*before_state, Stateful::current_state_version); + map.set_state (*_before_state, Stateful::current_state_version); // delete the dummy (hidden) marker we used for events while moving. delete _marker; } @@ -3525,7 +3546,8 @@ BBTRulerDrag::BBTRulerDrag (Editor* e, ArdourCanvas::Item* i) : Drag (e, i) , _grab_qn (0.0) , _tempo (0) - , before_state (0) + , _before_state (0) + , _drag_valid (true) { DEBUG_TRACE (DEBUG::Drags, "New BBTRulerDrag\n"); @@ -3537,10 +3559,23 @@ BBTRulerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) Drag::start_grab (event, cursor); TempoMap& map (_editor->session()->tempo_map()); _tempo = const_cast (&map.tempo_section_at_frame (raw_grab_frame())); + + if (adjusted_current_frame (event, false) <= _tempo->frame()) { + _drag_valid = false; + return; + } + + _editor->tempo_curve_selected (_tempo, true); + ostringstream sstr; + if (_tempo->clamped()) { + TempoSection* prev = map.previous_tempo_section (_tempo); + if (prev) { + sstr << "end: " << fixed << setprecision(3) << prev->end_note_types_per_minute() << "\n"; + } + } - sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute() << "\n"; - sstr << "mouse: " << fixed << setprecision(3) << map.tempo_at_frame (adjusted_current_frame (event)).note_types_per_minute(); + sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute(); show_verbose_cursor_text (sstr.str()); } @@ -3548,6 +3583,9 @@ void BBTRulerDrag::setup_pointer_frame_offset () { TempoMap& map (_editor->session()->tempo_map()); + /* get current state */ + _before_state = &map.get_state(); + const double beat_at_frame = max (0.0, map.beat_at_frame (raw_grab_frame())); const uint32_t divisions = _editor->get_grid_beat_divisions (0); double beat = 0.0; @@ -3571,14 +3609,15 @@ BBTRulerDrag::setup_pointer_frame_offset () void BBTRulerDrag::motion (GdkEvent* event, bool first_move) { - TempoMap& map (_editor->session()->tempo_map()); + if (!_drag_valid) { + return; + } if (first_move) { - /* get current state */ - before_state = &map.get_state(); _editor->begin_reversible_command (_("stretch tempo")); } + TempoMap& map (_editor->session()->tempo_map()); framepos_t pf; if (_editor->snap_musical()) { @@ -3589,11 +3628,18 @@ BBTRulerDrag::motion (GdkEvent* event, bool first_move) if (ArdourKeyboard::indicates_constraint (event->button.state)) { /* adjust previous tempo to match pointer frame */ - _editor->session()->tempo_map().gui_stretch_tempo (_tempo, map.frame_at_quarter_note (_grab_qn), pf); + _editor->session()->tempo_map().gui_stretch_tempo (_tempo, map.frame_at_quarter_note (_grab_qn), pf, _grab_qn, map.quarter_note_at_frame (pf)); } + ostringstream sstr; - sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute() << "\n"; - sstr << "mouse: " << fixed << setprecision(3) << map.tempo_at_frame (pf).note_types_per_minute(); + if (_tempo->clamped()) { + TempoSection* prev = map.previous_tempo_section (_tempo); + if (prev) { + _editor->tempo_curve_selected (prev, true); + sstr << "end: " << fixed << setprecision(3) << prev->end_note_types_per_minute() << "\n"; + } + } + sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute(); show_verbose_cursor_text (sstr.str()); } @@ -3606,16 +3652,29 @@ BBTRulerDrag::finished (GdkEvent* event, bool movement_occurred) TempoMap& map (_editor->session()->tempo_map()); + _editor->tempo_curve_selected (_tempo, false); + if (_tempo->clamped()) { + TempoSection* prev_tempo = map.previous_tempo_section (_tempo); + if (prev_tempo) { + _editor->tempo_curve_selected (prev_tempo, false); + } + } + + if (!movement_occurred || !_drag_valid) { + return; + } + XMLNode &after = map.get_state(); - _editor->session()->add_command(new MementoCommand(map, before_state, &after)); + _editor->session()->add_command(new MementoCommand(map, _before_state, &after)); _editor->commit_reversible_command (); + } void BBTRulerDrag::aborted (bool moved) { if (moved) { - _editor->session()->tempo_map().set_state (*before_state, Stateful::current_state_version); + _editor->session()->tempo_map().set_state (*_before_state, Stateful::current_state_version); } } @@ -3624,7 +3683,9 @@ TempoTwistDrag::TempoTwistDrag (Editor* e, ArdourCanvas::Item* i) , _grab_qn (0.0) , _grab_tempo (0.0) , _tempo (0) - , before_state (0) + , _next_tempo (0) + , _drag_valid (true) + , _before_state (0) { DEBUG_TRACE (DEBUG::Drags, "New TempoTwistDrag\n"); @@ -3635,13 +3696,36 @@ TempoTwistDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) { Drag::start_grab (event, cursor); TempoMap& map (_editor->session()->tempo_map()); + /* get current state */ + _before_state = &map.get_state(); _tempo = const_cast (&map.tempo_section_at_frame (raw_grab_frame())); - _grab_tempo = Tempo (_tempo->note_types_per_minute(), _tempo->note_type()); - ostringstream sstr; - sstr << "<" << fixed << setprecision(3) << _tempo->note_types_per_minute() << "\n"; - sstr << ">" << fixed << setprecision(3) << _tempo->end_note_types_per_minute(); - show_verbose_cursor_text (sstr.str()); + if (_tempo->locked_to_meter()) { + _drag_valid = false; + return; + } + + _next_tempo = map.next_tempo_section (_tempo); + if (_next_tempo) { + if (!map.next_tempo_section (_next_tempo)) { + _drag_valid = false; + finished (event, false); + + return; + } + _editor->tempo_curve_selected (_tempo, true); + _editor->tempo_curve_selected (_next_tempo, true); + + ostringstream sstr; + sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute() << "\n"; + sstr << "end: " << fixed << setprecision(3) << _tempo->end_note_types_per_minute() << "\n"; + sstr << "start: " << fixed << setprecision(3) << _next_tempo->note_types_per_minute(); + show_verbose_cursor_text (sstr.str()); + } else { + _drag_valid = false; + } + + _grab_tempo = Tempo (_tempo->note_types_per_minute(), _tempo->note_type()); } void @@ -3671,11 +3755,14 @@ TempoTwistDrag::setup_pointer_frame_offset () void TempoTwistDrag::motion (GdkEvent* event, bool first_move) { + + if (!_next_tempo || !_drag_valid) { + return; + } + TempoMap& map (_editor->session()->tempo_map()); if (first_move) { - /* get current state */ - before_state = &map.get_state(); _editor->begin_reversible_command (_("twist tempo")); } @@ -3687,29 +3774,30 @@ TempoTwistDrag::motion (GdkEvent* event, bool first_move) pf = adjusted_current_frame (event); } - if (ArdourKeyboard::indicates_copy (event->button.state)) { - /* adjust this and the next tempi to match pointer frame */ - double new_bpm = max (1.5, _grab_tempo.note_types_per_minute() + ((grab_y() - min (-1.0, current_pointer_y())) / 5.0)); + /* adjust this and the next tempi to match pointer frame */ + double new_bpm = max (1.5, _grab_tempo.note_types_per_minute() + ((grab_y() - min (-1.0, current_pointer_y())) / 5.0)); + _editor->session()->tempo_map().gui_twist_tempi (_tempo, new_bpm, map.frame_at_quarter_note (_grab_qn), pf); - _editor->session()->tempo_map().gui_twist_tempi (_tempo, new_bpm, map.frame_at_quarter_note (_grab_qn), pf); - } ostringstream sstr; - sstr << "<" << fixed << setprecision(3) << _tempo->note_types_per_minute() << "\n"; - sstr << ">" << fixed << setprecision(3) << _tempo->end_note_types_per_minute(); + sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute() << "\n"; + sstr << "end: " << fixed << setprecision(3) << _tempo->end_note_types_per_minute() << "\n"; + sstr << "start: " << fixed << setprecision(3) << _next_tempo->note_types_per_minute(); show_verbose_cursor_text (sstr.str()); } void TempoTwistDrag::finished (GdkEvent* event, bool movement_occurred) { - if (!movement_occurred) { + if (!movement_occurred || !_drag_valid) { return; } - TempoMap& map (_editor->session()->tempo_map()); + _editor->tempo_curve_selected (_tempo, false); + _editor->tempo_curve_selected (_next_tempo, false); + TempoMap& map (_editor->session()->tempo_map()); XMLNode &after = map.get_state(); - _editor->session()->add_command(new MementoCommand(map, before_state, &after)); + _editor->session()->add_command(new MementoCommand(map, _before_state, &after)); _editor->commit_reversible_command (); } @@ -3717,7 +3805,7 @@ void TempoTwistDrag::aborted (bool moved) { if (moved) { - _editor->session()->tempo_map().set_state (*before_state, Stateful::current_state_version); + _editor->session()->tempo_map().set_state (*_before_state, Stateful::current_state_version); } } @@ -3725,22 +3813,42 @@ TempoEndDrag::TempoEndDrag (Editor* e, ArdourCanvas::Item* i) : Drag (e, i) , _grab_qn (0.0) , _tempo (0) - , before_state (0) + , _before_state (0) + , _drag_valid (true) { DEBUG_TRACE (DEBUG::Drags, "New TempoEndDrag\n"); - + TempoMarker* marker = reinterpret_cast (_item->get_data ("marker")); + _tempo = &marker->tempo(); + _grab_qn = _tempo->pulse() * 4.0; } void TempoEndDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) { Drag::start_grab (event, cursor); - TempoMap& map (_editor->session()->tempo_map()); - _tempo = const_cast (&map.tempo_section_at_frame (raw_grab_frame())); + TempoMap& tmap (_editor->session()->tempo_map()); + + /* get current state */ + _before_state = &tmap.get_state(); + + if (_tempo->locked_to_meter()) { + _drag_valid = false; + return; + } ostringstream sstr; - sstr << "end: " << fixed << setprecision(3) << _tempo->end_note_types_per_minute() << "\n"; - sstr << "start: " << fixed << setprecision(3) << _tempo->end_note_types_per_minute(); + + TempoSection* prev = 0; + if ((prev = tmap.previous_tempo_section (_tempo)) != 0) { + _editor->tempo_curve_selected (tmap.previous_tempo_section (_tempo), true); + sstr << "end: " << fixed << setprecision(3) << tmap.tempo_section_at_frame (_tempo->frame() - 1).end_note_types_per_minute() << "\n"; + } + + if (_tempo->clamped()) { + _editor->tempo_curve_selected (_tempo, true); + sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute(); + } + show_verbose_cursor_text (sstr.str()); } @@ -3748,21 +3856,6 @@ void TempoEndDrag::setup_pointer_frame_offset () { TempoMap& map (_editor->session()->tempo_map()); - const double beat_at_frame = max (0.0, map.beat_at_frame (raw_grab_frame())); - const uint32_t divisions = _editor->get_grid_beat_divisions (0); - double beat = 0.0; - - if (divisions > 0) { - beat = floor (beat_at_frame) + (floor (((beat_at_frame - floor (beat_at_frame)) * divisions)) / divisions); - } else { - /* while it makes some sense for the user to determine the division to 'grab', - grabbing a bar often leads to confusing results wrt the actual tempo section being altered - and the result over steep tempo curves. Use sixteenths. - */ - beat = floor (beat_at_frame) + (floor (((beat_at_frame - floor (beat_at_frame)) * 4)) / 4); - } - - _grab_qn = map.quarter_note_at_beat (beat); _pointer_frame_offset = raw_grab_frame() - map.frame_at_quarter_note (_grab_qn); @@ -3771,44 +3864,58 @@ TempoEndDrag::setup_pointer_frame_offset () void TempoEndDrag::motion (GdkEvent* event, bool first_move) { + if (!_drag_valid) { + return; + } + TempoMap& map (_editor->session()->tempo_map()); if (first_move) { - /* get current state */ - before_state = &map.get_state(); _editor->begin_reversible_command (_("stretch end tempo")); } - - framepos_t const pf = adjusted_current_frame (event, false); map.gui_stretch_tempo_end (&map.tempo_section_at_frame (_tempo->frame() - 1), map.frame_at_quarter_note (_grab_qn), pf); ostringstream sstr; - sstr << "end: " << fixed << setprecision(3) << _tempo->end_note_types_per_minute() << "\n"; - sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute(); + sstr << "end: " << fixed << setprecision(3) << map.tempo_section_at_frame (_tempo->frame() - 1).end_note_types_per_minute() << "\n"; + + if (_tempo->clamped()) { + sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute(); + } + show_verbose_cursor_text (sstr.str()); } void TempoEndDrag::finished (GdkEvent* event, bool movement_occurred) { - if (!movement_occurred) { + if (!movement_occurred || !_drag_valid) { return; } - TempoMap& map (_editor->session()->tempo_map()); + TempoMap& tmap (_editor->session()->tempo_map()); - XMLNode &after = map.get_state(); - _editor->session()->add_command(new MementoCommand(map, before_state, &after)); + XMLNode &after = tmap.get_state(); + _editor->session()->add_command(new MementoCommand(tmap, _before_state, &after)); _editor->commit_reversible_command (); + + TempoSection* prev = 0; + if ((prev = tmap.previous_tempo_section (_tempo)) != 0) { + _editor->tempo_curve_selected (prev, false); + } + + if (_tempo->clamped()) { + _editor->tempo_curve_selected (_tempo, false); + + } } void TempoEndDrag::aborted (bool moved) { if (moved) { - _editor->session()->tempo_map().set_state (*before_state, Stateful::current_state_version); + _editor->session()->tempo_map().set_state (*_before_state, Stateful::current_state_version); } } @@ -3881,7 +3988,7 @@ CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c) } - if (AudioEngine::instance()->connected()) { + if (AudioEngine::instance()->running()) { /* do this only if we're the engine is connected * because otherwise this request will never be @@ -3891,13 +3998,15 @@ CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c) */ s->request_suspend_timecode_transmission (); - while (AudioEngine::instance()->connected() && !s->timecode_transmission_suspended ()) { + while (AudioEngine::instance()->running() && !s->timecode_transmission_suspended ()) { /* twiddle our thumbs */ } } } fake_locate (where.frame - snap_delta (event->button.state)); + + _last_y_delta = 0; } void @@ -3910,6 +4019,39 @@ CursorDrag::motion (GdkEvent* event, bool) if (where.frame != last_pointer_frame()) { fake_locate (where.frame - snap_delta (event->button.state)); } + + //maybe do zooming, too, if the option is enabled + if (UIConfiguration::instance ().get_use_time_rulers_to_zoom_with_vertical_drag () ) { + + //To avoid accidental zooming, the mouse must move exactly vertical, not diagonal, to trigger a zoom step + //we use screen coordinates for this, not canvas-based grab_x + double mx = event->button.x; + double dx = fabs(mx - _last_mx); + double my = event->button.y; + double dy = fabs(my - _last_my); + + { + //do zooming in windowed "steps" so it feels more reversible ? + const int stepsize = 2; //stepsize ==1 means "trigger on every pixel of movement" + int y_delta = grab_y() - current_pointer_y(); + y_delta = y_delta / stepsize; + + //if all requirements are met, do the actual zoom + const double scale = 1.2; + if ( (dy>dx) && (_last_dx ==0) && (y_delta != _last_y_delta) ) { + if ( _last_y_delta > y_delta ) { + _editor->temporal_zoom_step_mouse_focus_scale (true, scale); + } else { + _editor->temporal_zoom_step_mouse_focus_scale (false, scale); + } + _last_y_delta = y_delta; + } + } + + _last_my = my; + _last_mx = mx; + _last_dx = dx; + } } void @@ -4600,7 +4742,7 @@ MarkerDrag::aborted (bool movement_occurred) void MarkerDrag::update_item (Location*) { - /* noop */ + /* noop */ } ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i) @@ -4702,10 +4844,9 @@ ControlPointDrag::motion (GdkEvent* event, bool first_motion) _editor->begin_reversible_command (_("automation event move")); _point->line().start_drag_single (_point, _fixed_grab_x, initial_fraction); } - pair result; + pair result; result = _point->line().drag_motion (_editor->sample_to_pixel_unrounded (cx_mf.frame), fraction, false, _pushing, _final_index); - - show_verbose_cursor_text (_point->line().get_verbose_cursor_string (result.second)); + show_verbose_cursor_text (_point->line().get_verbose_cursor_relative_string (result.first, result.second)); } void @@ -4822,10 +4963,10 @@ LineDrag::motion (GdkEvent* event, bool first_move) } /* we are ignoring x position for this drag, so we can just pass in anything */ - pair result; + pair result; result = _line->drag_motion (0, fraction, true, false, ignored); - show_verbose_cursor_text (_line->get_verbose_cursor_string (result.second)); + show_verbose_cursor_text (_line->get_verbose_cursor_relative_string (result.first, result.second)); } void @@ -5764,7 +5905,7 @@ RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred) case CreateSkipMarker: case CreateRangeMarker: case CreateCDMarker: - { + { XMLNode &before = _editor->session()->locations()->get_state(); if (_operation == CreateSkipMarker) { _editor->begin_reversible_command (_("new skip marker")); @@ -5791,7 +5932,7 @@ RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred) _editor->session()->add_command(new MementoCommand(*(_editor->session()->locations()), &before, &after)); _editor->commit_reversible_command (); break; - } + } case CreateTransportMarker: // popup menu to pick loop or punch @@ -6313,10 +6454,10 @@ AutomationRangeDrag::motion (GdkEvent*, bool first_move) for (list::iterator l = _lines.begin(); l != _lines.end(); ++l) { float const f = y_fraction (l->line, current_pointer_y()); /* we are ignoring x position for this drag, so we can just pass in anything */ - pair result; + pair result; uint32_t ignored; result = l->line->drag_motion (0, f, true, false, ignored); - show_verbose_cursor_text (l->line->get_verbose_cursor_relative_string (l->original_fraction, result.second)); + show_verbose_cursor_text (l->line->get_verbose_cursor_relative_string (result.first, result.second)); } } @@ -6609,7 +6750,7 @@ NoteCreateDrag::finished (GdkEvent* ev, bool had_movement) framepos_t const start = min (_note[0], _note[1]); framepos_t const start_sess_rel = start + _region_view->region()->position(); framecnt_t length = max (_editor->pixel_to_sample (1.0), (framecnt_t) fabs ((double)(_note[0] - _note[1]))); - framecnt_t const g = grid_frames (start); + framecnt_t const g = grid_frames (start_sess_rel); if (_editor->get_grid_music_divisions (ev->button.state) != 0 && length < g) { length = g; @@ -6619,7 +6760,10 @@ NoteCreateDrag::finished (GdkEvent* ev, bool had_movement) const double qn_length = map.quarter_notes_between_frames (start_sess_rel, start_sess_rel + length); Evoral::Beats qn_length_beats = max (Evoral::Beats::ticks(1), Evoral::Beats (qn_length)); + _editor->begin_reversible_command (_("Create Note")); + _region_view->clear_editor_note_selection(); _region_view->create_note_at (start, _drag_rect->y0(), qn_length_beats, ev->button.state, false); + _editor->commit_reversible_command (); } double @@ -6640,7 +6784,7 @@ HitCreateDrag::HitCreateDrag (Editor* e, ArdourCanvas::Item* i, MidiRegionView* : Drag (e, i) , _region_view (rv) , _last_pos (0) - , _last_y (0.0) + , _y (0.0) { } @@ -6655,6 +6799,8 @@ HitCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) TempoMap& map (_editor->session()->tempo_map()); + _y = _region_view->note_to_y (_region_view->y_to_note (y_to_region (event->button.y))); + const framepos_t pf = _drags->current_pointer_frame (); const int32_t divisions = _editor->get_grid_music_divisions (event->button.state); @@ -6667,14 +6813,13 @@ HitCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) } const framepos_t start = map.frame_at_quarter_note (eqaf) - _region_view->region()->position(); - const double y = _region_view->note_to_y (_region_view->y_to_note (y_to_region (event->button.y))); - Evoral::Beats length = _region_view->get_grid_beats (pf); - _region_view->create_note_at (start, y, length, event->button.state, false); + _editor->begin_reversible_command (_("Create Hit")); + _region_view->clear_editor_note_selection(); + _region_view->create_note_at (start, _y, length, event->button.state, false); _last_pos = start; - _last_y = y; } void @@ -6691,28 +6836,28 @@ HitCreateDrag::motion (GdkEvent* event, bool) const double eqaf = map.exact_qn_at_frame (pf, divisions); const framepos_t start = map.frame_at_quarter_note (eqaf) - _region_view->region()->position (); - const double y = _region_view->note_to_y (_region_view->y_to_note (y_to_region (event->button.y))); - if (_last_pos == start && y == _last_y) { + if (_last_pos == start) { return; } Evoral::Beats length = _region_view->get_grid_beats (pf); boost::shared_ptr mr = _region_view->midi_region(); + if (eqaf >= mr->quarter_note() + mr->length_beats()) { return; } - _region_view->create_note_at (start, y, length, event->button.state, false); + _region_view->create_note_at (start, _y, length, event->button.state, false); _last_pos = start; - _last_y = y; } void HitCreateDrag::finished (GdkEvent* /* ev */, bool /* had_movement */) { + _editor->commit_reversible_command (); } @@ -6879,56 +7024,3 @@ void RegionCutDrag::aborted (bool) { } - -RulerZoomDrag::RulerZoomDrag (Editor* e, ArdourCanvas::Item* item) - : Drag (e, item, true) -{ -} - -void -RulerZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor* c) -{ - Drag::start_grab (event, c); - - framepos_t where = _editor->canvas_event_sample(event); - - _editor->_dragging_playhead = true; - - _editor->playhead_cursor->set_position (where); -} - -void -RulerZoomDrag::motion (GdkEvent* event, bool) -{ - framepos_t where = _editor->canvas_event_sample(event); - - _editor->playhead_cursor->set_position (where); - - const double movement_limit = 20.0; - const double scale = 1.08; - const double y_delta = last_pointer_y() - current_pointer_y(); - - if (y_delta > 0 && y_delta < movement_limit) { - _editor->temporal_zoom_step_mouse_focus_scale (true, scale); - } else if (y_delta < 0 && y_delta > -movement_limit) { - _editor->temporal_zoom_step_mouse_focus_scale (false, scale); - } -} - -void -RulerZoomDrag::finished (GdkEvent*, bool) -{ - _editor->_dragging_playhead = false; - - Session* s = _editor->session (); - if (s) { - s->request_locate (_editor->playhead_cursor->current_frame (), _was_rolling); - _editor->_pending_locate_request = true; - } - -} - -void -RulerZoomDrag::aborted (bool) -{ -}