+void
+TempoTwistDrag::motion (GdkEvent* event, bool first_move)
+{
+
+ if (!_next_tempo || !_drag_valid) {
+ return;
+ }
+
+ TempoMap& map (_editor->session()->tempo_map());
+
+ if (first_move) {
+ _editor->begin_reversible_command (_("twist tempo"));
+ }
+
+ samplepos_t pf;
+
+ if (_editor->grid_musical()) {
+ pf = adjusted_current_sample (event, false);
+ } else {
+ pf = adjusted_current_sample (event);
+ }
+
+ /* adjust this and the next tempi to match pointer sample */
+ 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.sample_at_quarter_note (_grab_qn), pf);
+
+ 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());
+}
+
+void
+TempoTwistDrag::finished (GdkEvent* event, bool movement_occurred)
+{
+ if (!movement_occurred || !_drag_valid) {
+ return;
+ }
+
+ _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<TempoMap>(map, _before_state, &after));
+ _editor->commit_reversible_command ();
+}
+
+void
+TempoTwistDrag::aborted (bool moved)
+{
+ if (moved) {
+ _editor->session()->tempo_map().set_state (*_before_state, Stateful::current_state_version);
+ }
+}
+
+TempoEndDrag::TempoEndDrag (Editor* e, ArdourCanvas::Item* i)
+ : Drag (e, i)
+ , _grab_qn (0.0)
+ , _tempo (0)
+ , _before_state (0)
+ , _drag_valid (true)
+{
+ DEBUG_TRACE (DEBUG::Drags, "New TempoEndDrag\n");
+ TempoMarker* marker = reinterpret_cast<TempoMarker*> (_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& tmap (_editor->session()->tempo_map());
+
+ /* get current state */
+ _before_state = &tmap.get_state();
+
+ if (_tempo->locked_to_meter()) {
+ _drag_valid = false;
+ return;
+ }
+
+ ostringstream sstr;
+
+ 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_sample (_tempo->sample() - 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());
+}
+
+void
+TempoEndDrag::setup_pointer_sample_offset ()
+{
+ TempoMap& map (_editor->session()->tempo_map());
+
+ _pointer_sample_offset = raw_grab_sample() - map.sample_at_quarter_note (_grab_qn);
+
+}
+
+void
+TempoEndDrag::motion (GdkEvent* event, bool first_move)
+{
+ if (!_drag_valid) {
+ return;
+ }
+
+ TempoMap& map (_editor->session()->tempo_map());
+
+ if (first_move) {
+ _editor->begin_reversible_command (_("stretch end tempo"));
+ }
+
+ samplepos_t const pf = adjusted_current_sample (event, false);
+ map.gui_stretch_tempo_end (&map.tempo_section_at_sample (_tempo->sample() - 1), map.sample_at_quarter_note (_grab_qn), pf);
+
+ ostringstream sstr;
+ sstr << "end: " << fixed << setprecision(3) << map.tempo_section_at_sample (_tempo->sample() - 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 || !_drag_valid) {
+ return;
+ }
+
+ TempoMap& tmap (_editor->session()->tempo_map());
+
+ XMLNode &after = tmap.get_state();
+ _editor->session()->add_command(new MementoCommand<TempoMap>(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);
+ }
+}