#endif
#include <stdint.h>
+#include <algorithm>
#include "pbd/memento_command.h"
#include "pbd/basename.h"
#include "gtkmm2ext/utils.h"
+#include "ardour/audioengine.h"
#include "ardour/audioregion.h"
#include "ardour/dB.h"
#include "ardour/midi_region.h"
#include "editor_drag.h"
#include "audio_time_axis.h"
#include "midi_time_axis.h"
-#include "canvas-note.h"
#include "selection.h"
#include "midi_selection.h"
#include "automation_time_axis.h"
#include "debug.h"
#include "editor_cursors.h"
#include "mouse_cursors.h"
+#include "note_base.h"
+#include "patch_change.h"
#include "verbose_cursor.h"
using namespace std;
}
void
-Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
+Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t /*time*/)
{
- _item->ungrab (0);
+ _item->ungrab ();
_item = new_item;
if (cursor == 0) {
- cursor = _editor->which_grabber_cursor ();
+ _item->grab ();
+ } else {
+ _item->grab ();
}
-
- _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
}
void
Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
{
- if (cursor == 0) {
- cursor = _editor->which_grabber_cursor ();
- }
-
// if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
if (Keyboard::is_button2_event (&event->button)) {
_last_pointer_x = _grab_x;
_last_pointer_y = _grab_y;
- _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
- *cursor,
- event->button.time);
+ if (cursor == 0) {
+ _item->grab ();
+
+ } else {
+ /* CAIROCANVAS need a variant here that passes *cursor */
+ _item->grab ();
+
+ }
if (_editor->session() && _editor->session()->transport_rolling()) {
_was_rolling = true;
{
_editor->stop_canvas_autoscroll ();
- _item->ungrab (event ? event->button.time : 0);
+ _item->ungrab ();
finished (event, _move_threshold_passed);
if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
if (!from_autoscroll) {
- _editor->maybe_autoscroll (true, allow_vertical_autoscroll ());
+ bool const moving_left = _drags->current_pointer_x() < _last_pointer_x;
+ bool const moving_up = _drags->current_pointer_y() < _last_pointer_y;
+ _editor->maybe_autoscroll (true, allow_vertical_autoscroll (), moving_left, moving_up);
}
motion (event, _move_threshold_passed != old_move_threshold_passed);
Drag::abort ()
{
if (_item) {
- _item->ungrab (0);
+ _item->ungrab ();
}
aborted (_move_threshold_passed);
_editor->verbose_cursor()->set_time (
frame,
_drags->current_pointer_x() + 10 - _editor->horizontal_position(),
- _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value() + _editor->canvas_timebars_vsize
+ _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value()
);
_editor->verbose_cursor()->show ();
_editor->verbose_cursor()->set_duration (
start, end,
_drags->current_pointer_x() + 10 - _editor->horizontal_position(),
- _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value() + _editor->canvas_timebars_vsize
+ _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value()
);
}
_editor->verbose_cursor()->set (
text,
_drags->current_pointer_x() + 10 - _editor->horizontal_position(),
- _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value() + _editor->canvas_timebars_vsize
+ _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value()
);
}
+boost::shared_ptr<Region>
+Drag::add_midi_region (MidiTimeAxisView* view)
+{
+ if (_editor->session()) {
+ const TempoMap& map (_editor->session()->tempo_map());
+ framecnt_t pos = grab_frame();
+ const Meter& m = map.meter_at (pos);
+ /* not that the frame rate used here can be affected by pull up/down which
+ might be wrong.
+ */
+ framecnt_t len = m.frames_per_bar (map.tempo_at (pos), _editor->session()->frame_rate());
+ return view->add_region (grab_frame(), len, true);
+ }
+
+ return boost::shared_ptr<Region>();
+}
struct EditorOrderTimeAxisViewSorter {
bool operator() (TimeAxisView* a, TimeAxisView* b) {
RouteTimeAxisView* ra = dynamic_cast<RouteTimeAxisView*> (a);
RouteTimeAxisView* rb = dynamic_cast<RouteTimeAxisView*> (b);
assert (ra && rb);
- return ra->route()->order_key (N_ ("editor")) < rb->route()->order_key (N_ ("editor"));
+ return ra->route()->order_key (EditorSort) < rb->route()->order_key (EditorSort);
}
};
_views.push_back (DraggingView (*i, this));
}
- RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
+ RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), boost::bind (&RegionDrag::region_going_away, this, _1), gui_context());
}
void
if ((*pending_region_position != _last_frame_position) && x_move_allowed) {
/* x movement since last time (in pixels) */
- dx = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
+ dx = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_pixel;
/* total x movement */
framecnt_t total_dx = *pending_region_position;
RegionView* rv = i->view;
- if (rv->region()->locked()) {
+ if (rv->region()->locked() || rv->region()->video_locked()) {
continue;
}
if (first_move) {
- rv->get_time_axis_view().hide_dependent_views (*rv);
+ rv->drag_start ();
/* Absolutely no idea why this is necessary, but it is; without
it, the region view disappears after the reparent.
later, as the two parent groups have different coordinates.
*/
- rv->get_canvas_group()->reparent (*(_editor->_region_motion_group));
+ rv->get_canvas_group()->reparent (_editor->_region_motion_group);
rv->fake_set_opaque (true);
}
if (tv->view()->layer_display() == Stacked) {
tv->view()->set_layer_display (Expanded);
}
-
+
/* We're only allowed to go -ve in layer on Expanded views */
if (tv->view()->layer_display() != Expanded && (i->layer + this_delta_layer) < 0) {
this_delta_layer = - i->layer;
}
-
+
/* Set height */
rv->set_height (tv->view()->child_height ());
-
+
/* Update show/hidden status as the region view may have come from a hidden track,
or have moved to one.
*/
double y = 0;
/* Get the y coordinate of the top of the track that this region is now on */
- tv->canvas_display()->i2w (x, y);
+ tv->canvas_display()->item_to_canvas (x, y);
y += _editor->get_trackview_group_vertical_offset();
/* And adjust for the layer that it should be on */
}
/* Now move the region view */
- rv->move (x_delta, y - rv->get_canvas_group()->property_y());
+ rv->move (x_delta, y - rv->get_canvas_group()->position().y);
}
} /* foreach region */
_total_x_delta += x_delta;
- if (first_move) {
- _editor->cursor_group->raise_to_top();
- }
-
if (x_delta != 0 && !_brushing) {
show_verbose_cursor_time (_last_frame_position);
}
);
}
+
+ _editor->maybe_locate_with_edit_preroll (_editor->get_selection().regions.start());
}
void
/* 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;
}
No need to do anything for copies as they are fake regions which will be deleted.
*/
- rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
- rv->get_canvas_group()->property_y() = i->initial_y;
- rv->get_time_axis_view().reveal_dependent_views (*rv);
+ rv->get_canvas_group()->reparent (dest_rtv->view()->canvas_item());
+ rv->get_canvas_group()->set_y_position (i->initial_y);
+ rv->drag_end ();
/* just change the model */
TimeAxisView* tv = &(rv->get_time_axis_view ());
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
assert (rtv);
- rv->get_canvas_group()->reparent (*rtv->view()->canvas_item());
- rv->get_canvas_group()->property_y() = 0;
- rv->get_time_axis_view().reveal_dependent_views (*rv);
+ rv->get_canvas_group()->reparent (rtv->view()->canvas_item());
+ rv->get_canvas_group()->set_y_position (0);
+ rv->drag_end ();
rv->fake_set_opaque (false);
rv->move (-_total_x_delta, 0);
rv->set_height (rtv->view()->child_height ());
RouteTimeAxisView* dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[_views.front().time_axis_view]);
- _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
- _primary->get_canvas_group()->property_y() = 0;
+ _primary->get_canvas_group()->reparent (dest_rtv->view()->canvas_item());
+ _primary->get_canvas_group()->set_y_position (0);
boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
RegionCreateDrag::motion (GdkEvent* event, bool first_move)
{
if (first_move) {
- add_region();
+ _region = add_midi_region (_view);
_view->playlist()->freeze ();
} else {
if (_region) {
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);
}
}
RegionCreateDrag::finished (GdkEvent*, bool movement_occurred)
{
if (!movement_occurred) {
- add_region ();
+ add_midi_region (_view);
} else {
_view->playlist()->thaw ();
}
-
- if (_region) {
- _editor->commit_reversible_command ();
- }
-}
-
-void
-RegionCreateDrag::add_region ()
-{
- if (_editor->session()) {
- const TempoMap& map (_editor->session()->tempo_map());
- framecnt_t pos = grab_frame();
- const Meter& m = map.meter_at (pos);
- /* not that the frame rate used here can be affected by pull up/down which
- might be wrong.
- */
- framecnt_t len = m.frames_per_bar (map.tempo_at (pos), _editor->session()->frame_rate());
- _region = _view->add_region (grab_frame(), len, false);
- }
}
void
NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*ignored*/)
{
Gdk::Cursor* cursor;
- ArdourCanvas::CanvasNoteEvent* cnote = dynamic_cast<ArdourCanvas::CanvasNoteEvent*>(_item);
+ NoteBase* cnote = reinterpret_cast<NoteBase*> (_item->get_data ("notebase"));
+ assert (cnote);
float x_fraction = cnote->mouse_x_fraction ();
if (x_fraction > 0.0 && x_fraction < 0.25) {
region = &cnote->region_view();
double const region_start = region->get_position_pixels();
- double const middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
+ double const middle_point = region_start + cnote->x0() + (cnote->x1() - cnote->x0()) / 2.0L;
if (grab_x() <= middle_point) {
cursor = _editor->cursors()->left_side_trim;
at_front = false;
}
- _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, *cursor, event->motion.time);
+ _item->grab ();
if (event->motion.state & Keyboard::PrimaryModifier) {
relative = false;
{
MidiRegionSelection& ms (_editor->get_selection().midi_regions);
for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
- (*r)->update_resizing (dynamic_cast<ArdourCanvas::CanvasNoteEvent*>(_item), at_front, _drags->current_pointer_x() - grab_x(), relative);
+ NoteBase* nb = reinterpret_cast<NoteBase*> (_item->get_data ("notebase"));
+ assert (nb);
+ (*r)->update_resizing (nb, at_front, _drags->current_pointer_x() - grab_x(), relative);
}
}
{
MidiRegionSelection& ms (_editor->get_selection().midi_regions);
for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
- (*r)->commit_resizing (dynamic_cast<ArdourCanvas::CanvasNoteEvent*>(_item), at_front, _drags->current_pointer_x() - grab_x(), relative);
+ NoteBase* nb = reinterpret_cast<NoteBase*> (_item->get_data ("notebase"));
+ assert (nb);
+ (*r)->commit_resizing (nb, at_front, _drags->current_pointer_x() - grab_x(), relative);
}
}
}
}
-RegionGainDrag::RegionGainDrag (Editor* e, ArdourCanvas::Item* i)
+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 RegionGainDrag\n");
+ 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
-RegionGainDrag::motion (GdkEvent* /*event*/, bool)
+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(dt);
+
+ 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
-RegionGainDrag::finished (GdkEvent *, bool)
+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
-RegionGainDrag::aborted (bool)
+VideoTimeLineDrag::aborted (bool)
{
- /* XXX: TODO */
+ 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)
+TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool preserve_fade_anchor)
: RegionDrag (e, i, p, v)
{
DEBUG_TRACE (DEBUG::Drags, "New TrimDrag\n");
+ _preserve_fade_anchor = preserve_fade_anchor;
}
void
if (arv) {
arv->temporarily_hide_envelope ();
+ arv->drag_start ();
}
boost::shared_ptr<Playlist> pl = rv->region()->playlist();
switch (_operation) {
case StartTrim:
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- i->view->trim_front (i->initial_position + dt, non_overlap_trim);
+ bool changed = i->view->trim_front (i->initial_position + dt, non_overlap_trim);
+ if (changed && _preserve_fade_anchor) {
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
+ if (arv) {
+ double distance;
+ double new_length;
+ framecnt_t len;
+ boost::shared_ptr<AudioRegion> ar (arv->audio_region());
+ distance = _drags->current_pointer_x() - grab_x();
+ 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 (ar, new_length); //the grey shape
+ }
+ }
}
break;
case EndTrim:
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- i->view->trim_end (i->initial_end + dt, non_overlap_trim);
+ bool changed = i->view->trim_end (i->initial_end + dt, non_overlap_trim);
+ if (changed && _preserve_fade_anchor) {
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
+ if (arv) {
+ double distance;
+ double new_length;
+ framecnt_t len;
+ boost::shared_ptr<AudioRegion> ar (arv->audio_region());
+ distance = grab_x() - _drags->current_pointer_x();
+ 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 (ar, new_length); //the grey shape
+ }
+ }
}
break;
if (movement_occurred) {
motion (event, false);
- /* This must happen before the region's StatefulDiffCommand is created, as it may
- `correct' (ahem) the region's _start from being negative to being zero. It
- needs to be zero in the undo record.
- */
if (_operation == StartTrim) {
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- i->view->trim_front_ending ();
+ {
+ /* This must happen before the region's StatefulDiffCommand is created, as it may
+ `correct' (ahem) the region's _start from being negative to being zero. It
+ needs to be zero in the undo record.
+ */
+ i->view->trim_front_ending ();
+ }
+ if (_preserve_fade_anchor) {
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
+ if (arv) {
+ double distance;
+ double new_length;
+ framecnt_t len;
+ boost::shared_ptr<AudioRegion> ar (arv->audio_region());
+ distance = _drags->current_pointer_x() - grab_x();
+ len = ar->fade_in()->back()->when;
+ new_length = len - _editor->unit_to_frame (distance);
+ new_length = ar->verify_xfade_bounds (new_length, true /*START*/ );
+ ar->set_fade_in_length(new_length);
+ }
+ }
+ }
+ } else if (_operation == EndTrim) {
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ if (_preserve_fade_anchor) {
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
+ if (arv) {
+ double distance;
+ double new_length;
+ framecnt_t len;
+ boost::shared_ptr<AudioRegion> ar (arv->audio_region());
+ distance = _drags->current_pointer_x() - grab_x();
+ len = ar->fade_out()->back()->when;
+ new_length = len - _editor->unit_to_frame (distance);
+ new_length = ar->verify_xfade_bounds (new_length, false /*END*/ );
+ ar->set_fade_out_length(new_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)) {
_primary->thaw_after_trim ();
} else {
}
}
}
+
for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
(*p)->thaw ();
}
motion (event, false);
+ TempoMap& map (_editor->session()->tempo_map());
+ framepos_t beat_time = map.round_to_beat (last_pointer_frame(), 0);
Timecode::BBT_Time when;
- TempoMap& map (_editor->session()->tempo_map());
- map.bbt_time (last_pointer_frame(), when);
+ map.bbt_time (beat_time, when);
if (_copy == true) {
_editor->begin_reversible_command (_("copy tempo mark"));
Session* s = _editor->session ();
if (s->timecode_transmission_suspended ()) {
- framepos_t const f = _editor->playhead_cursor->current_frame;
+ framepos_t const f = _editor->playhead_cursor->current_frame ();
s->send_mmc_locate (f);
s->send_full_time_code (f);
}
{
Drag::start_grab (event, c);
- _grab_zoom = _editor->frames_per_unit;
+ _grab_zoom = _editor->frames_per_pixel;
framepos_t where = _editor->event_frame (event, 0, 0);
_editor->snap_to_with_modifier (where, event);
s->cancel_audition ();
}
- s->request_suspend_timecode_transmission ();
- while (!s->timecode_transmission_suspended ()) {
- /* twiddle our thumbs */
+
+ if (AudioEngine::instance()->connected()) {
+
+ /* do this only if we're the engine is connected
+ * because otherwise this request will never be
+ * serviced and we'll busy wait forever. likewise,
+ * notice if we are disconnected while waiting for the
+ * request to be serviced.
+ */
+
+ s->request_suspend_timecode_transmission ();
+ while (AudioEngine::instance()->connected() && !s->timecode_transmission_suspended ()) {
+ /* twiddle our thumbs */
+ }
}
}
Session* s = _editor->session ();
if (s) {
- s->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
+ s->request_locate (_editor->playhead_cursor->current_frame (), _was_rolling);
_editor->_pending_locate_request = true;
s->request_resume_timecode_transmission ();
}
boost::shared_ptr<AudioRegion> const r = arv->audio_region ();
show_verbose_cursor_duration (r->position(), r->position() + r->fade_in()->back()->when, 32);
-
- arv->show_fade_line((framepos_t) r->fade_in()->back()->when);
}
void
continue;
}
- tmp->reset_fade_in_shape_width (fade_length);
- tmp->show_fade_line((framecnt_t) fade_length);
+ tmp->reset_fade_in_shape_width (tmp->audio_region(), fade_length);
}
show_verbose_cursor_duration (region->position(), region->position() + fade_length, 32);
tmp->audio_region()->set_fade_in_length (fade_length);
tmp->audio_region()->set_fade_in_active (true);
- tmp->hide_fade_line();
XMLNode &after = alist->get_state();
_editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
continue;
}
- tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
- tmp->hide_fade_line();
+ tmp->reset_fade_in_shape_width (tmp->audio_region(), tmp->audio_region()->fade_in()->back()->when);
}
}
boost::shared_ptr<AudioRegion> r = arv->audio_region ();
show_verbose_cursor_duration (r->last_frame() - r->fade_out()->back()->when, r->last_frame());
-
- arv->show_fade_line(r->length() - r->fade_out()->back()->when);
}
void
continue;
}
- tmp->reset_fade_out_shape_width (fade_length);
- tmp->show_fade_line(region->length() - 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());
tmp->audio_region()->set_fade_out_length (fade_length);
tmp->audio_region()->set_fade_out_active (true);
- tmp->hide_fade_line();
XMLNode &after = alist->get_state();
_editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
continue;
}
- tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
- tmp->hide_fade_line();
+ tmp->reset_fade_out_shape_width (tmp->audio_region(), tmp->audio_region()->fade_out()->back()->when);
}
}
_marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
assert (_marker);
- _points.push_back (Gnome::Art::Point (0, 0));
- _points.push_back (Gnome::Art::Point (0, physical_screen_height (_editor->get_window())));
+ _points.push_back (ArdourCanvas::Duple (0, 0));
+ _points.push_back (ArdourCanvas::Duple (0, physical_screen_height (_editor->get_window())));
}
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());
}
}
}
event->button.x + 10, event->button.y + 10);
_editor->verbose_cursor()->show ();
+
+ _pushing = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
+
+ if (!_point->can_slide ()) {
+ _x_constrained = true;
+ }
}
void
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 (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 ();
}
double cx = event->button.x;
double cy = event->button.y;
- _line->parent_group().w2i (cx, cy);
+ _line->parent_group().canvas_to_item (cx, cy);
- framecnt_t const frame_within_region = (framecnt_t) floor (cx * _editor->frames_per_unit);
+ framecnt_t const frame_within_region = (framecnt_t) floor (cx * _editor->frames_per_pixel);
uint32_t before;
uint32_t after;
cy = min ((double) _line->height(), cy);
double const fraction = 1.0 - (cy / _line->height());
-
- bool push;
-
- if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
- push = false;
- } else {
- push = true;
- }
+ 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 ();
}
double cx = event->button.x;
double cy = event->button.y;
- _item->property_parent().get_value()->w2i(cx, cy);
+ _item->parent()->canvas_to_item (cx, cy);
/* store grab start in parent frame */
_region_view_grab_x = cx;
cx = 0;
}
- ArdourCanvas::Points points;
-
- double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
-
- _line->get_bounds(x1, y2, x2, y2);
-
- points.push_back(Gnome::Art::Point(cx, 2.0)); // first x-coord needs to be a non-normal value
- points.push_back(Gnome::Art::Point(cx, y2 - y1));
-
- _line->property_points() = points;
+ boost::optional<Rect> bbox = _line->bounding_box ();
+ assert (bbox);
+ _line->set (ArdourCanvas::Duple (cx, 2.0), ArdourCanvas::Duple (cx, bbox.get().height ()));
float *pos = new float;
*pos = cx;
RubberbandSelectDrag::RubberbandSelectDrag (Editor* e, ArdourCanvas::Item* i)
: Drag (e, i)
+ , _vertical_only (false)
{
DEBUG_TRACE (DEBUG::Drags, "New RubberbandSelectDrag\n");
}
double x1 = _editor->frame_to_pixel (start);
double x2 = _editor->frame_to_pixel (end);
- _editor->rubberband_rect->property_x1() = x1;
- _editor->rubberband_rect->property_y1() = y1;
- _editor->rubberband_rect->property_x2() = x2;
- _editor->rubberband_rect->property_y2() = y2;
+ _editor->rubberband_rect->set_x0 (x1);
+ if (_vertical_only) {
+ /* fixed 10 pixel width */
+ _editor->rubberband_rect->set_x1 (x1 + 10);
+ } else {
+ _editor->rubberband_rect->set_x1 (x2);
+ }
+
+ _editor->rubberband_rect->set_y0 (y1);
+ _editor->rubberband_rect->set_y1 (y2);
_editor->rubberband_rect->show();
_editor->rubberband_rect->raise_to_top();
} else {
- deselect_things ();
+ /* just a click */
+
+ bool do_deselect = true;
+ MidiTimeAxisView* mtv;
+
+ if ((mtv = dynamic_cast<MidiTimeAxisView*>(_editor->clicked_axisview)) != 0) {
+ /* MIDI track */
+ if (_editor->selection->empty()) {
+ /* nothing selected */
+ add_midi_region (mtv);
+ do_deselect = false;
+ }
+ }
+
+ /* do not deselect if Primary or Tertiary (toggle-select or
+ * extend-select are pressed.
+ */
+
+ if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier) &&
+ !Keyboard::modifier_state_contains (event->button.state, Keyboard::TertiaryModifier) &&
+ do_deselect) {
+ deselect_things ();
+ }
}
TimeFXDrag::motion (GdkEvent* event, bool)
{
RegionView* rv = _primary;
+ StreamView* cv = rv->get_time_axis_view().view ();
+
+ pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (grab_y());
+ int layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
+ int layers = tv.first->layer_display() == Overlaid ? 1 : cv->layers();
framepos_t const pf = adjusted_current_frame (event);
if (pf > rv->region()->position()) {
- rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
+ rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf, layers, layer);
}
show_verbose_cursor_time (pf);
}
#endif
- // XXX how do timeFX on multiple regions ?
-
- RegionSelection rs;
- rs.add (_primary);
+ if (!_editor->get_selection().regions.empty()) {
+ /* primary will already be included in the selection, and edit
+ group shared editing will propagate selection across
+ equivalent regions, so just use the current region
+ selection.
+ */
- if (_editor->time_stretch (rs, percentage) == -1) {
- error << _("An error occurred while executing time stretch operation") << endmsg;
+ if (_editor->time_stretch (_editor->get_selection().regions, percentage) == -1) {
+ error << _("An error occurred while executing time stretch operation") << endmsg;
+ }
}
}
SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
: Drag (e, i)
, _operation (o)
- , _copy (false)
+ , _add (false)
+ , _extend (false)
, _original_pointer_time_axis (-1)
, _last_pointer_time_axis (-1)
+ , _time_selection_at_start (!_editor->get_selection().time.empty())
{
DEBUG_TRACE (DEBUG::Drags, "New SelectionDrag\n");
+
+ if (_time_selection_at_start) {
+ start_at_start = _editor->get_selection().time.start();
+ end_at_start = _editor->get_selection().time.end_frame();
+ }
}
void
switch (_operation) {
case CreateSelection:
- if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
- _copy = true;
+ if (Keyboard::modifier_state_equals (event->button.state, Keyboard::CopyModifier)) {
+ _add = true;
} else {
- _copy = false;
+ _add = false;
}
cursor = _editor->cursors()->selector;
Drag::start_grab (event, cursor);
case SelectionMove:
Drag::start_grab (event, cursor);
break;
+
+ case SelectionExtend:
+ Drag::start_grab (event, cursor);
+ break;
}
if (_operation == SelectionMove) {
case SelectionEndTrim:
_pointer_frame_offset = raw_grab_frame() - _editor->selection->time[_editor->clicked_selection].end;
break;
+
+ case SelectionExtend:
+ break;
}
}
{
framepos_t start = 0;
framepos_t end = 0;
- framecnt_t length;
+ framecnt_t length = 0;
+ framecnt_t distance = 0;
pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
if (pending_time_axis.first == 0) {
framepos_t grab = grab_frame ();
if (first_move) {
- _editor->snap_to (grab);
+ grab = adjusted_current_frame (event, false);
+ if (grab < pending_position) {
+ _editor->snap_to (grab, -1);
+ } else {
+ _editor->snap_to (grab, 1);
+ }
}
- if (pending_position < grab_frame()) {
+ if (pending_position < grab) {
start = pending_position;
end = grab;
} else {
if (first_move) {
- if (_copy) {
+ if (_add) {
/* adding to the selection */
_editor->set_selected_track_as_side_effect (Selection::Add);
//_editor->selection->add (_editor->clicked_axisview);
_editor->clicked_selection = _editor->selection->add (start, end);
- _copy = false;
+ _add = false;
} else {
/* new selection */
}
break;
-
+
case SelectionMove:
start = _editor->selection->time[_editor->clicked_selection].start;
end = _editor->selection->time[_editor->clicked_selection].end;
length = end - start;
-
+ distance = pending_position - start;
start = pending_position;
_editor->snap_to (start);
end = start + length;
break;
+
+ case SelectionExtend:
+ break;
}
- if (event->button.x >= _editor->horizontal_position() + _editor->_canvas_width) {
+ if (event->button.x >= _editor->horizontal_position() + _editor->_visible_canvas_width) {
_editor->start_canvas_autoscroll (1, 0);
}
if (start != end) {
- _editor->selection->replace (_editor->clicked_selection, start, end);
+ switch (_operation) {
+ case SelectionMove:
+ if (_time_selection_at_start) {
+ _editor->selection->move_time (distance);
+ }
+ break;
+ default:
+ _editor->selection->replace (_editor->clicked_selection, start, end);
+ }
}
if (_operation == SelectionMove) {
}
/* XXX what if its a music time selection? */
- if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
- s->request_play_range (&_editor->selection->time, true);
+ if (s) {
+ if ( s->get_play_range() && s->transport_rolling() ) {
+ s->request_play_range (&_editor->selection->time, true);
+ } else {
+ if (Config->get_always_play_range() && !s->transport_rolling()) {
+ s->request_locate (_editor->get_selection().time.start());
+ }
+ }
}
-
} else {
- /* just a click, no pointer movement.*/
+ /* just a click, no pointer movement.
+ */
- if (Keyboard::no_modifier_keys_pressed (&event->button)) {
- _editor->selection->clear_time();
+ if (_operation == SelectionExtend) {
+ if (_time_selection_at_start) {
+ framepos_t pos = adjusted_current_frame (event, false);
+ framepos_t start = min (pos, start_at_start);
+ framepos_t end = max (pos, end_at_start);
+ _editor->selection->set (start, end);
+ }
+ } else {
+ if (Keyboard::modifier_state_equals (event->button.state, Keyboard::CopyModifier)) {
+ if (_editor->clicked_selection) {
+ _editor->selection->remove (_editor->clicked_selection);
+ }
+ } else {
+ if (!_editor->clicked_selection) {
+ _editor->selection->clear_time();
+ }
+ }
}
if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
_editor->selection->set (_editor->clicked_axisview);
}
-
+
if (s && s->get_play_range () && s->transport_rolling()) {
s->request_stop (false, false);
}
}
_editor->stop_canvas_autoscroll ();
+ _editor->clicked_selection = 0;
}
void
{
DEBUG_TRACE (DEBUG::Drags, "New RangeMarkerBarDrag\n");
- _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0,
- physical_screen_height (_editor->get_window()));
+ _drag_rect = new ArdourCanvas::Rectangle (_editor->time_line_group,
+ ArdourCanvas::Rect (0.0, 0.0, 0.0,
+ physical_screen_height (_editor->get_window())));
_drag_rect->hide ();
- _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
- _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
+ _drag_rect->set_fill_color (ARDOUR_UI::config()->canvasvar_RangeDragRect.get());
+ _drag_rect->set_outline_color (ARDOUR_UI::config()->canvasvar_RangeDragRect.get());
}
void
{
framepos_t start = 0;
framepos_t end = 0;
- ArdourCanvas::SimpleRect *crect;
+ ArdourCanvas::Rectangle *crect;
switch (_operation) {
case CreateRangeMarker:
crect = _editor->cd_marker_bar_drag_rect;
break;
default:
- cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
+ error << string_compose (_("programming_error: %1"), "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()") << endmsg;
return;
break;
}
}
}
- if (event->button.x >= _editor->horizontal_position() + _editor->_canvas_width) {
+ if (event->button.x >= _editor->horizontal_position() + _editor->_visible_canvas_width) {
_editor->start_canvas_autoscroll (1, 0);
}
double x1 = _editor->frame_to_pixel (start);
double x2 = _editor->frame_to_pixel (end);
- crect->property_x1() = x1;
- crect->property_x2() = x2;
+ crect->set_x0 (x1);
+ crect->set_x1 (x2);
update_item (_editor->temp_location);
}
double const x1 = _editor->frame_to_pixel (location->start());
double const x2 = _editor->frame_to_pixel (location->end());
- _drag_rect->property_x1() = x1;
- _drag_rect->property_x2() = x2;
+ _drag_rect->set_x0 (x1);
+ _drag_rect->set_x1 (x2);
}
MouseZoomDrag::MouseZoomDrag (Editor* e, ArdourCanvas::Item* i)
motion (event, false);
if (grab_frame() < last_pointer_frame()) {
- _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
+ _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame());
} else {
- _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
+ _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame());
}
} else {
if (Keyboard::the_keyboard().key_is_down (GDK_Shift_L)) {
{
DEBUG_TRACE (DEBUG::Drags, "New NoteDrag\n");
- _primary = dynamic_cast<CanvasNoteEvent*> (_item);
+ _primary = reinterpret_cast<NoteBase*> (_item->get_data ("notebase"));
+ assert (_primary);
_region = &_primary->region_view ();
_note_height = _region->midi_stream_view()->note_height ();
}
int8_t
NoteDrag::total_dy () const
{
- return ((int8_t) (grab_y() / _note_height)) - ((int8_t) (_drags->current_pointer_y() / _note_height));
+ MidiStreamView* msv = _region->midi_stream_view ();
+ double const y = _region->midi_view()->y_position ();
+ /* new current note */
+ uint8_t n = msv->y_to_note (_drags->current_pointer_y () - y);
+ /* clamp */
+ n = max (msv->lowest_note(), n);
+ n = min (msv->highest_note(), n);
+ /* and work out delta */
+ return n - msv->y_to_note (grab_y() - y);
}
void
NoteDrag::finished (GdkEvent* ev, bool moved)
{
if (!moved) {
- if (_editor->current_mouse_mode() == Editing::MouseObject) {
-
+ /* no motion - select note */
+
+ if (_editor->current_mouse_mode() == Editing::MouseObject ||
+ _editor->current_mouse_mode() == Editing::MouseDraw) {
+
if (_was_selected) {
bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
if (add) {
/* XXX: TODO */
}
-AutomationRangeDrag::AutomationRangeDrag (Editor* editor, ArdourCanvas::Item* item, list<AudioRange> const & r)
- : Drag (editor, item)
+/** Make an AutomationRangeDrag for lines in an AutomationTimeAxisView */
+AutomationRangeDrag::AutomationRangeDrag (Editor* editor, AutomationTimeAxisView* atv, list<AudioRange> const & r)
+ : Drag (editor, atv->base_item ())
, _ranges (r)
, _nothing_to_drag (false)
{
DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n");
+ y_origin = atv->y_position();
+ setup (atv->lines ());
+}
- _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
- assert (_atav);
+/** Make an AutomationRangeDrag for region gain lines */
+AutomationRangeDrag::AutomationRangeDrag (Editor* editor, AudioRegionView* rv, list<AudioRange> const & r)
+ : Drag (editor, rv->get_canvas_group ())
+ , _ranges (r)
+ , _nothing_to_drag (false)
+{
+ DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n");
- /* get all lines in the automation view */
- list<boost::shared_ptr<AutomationLine> > lines = _atav->lines ();
+ list<boost::shared_ptr<AutomationLine> > lines;
+ lines.push_back (rv->get_gain_line ());
+ y_origin = rv->get_time_axis_view().y_position();
+ setup (lines);
+}
- /* find those that overlap the ranges being dragged */
- list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin ();
+/** @param lines AutomationLines to drag.
+ * @param offset Offset from the session start to the points in the AutomationLines.
+ */
+void
+AutomationRangeDrag::setup (list<boost::shared_ptr<AutomationLine> > const & lines)
+{
+ /* find the lines that overlap the ranges being dragged */
+ list<boost::shared_ptr<AutomationLine> >::const_iterator i = lines.begin ();
while (i != lines.end ()) {
- list<boost::shared_ptr<AutomationLine> >::iterator j = i;
+ list<boost::shared_ptr<AutomationLine> >::const_iterator j = i;
++j;
- pair<framepos_t, framepos_t> const r = (*i)->get_point_x_range ();
+ pair<framepos_t, framepos_t> r = (*i)->get_point_x_range ();
/* check this range against all the AudioRanges that we are using */
list<AudioRange>::const_iterator k = _ranges.begin ();
while (k != _ranges.end()) {
- if (k->coverage (r.first, r.second) != OverlapNone) {
+ if (k->coverage (r.first, r.second) != Evoral::OverlapNone) {
break;
}
++k;
/* Now ::lines contains the AutomationLines that somehow overlap our drag */
}
+double
+AutomationRangeDrag::y_fraction (boost::shared_ptr<AutomationLine> line, double global_y) const
+{
+ return 1.0 - ((global_y - y_origin) / line->height());
+}
+
void
AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
{
/* Get line states before we start changing things */
for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
i->state = &i->line->get_state ();
+ i->original_fraction = y_fraction (i->line, _drags->current_pointer_y());
}
if (_ranges.empty()) {
double const q = j->line->time_converter().from (a - j->line->time_converter().origin_b ());
the_list->add (p, the_list->eval (p));
- j->line->add_always_in_view (p);
the_list->add (q, the_list->eval (q));
- j->line->add_always_in_view (q);
}
/* same thing for the end */
double const q = j->line->time_converter().from (i->end - j->line->time_converter().origin_b ());
the_list->add (p, the_list->eval (p));
- j->line->add_always_in_view (p);
the_list->add (q, the_list->eval (q));
- j->line->add_always_in_view (q);
}
}
}
for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
- i->line->start_drag_multiple (i->points, 1 - (_drags->current_pointer_y() / i->line->height ()), i->state);
+ i->line->start_drag_multiple (i->points, y_fraction (i->line, _drags->current_pointer_y()), i->state);
}
}
return;
}
- for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
- float const f = 1 - (_drags->current_pointer_y() / i->line->height());
-
+ 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 */
- i->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->clear_always_in_view ();
+ i->line->end_drag (false, 0);
}
_editor->session()->commit_reversible_command ();
AutomationRangeDrag::aborted (bool)
{
for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
- i->line->clear_always_in_view ();
i->line->reset ();
}
}
{
time_axis_view = parent->find_time_axis_view (&v->get_time_axis_view ());
layer = v->region()->layer ();
- initial_y = v->get_canvas_group()->property_y ();
+ initial_y = v->get_canvas_group()->position().y;
initial_playlist = v->region()->playlist ();
initial_position = v->region()->position ();
initial_end = v->region()->position () + v->region()->length ();
}
-PatchChangeDrag::PatchChangeDrag (Editor* e, CanvasPatchChange* i, MidiRegionView* r)
- : Drag (e, i)
+PatchChangeDrag::PatchChangeDrag (Editor* e, PatchChange* i, MidiRegionView* r)
+ : Drag (e, i->canvas_item ())
, _region_view (r)
, _patch_change (i)
, _cumulative_dx (0)
{
- DEBUG_TRACE (DEBUG::Drags, "New PatchChangeDrag\n");
+ DEBUG_TRACE (DEBUG::Drags, string_compose ("New PatchChangeDrag, patch @ %1, grab @ %2\n",
+ _region_view->source_beats_to_absolute_frames (_patch_change->patch()->time()),
+ grab_frame()));
}
void
f = max (f, r->position ());
f = min (f, r->last_frame ());
- framecnt_t const dxf = f - grab_frame();
- double const dxu = _editor->frame_to_unit (dxf);
- _patch_change->move (dxu - _cumulative_dx, 0);
+ framecnt_t const dxf = f - grab_frame(); // permitted dx in frames
+ double const dxu = _editor->frame_to_unit (dxf); // permitted fx in units
+ _patch_change->move (ArdourCanvas::Duple (dxu - _cumulative_dx, 0));
_cumulative_dx = dxu;
}
}
boost::shared_ptr<Region> r (_region_view->region ());
-
framepos_t f = adjusted_current_frame (ev);
f = max (f, r->position ());
f = min (f, r->last_frame ());
_region_view->move_patch_change (
*_patch_change,
- _region_view->region_frames_to_region_beats (f - r->position() - r->start())
+ _region_view->region_frames_to_region_beats (f - (r->position() - r->start()))
);
}
void
PatchChangeDrag::aborted (bool)
{
- _patch_change->move (-_cumulative_dx, 0);
+ _patch_change->move (ArdourCanvas::Duple (-_cumulative_dx, 0));
}
void
}
void
-MidiRubberbandSelectDrag::select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool drag_in_progress)
+MidiRubberbandSelectDrag::select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool /*drag_in_progress*/)
{
framepos_t const p = _region_view->region()->position ();
double const y = _region_view->midi_view()->y_position ();
/* XXX */
}
+MidiVerticalSelectDrag::MidiVerticalSelectDrag (Editor* e, MidiRegionView* rv)
+ : RubberbandSelectDrag (e, rv->get_canvas_frame ())
+ , _region_view (rv)
+{
+ _vertical_only = true;
+}
+
+void
+MidiVerticalSelectDrag::select_things (int button_state, framepos_t /*x1*/, framepos_t /*x2*/, double y1, double y2, bool /*drag_in_progress*/)
+{
+ double const y = _region_view->midi_view()->y_position ();
+
+ y1 = max (0.0, y1 - y);
+ y2 = max (0.0, y2 - y);
+
+ _region_view->update_vertical_drag_selection (
+ y1,
+ y2,
+ Keyboard::modifier_state_contains (button_state, Keyboard::TertiaryModifier)
+ );
+}
+
+void
+MidiVerticalSelectDrag::deselect_things ()
+{
+ /* XXX */
+}
+
EditorRubberbandSelectDrag::EditorRubberbandSelectDrag (Editor* e, ArdourCanvas::Item* i)
: RubberbandSelectDrag (e, i)
{
{
Drag::start_grab (event, cursor);
- _drag_rect = new ArdourCanvas::SimpleRect (*_region_view->get_canvas_group ());
+ _drag_rect = new ArdourCanvas::Rectangle (_region_view->get_canvas_group ());
framepos_t pf = _drags->current_pointer_frame ();
framecnt_t const g = grid_frames (pf);
double const x = _editor->frame_to_pixel (_note[0]);
double const y = sv->note_to_y (sv->y_to_note (y_to_region (event->button.y)));
- _drag_rect->property_x1() = x;
- _drag_rect->property_y1() = y;
- _drag_rect->property_x2() = x;
- _drag_rect->property_y2() = y + floor (_region_view->midi_stream_view()->note_height ());
-
- _drag_rect->property_outline_what() = 0xff;
- _drag_rect->property_outline_color_rgba() = 0xffffff99;
- _drag_rect->property_fill_color_rgba() = 0xffffff66;
+ _drag_rect->set (ArdourCanvas::Rect (x, y, x, y + floor (_region_view->midi_stream_view()->note_height ())));
+ _drag_rect->set_outline_what (0xff);
+ _drag_rect->set_outline_color (0xffffff99);
+ _drag_rect->set_fill_color (0xffffff66);
}
void
NoteCreateDrag::motion (GdkEvent* event, bool)
{
- _note[1] = adjusted_current_frame (event) - _region_view->region()->position ();
+ _note[1] = max ((framepos_t)0, adjusted_current_frame (event) - _region_view->region()->position ());
double const x = _editor->frame_to_pixel (_note[1]);
if (_note[1] > _note[0]) {
- _drag_rect->property_x2() = x;
+ _drag_rect->set_x1 (x);
} else {
- _drag_rect->property_x1() = x;
+ _drag_rect->set_x0 (x);
}
}
void
-NoteCreateDrag::finished (GdkEvent* event, bool had_movement)
+NoteCreateDrag::finished (GdkEvent*, bool had_movement)
{
if (!had_movement) {
return;
}
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;
double const length_beats = max (one_tick, _region_view->region_frames_to_region_beats (length));
- _region_view->create_note_at (start, _drag_rect->property_y1(), length_beats, false);
+ _region_view->create_note_at (start, _drag_rect->y0(), length_beats, false);
}
double
NoteCreateDrag::y_to_region (double y) const
{
double x = 0;
- _region_view->get_canvas_group()->w2i (x, y);
+ _region_view->get_canvas_group()->canvas_to_item (x, y);
return y;
}
{
}
+
+CrossfadeEdgeDrag::CrossfadeEdgeDrag (Editor* e, AudioRegionView* rv, ArdourCanvas::Item* i, bool start_yn)
+ : Drag (e, i)
+ , arv (rv)
+ , start (start_yn)
+{
+ std::cout << ("CrossfadeEdgeDrag is DEPRECATED. See TrimDrag::preserve_fade_anchor") << endl;
+}
+
+void
+CrossfadeEdgeDrag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
+{
+ Drag::start_grab (event, cursor);
+}
+
+void
+CrossfadeEdgeDrag::motion (GdkEvent*, bool)
+{
+ double distance;
+ double new_length;
+ framecnt_t len;
+
+ boost::shared_ptr<AudioRegion> ar (arv->audio_region());
+
+ if (start) {
+ distance = _drags->current_pointer_x() - grab_x();
+ len = ar->fade_in()->back()->when;
+ } else {
+ distance = grab_x() - _drags->current_pointer_x();
+ len = ar->fade_out()->back()->when;
+ }
+
+ /* how long should it be ? */
+
+ new_length = len + _editor->unit_to_frame (distance);
+
+ /* now check with the region that this is legal */
+
+ new_length = ar->verify_xfade_bounds (new_length, start);
+
+ if (start) {
+ arv->redraw_start_xfade_to (ar, new_length);
+ } else {
+ arv->redraw_end_xfade_to (ar, new_length);
+ }
+}
+
+void
+CrossfadeEdgeDrag::finished (GdkEvent*, bool)
+{
+ double distance;
+ double new_length;
+ framecnt_t len;
+
+ boost::shared_ptr<AudioRegion> ar (arv->audio_region());
+
+ if (start) {
+ distance = _drags->current_pointer_x() - grab_x();
+ len = ar->fade_in()->back()->when;
+ } else {
+ distance = grab_x() - _drags->current_pointer_x();
+ len = ar->fade_out()->back()->when;
+ }
+
+ new_length = ar->verify_xfade_bounds (len + _editor->unit_to_frame (distance), start);
+
+ _editor->begin_reversible_command ("xfade trim");
+ ar->playlist()->clear_owned_changes ();
+
+ if (start) {
+ ar->set_fade_in_length (new_length);
+ } else {
+ ar->set_fade_out_length (new_length);
+ }
+
+ /* Adjusting the xfade may affect other regions in the playlist, so we need
+ to get undo Commands from the whole playlist rather than just the
+ region.
+ */
+
+ vector<Command*> cmds;
+ ar->playlist()->rdiff (cmds);
+ _editor->session()->add_commands (cmds);
+ _editor->commit_reversible_command ();
+
+}
+
+void
+CrossfadeEdgeDrag::aborted (bool)
+{
+ if (start) {
+ arv->redraw_start_xfade ();
+ } else {
+ arv->redraw_end_xfade ();
+ }
+}
+