#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"
return boost::shared_ptr<Region>();
}
-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<ARDOUR::Stripable> const& a = tav_a->stripable ();
+ boost::shared_ptr<ARDOUR::Stripable> const& b = tav_b->stripable ();
+ return ARDOUR::Stripable::Sorter () (a, b);
}
};
*/
TrackViewList track_views = _editor->track_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);
/* 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;
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<boost::shared_ptr<MidiTrack> > midi_tracks;
boost::shared_ptr<ARDOUR::PluginInfo>(),
(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) {
PlaylistSet frozen_playlists;
set<RouteTimeAxisView*> 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<boost::shared_ptr<Playlist>, RouteTimeAxisView*> PlaylistMapping;
PlaylistMapping playlist_mapping;
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);
}
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));
+ }
}
}
}
if (insert_result.second) {
pl->freeze();
}
+
+ MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (rv);
+ /* a MRV start trim may change the source length. ensure we cover all playlists here */
+ if (mrv && _operation == StartTrim) {
+ vector<boost::shared_ptr<Playlist> > all_playlists;
+ _editor->session()->playlists->get (all_playlists);
+ for (vector<boost::shared_ptr<Playlist> >::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();
+ }
+
+ }
+ }
+ }
}
}
if (!_editor->selection->selected (_primary)) {
_primary->thaw_after_trim ();
} else {
-
- set<boost::shared_ptr<Playlist> > diffed_playlists;
-
for (list<DraggingView>::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<Playlist> p = i->view->region()->playlist ();
- if (diffed_playlists.find (p) == diffed_playlists.end()) {
- vector<Command*> cmds;
- p->rdiff (cmds);
- _editor->session()->add_commands (cmds);
- diffed_playlists.insert (p);
- }
}
}
for (set<boost::shared_ptr<Playlist> >::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<Command*> cmds;
+ (*p)->rdiff (cmds);
+ _editor->session()->add_commands (cmds);
(*p)->thaw ();
}
} 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;
, _grab_qn (0.0)
, _tempo (0)
, _before_state (0)
+ , _drag_valid (true)
{
DEBUG_TRACE (DEBUG::Drags, "New BBTRulerDrag\n");
Drag::start_grab (event, cursor);
TempoMap& map (_editor->session()->tempo_map());
_tempo = const_cast<TempoSection*> (&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) {
- _editor->tempo_curve_selected (prev, true);
sstr << "end: " << fixed << setprecision(3) << prev->end_note_types_per_minute() << "\n";
}
}
void
BBTRulerDrag::motion (GdkEvent* event, bool first_move)
{
- TempoMap& map (_editor->session()->tempo_map());
+ if (!_drag_valid) {
+ return;
+ }
if (first_move) {
_editor->begin_reversible_command (_("stretch tempo"));
}
+ TempoMap& map (_editor->session()->tempo_map());
framepos_t pf;
if (_editor->snap_musical()) {
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;
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 ();
_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<TempoMap>(map, _before_state, &after));
+ _editor->commit_reversible_command ();
+
}
void
_before_state = &map.get_state();
_tempo = const_cast<TempoSection*> (&map.tempo_section_at_frame (raw_grab_frame()));
+ 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)) {
void
TempoTwistDrag::finished (GdkEvent* event, bool movement_occurred)
{
- TempoMap& map (_editor->session()->tempo_map());
-
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 ();
, _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"));
/* get current state */
_before_state = &tmap.get_state();
+ if (_tempo->locked_to_meter()) {
+ _drag_valid = false;
+ return;
+ }
ostringstream sstr;
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"));
}
-
-
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);
void
TempoEndDrag::finished (GdkEvent* event, bool movement_occurred)
{
- if (!movement_occurred) {
+ if (!movement_occurred || !_drag_valid) {
return;
}
}
- 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
*/
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
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
void
MarkerDrag::update_item (Location*)
{
- /* noop */
+ /* noop */
}
ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
_editor->begin_reversible_command (_("automation event move"));
_point->line().start_drag_single (_point, _fixed_grab_x, initial_fraction);
}
- pair<double, float> result;
+ pair<float, float> 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
}
/* we are ignoring x position for this drag, so we can just pass in anything */
- pair<double, float> result;
+ pair<float, float> 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
case CreateSkipMarker:
case CreateRangeMarker:
case CreateCDMarker:
- {
+ {
XMLNode &before = _editor->session()->locations()->get_state();
if (_operation == CreateSkipMarker) {
_editor->begin_reversible_command (_("new skip marker"));
_editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
_editor->commit_reversible_command ();
break;
- }
+ }
case CreateTransportMarker:
// popup menu to pick loop or punch
for (list<Line>::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<double, float> result;
+ pair<float, float> 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));
}
}
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;
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)
-{
-}