#endif
#include <stdint.h>
+#include <algorithm>
#include "pbd/memento_command.h"
#include "pbd/basename.h"
RegionView* rv = i->view;
- if (rv->region()->locked()) {
+ if (rv->region()->locked() || rv->region()->video_locked()) {
continue;
}
/* insert the regions into their new playlists */
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- if (i->view->region()->locked()) {
+ if (i->view->region()->locked() || i->view->region()->video_locked()) {
continue;
}
RouteTimeAxisView* const dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]);
double const dest_layer = i->layer;
- if (rv->region()->locked()) {
+ if (rv->region()->locked() || rv->region()->video_locked()) {
++i;
continue;
}
place snapped notes at the start of the region.
*/
- framecnt_t const len = abs (f - grab_frame () - 1);
+ framecnt_t const len = (framecnt_t) fabs (f - grab_frame () - 1);
_region->set_length (len < 1 ? 1 : len);
}
}
}
}
+AVDraggingView::AVDraggingView (RegionView* v)
+ : view (v)
+{
+ initial_position = v->region()->position ();
+}
+
+VideoTimeLineDrag::VideoTimeLineDrag (Editor* e, ArdourCanvas::Item* i)
+ : Drag (e, i)
+{
+ DEBUG_TRACE (DEBUG::Drags, "New VideoTimeLineDrag\n");
+
+ RegionSelection rs;
+ TrackViewList empty;
+ empty.clear();
+ _editor->get_regions_after(rs, (framepos_t) 0, empty);
+ std::list<RegionView*> views = rs.by_layer();
+
+ for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
+ RegionView* rv = (*i);
+ if (!rv->region()->video_locked()) {
+ continue;
+ }
+ _views.push_back (AVDraggingView (rv));
+ }
+}
+
+void
+VideoTimeLineDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
+{
+ Drag::start_grab (event);
+ if (_editor->session() == 0) {
+ return;
+ }
+
+ _startdrag_video_offset=ARDOUR_UI::instance()->video_timeline->get_offset();
+ _max_backwards_drag = (
+ ARDOUR_UI::instance()->video_timeline->get_duration()
+ + ARDOUR_UI::instance()->video_timeline->get_offset()
+ - ceil(ARDOUR_UI::instance()->video_timeline->get_apv())
+ );
+
+ for (list<AVDraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
+ if (i->initial_position < _max_backwards_drag || _max_backwards_drag < 0) {
+ _max_backwards_drag = ARDOUR_UI::instance()->video_timeline->quantify_frames_to_apv (i->initial_position);
+ }
+ }
+ DEBUG_TRACE (DEBUG::Drags, string_compose("VideoTimeLineDrag: max backwards-drag: %1\n", _max_backwards_drag));
+
+ char buf[128];
+ Timecode::Time timecode;
+ _editor->session()->sample_to_timecode(abs(_startdrag_video_offset), timecode, true /* use_offset */, false /* use_subframes */ );
+ snprintf (buf, sizeof (buf), "Video Start:\n%c%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, (_startdrag_video_offset<0?'-':' '), timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
+ _editor->verbose_cursor()->set(buf, event->button.x + 10, event->button.y + 10);
+ _editor->verbose_cursor()->show ();
+}
+
+void
+VideoTimeLineDrag::motion (GdkEvent* event, bool first_move)
+{
+ if (_editor->session() == 0) {
+ return;
+ }
+ if (ARDOUR_UI::instance()->video_timeline->is_offset_locked()) {
+ return;
+ }
+
+ framecnt_t dt = adjusted_current_frame (event) - raw_grab_frame() + _pointer_frame_offset;
+ dt = ARDOUR_UI::instance()->video_timeline->quantify_frames_to_apv(_startdrag_video_offset+dt) - _startdrag_video_offset;
+
+ if (_max_backwards_drag >= 0 && dt <= - _max_backwards_drag) {
+ dt = - _max_backwards_drag;
+ }
+
+ ARDOUR_UI::instance()->video_timeline->set_offset(_startdrag_video_offset+dt);
+ ARDOUR_UI::instance()->flush_videotimeline_cache(true);
+
+ for (list<AVDraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
+ RegionView* rv = i->view;
+ DEBUG_TRACE (DEBUG::Drags, string_compose("SHIFT REGION at %1 by %2\n", i->initial_position, dt));
+ if (first_move) {
+ rv->drag_start ();
+ _editor->update_canvas_now ();
+ rv->fake_set_opaque (true);
+ rv->region()->clear_changes ();
+ rv->region()->suspend_property_changes();
+ }
+ rv->region()->set_position(i->initial_position + dt);
+ rv->region_changed(ARDOUR::Properties::position);
+ }
+
+ const framepos_t offset = ARDOUR_UI::instance()->video_timeline->get_offset();
+ Timecode::Time timecode;
+ Timecode::Time timediff;
+ char buf[128];
+ _editor->session()->sample_to_timecode(abs(offset), timecode, true /* use_offset */, false /* use_subframes */ );
+ _editor->session()->sample_to_timecode(abs(dt), timediff, false /* use_offset */, false /* use_subframes */ );
+ snprintf (buf, sizeof (buf),
+ "%s\n%c%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32
+ "\n%s\n%c%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32
+ , _("Video Start:"),
+ (offset<0?'-':' '), timecode.hours, timecode.minutes, timecode.seconds, timecode.frames
+ , _("Diff:"),
+ (dt<0?'-':' '), timediff.hours, timediff.minutes, timediff.seconds, timediff.frames
+ );
+ _editor->verbose_cursor()->set(buf, event->button.x + 10, event->button.y + 10);
+ _editor->verbose_cursor()->show ();
+}
+
+void
+VideoTimeLineDrag::finished (GdkEvent * /*event*/, bool movement_occurred)
+{
+ if (ARDOUR_UI::instance()->video_timeline->is_offset_locked()) {
+ return;
+ }
+
+ if (!movement_occurred || ! _editor->session()) {
+ return;
+ }
+
+ ARDOUR_UI::instance()->flush_videotimeline_cache(true);
+
+ _editor->begin_reversible_command (_("Move Video"));
+
+ XMLNode &before = ARDOUR_UI::instance()->video_timeline->get_state();
+ ARDOUR_UI::instance()->video_timeline->save_undo();
+ XMLNode &after = ARDOUR_UI::instance()->video_timeline->get_state();
+ _editor->session()->add_command(new MementoCommand<VideoTimeLine>(*(ARDOUR_UI::instance()->video_timeline), &before, &after));
+
+ for (list<AVDraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
+ i->view->drag_end();
+ i->view->fake_set_opaque (false);
+ i->view->region()->resume_property_changes ();
+
+ _editor->session()->add_command (new StatefulDiffCommand (i->view->region()));
+ }
+
+ _editor->session()->maybe_update_session_range(
+ std::max(ARDOUR_UI::instance()->video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
+ std::max(ARDOUR_UI::instance()->video_timeline->get_offset() + ARDOUR_UI::instance()->video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0)
+ );
+
+
+ _editor->commit_reversible_command ();
+ _editor->update_canvas_now ();
+}
+
+void
+VideoTimeLineDrag::aborted (bool)
+{
+ if (ARDOUR_UI::instance()->video_timeline->is_offset_locked()) {
+ return;
+ }
+ ARDOUR_UI::instance()->video_timeline->set_offset(_startdrag_video_offset);
+ ARDOUR_UI::instance()->flush_videotimeline_cache(true);
+
+ for (list<AVDraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
+ i->view->region()->resume_property_changes ();
+ i->view->region()->set_position(i->initial_position);
+ }
+}
+
TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool preserve_fade_anchor)
: RegionDrag (e, i, p, v)
{
len = ar->fade_in()->back()->when;
new_length = len - _editor->unit_to_frame (distance);
new_length = ar->verify_xfade_bounds (new_length, true /*START*/ );
- arv->reset_fade_in_shape_width (new_length); //the grey shape
- arv->redraw_start_xfade_to (ar, new_length); //the green lines & blue rect
+ arv->reset_fade_in_shape_width (ar, new_length); //the grey shape
}
}
}
len = ar->fade_out()->back()->when;
new_length = len - _editor->unit_to_frame (distance);
new_length = ar->verify_xfade_bounds (new_length, false /*END*/ );
- arv->reset_fade_out_shape_width (new_length); //the grey shape
- arv->redraw_end_xfade_to (ar, new_length); //the green lines & blue rect (must do this after)
+ arv->reset_fade_out_shape_width (ar, new_length); //the grey shape
}
}
}
}
}
}
-
- if (_operation == StartTrim) {
- _editor->maybe_locate_with_edit_preroll ( _views.begin()->view->region()->position() );
- }
- if (_operation == EndTrim) {
- _editor->maybe_locate_with_edit_preroll ( _views.begin()->view->region()->position() + _views.begin()->view->region()->length() );
+
+ if (!_views.empty()) {
+ if (_operation == StartTrim) {
+ _editor->maybe_locate_with_edit_preroll(
+ _views.begin()->view->region()->position());
+ }
+ if (_operation == EndTrim) {
+ _editor->maybe_locate_with_edit_preroll(
+ _views.begin()->view->region()->position() +
+ _views.begin()->view->region()->length());
+ }
}
if (!_editor->selection->selected (_primary)) {
framepos_t const f = _editor->playhead_cursor->current_frame;
s->send_mmc_locate (f);
s->send_full_time_code (f);
+ s->send_song_position_pointer (f);
}
show_verbose_cursor_time (t);
continue;
}
- tmp->reset_fade_in_shape_width (fade_length);
- boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
- tmp->redraw_start_xfade_to (ar, fade_length);
+ tmp->reset_fade_in_shape_width (tmp->audio_region(), fade_length);
}
show_verbose_cursor_duration (region->position(), region->position() + fade_length, 32);
continue;
}
- tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
+ tmp->reset_fade_in_shape_width (tmp->audio_region(), tmp->audio_region()->fade_in()->back()->when);
}
}
continue;
}
- tmp->reset_fade_out_shape_width (fade_length);
- boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
- tmp->redraw_end_xfade_to (ar, fade_length);
+ tmp->reset_fade_out_shape_width (tmp->audio_region(), fade_length);
}
show_verbose_cursor_duration (region->last_frame() - fade_length, region->last_frame());
continue;
}
- tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
+ tmp->reset_fade_out_shape_width (tmp->audio_region(), tmp->audio_region()->fade_out()->back()->when);
}
}
MarkerDrag::~MarkerDrag ()
{
- for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
- delete *i;
+ for (CopiedLocationInfo::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
+ delete i->location;
}
}
+MarkerDrag::CopiedLocationMarkerInfo::CopiedLocationMarkerInfo (Location* l, Marker* m)
+{
+ location = new Location (*l);
+ markers.push_back (m);
+ move_both = false;
+}
+
void
MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
{
switch (op) {
case Selection::Toggle:
- _editor->selection->toggle (_marker);
+ /* we toggle on the button release */
break;
case Selection::Set:
if (!_editor->selection->selected (_marker)) {
break;
}
- /* Set up copies for us to manipulate during the drag */
+ /* Set up copies for us to manipulate during the drag
+ */
for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
+
Location* l = _editor->find_location_from_marker (*i, is_start);
- _copied_locations.push_back (new Location (*l));
+
+ if (!l) {
+ continue;
+ }
+
+ if (l->is_mark()) {
+ _copied_locations.push_back (CopiedLocationMarkerInfo (l, *i));
+ } else {
+ /* range: check that the other end of the range isn't
+ already there.
+ */
+ CopiedLocationInfo::iterator x;
+ for (x = _copied_locations.begin(); x != _copied_locations.end(); ++x) {
+ if (*(*x).location == *l) {
+ break;
+ }
+ }
+ if (x == _copied_locations.end()) {
+ _copied_locations.push_back (CopiedLocationMarkerInfo (l, *i));
+ } else {
+ (*x).markers.push_back (*i);
+ (*x).move_both = true;
+ }
+ }
+
}
}
framecnt_t f_delta = 0;
bool is_start;
bool move_both = false;
- Marker* marker;
Location *real_location;
Location *copy_location = 0;
framepos_t const newframe = adjusted_current_frame (event);
-
framepos_t next = newframe;
if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
move_both = true;
}
- MarkerSelection::iterator i;
- list<Location*>::iterator x;
+ CopiedLocationInfo::iterator x;
/* find the marker we're dragging, and compute the delta */
- for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
- x != _copied_locations.end() && i != _editor->selection->markers.end();
- ++i, ++x) {
+ for (x = _copied_locations.begin(); x != _copied_locations.end(); ++x) {
+
+ copy_location = (*x).location;
- copy_location = *x;
- marker = *i;
+ if (find (x->markers.begin(), x->markers.end(), _marker) != x->markers.end()) {
- if (marker == _marker) {
+ /* this marker is represented by this
+ * CopiedLocationMarkerInfo
+ */
- if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
+ if ((real_location = _editor->find_location_from_marker (_marker, is_start)) == 0) {
/* que pasa ?? */
return;
}
} else {
- switch (marker->type()) {
+ switch (_marker->type()) {
case Marker::SessionStart:
case Marker::RangeStart:
case Marker::LoopStart:
return;
}
}
+
break;
}
}
- if (i == _editor->selection->markers.end()) {
+ if (x == _copied_locations.end()) {
/* hmm, impossible - we didn't find the dragged marker */
return;
}
/* now move them all */
- for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
- x != _copied_locations.end() && i != _editor->selection->markers.end();
- ++i, ++x) {
+ for (x = _copied_locations.begin(); x != _copied_locations.end(); ++x) {
- copy_location = *x;
- marker = *i;
+ copy_location = x->location;
/* call this to find out if its the start or end */
- if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
+ if ((real_location = _editor->find_location_from_marker (x->markers.front(), is_start)) == 0) {
continue;
}
copy_location->set_start (copy_location->start() + f_delta);
} else {
-
+
framepos_t new_start = copy_location->start() + f_delta;
framepos_t new_end = copy_location->end() + f_delta;
-
+
if (is_start) { // start-of-range marker
-
- if (move_both) {
+
+ if (move_both || (*x).move_both) {
copy_location->set_start (new_start);
copy_location->set_end (new_end);
} else if (new_start < copy_location->end()) {
} else { // end marker
- if (move_both) {
+ if (move_both || (*x).move_both) {
copy_location->set_end (new_end);
copy_location->set_start (new_start);
} else if (new_end > copy_location->start()) {
}
update_item (copy_location);
-
+
+ /* now lookup the actual GUI items used to display this
+ * location and move them to wherever the copy of the location
+ * is now. This means that the logic in ARDOUR::Location is
+ * still enforced, even though we are not (yet) modifying
+ * the real Location itself.
+ */
+
Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
if (lm) {
lm->set_position (copy_location->start(), copy_location->end());
}
+
}
assert (!_copied_locations.empty());
break;
case Selection::Toggle:
+ /* we toggle on the button release, click only */
+ _editor->selection->toggle (_marker);
+ break;
+
case Selection::Extend:
case Selection::Add:
break;
XMLNode &before = _editor->session()->locations()->get_state();
MarkerSelection::iterator i;
- list<Location*>::iterator x;
+ CopiedLocationInfo::iterator x;
bool is_start;
for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
}
if (location->is_mark()) {
- location->set_start ((*x)->start());
+ location->set_start (((*x).location)->start());
} else {
- location->set ((*x)->start(), (*x)->end());
+ location->set (((*x).location)->start(), ((*x).location)->end());
}
}
}
_editor->verbose_cursor()->show ();
+ _pushing = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
+
if (!_point->can_slide ()) {
_x_constrained = true;
}
cx_frames = min (cx_frames, _point->line().maximum_time());
float const fraction = 1.0 - (cy / _point->line().height());
- bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
- _point->line().drag_motion (_editor->frame_to_unit_unrounded (cx_frames), fraction, false, push);
+ _point->line().drag_motion (_editor->frame_to_unit_unrounded (cx_frames), fraction, false, _pushing, _final_index);
_editor->verbose_cursor()->set_text (_point->line().get_verbose_cursor_string (fraction));
}
motion (event, false);
}
- _point->line().end_drag ();
+ _point->line().end_drag (_pushing, _final_index);
_editor->session()->commit_reversible_command ();
}
cy = min ((double) _line->height(), cy);
double const fraction = 1.0 - (cy / _line->height());
- bool const push = !Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
+ uint32_t ignored;
/* we are ignoring x position for this drag, so we can just pass in anything */
- _line->drag_motion (0, fraction, true, push);
+ _line->drag_motion (0, fraction, true, false, ignored);
_editor->verbose_cursor()->set_text (_line->get_verbose_cursor_string (fraction));
}
LineDrag::finished (GdkEvent* event, bool)
{
motion (event, false);
- _line->end_drag ();
+ _line->end_drag (false, 0);
_editor->session()->commit_reversible_command ();
}
for (list<Line>::iterator l = _lines.begin(); l != _lines.end(); ++l) {
float const f = y_fraction (l->line, _drags->current_pointer_y());
/* we are ignoring x position for this drag, so we can just pass in anything */
- l->line->drag_motion (0, f, true, false);
+ uint32_t ignored;
+ l->line->drag_motion (0, f, true, false, ignored);
show_verbose_cursor_text (l->line->get_verbose_cursor_relative_string (l->original_fraction, f));
}
}
motion (event, false);
for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
- i->line->end_drag ();
+ i->line->end_drag (false, 0);
}
_editor->session()->commit_reversible_command ();
}
framepos_t const start = min (_note[0], _note[1]);
- framecnt_t length = abs (_note[0] - _note[1]);
+ framecnt_t length = (framecnt_t) fabs (_note[0] - _note[1]);
framecnt_t const g = grid_frames (start);
double const one_tick = 1 / Timecode::BBT_Time::ticks_per_beat;