First cut of some Pro-tools inspired editing features; linked play/play range

and linked object/range modes.


git-svn-id: svn://localhost/ardour2/branches/3.0@6431 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Carl Hetherington 2010-01-01 22:11:15 +00:00
parent 6572f421a4
commit f5acf93672
18 changed files with 582 additions and 186 deletions

View file

@ -1558,8 +1558,13 @@ ARDOUR_UI::transport_roll ()
if (_session->get_play_loop()) {
_session->request_play_loop (false, true);
} else if (_session->get_play_range ()) {
_session->request_play_range (false, true);
} else if (_session->get_play_range () && !join_play_range_button.get_active()) {
/* stop playing a range if we currently are */
_session->request_play_range (0, true);
}
if (join_play_range_button.get_active()) {
_session->request_play_range (&editor->get_selection().time, true);
}
if (!rolling) {
@ -1619,6 +1624,10 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
if (rolling) {
_session->request_stop (with_abort, true);
} else {
if (join_play_range_button.get_active()) {
_session->request_play_range (&editor->get_selection().time, true);
}
_session->request_transport_speed (1.0f);
}
}
@ -1761,6 +1770,8 @@ ARDOUR_UI::map_transport_state ()
if (sp != 0.0) {
/* we're rolling */
if (_session->get_play_range()) {
play_selection_button.set_visual_state (1);
@ -1780,6 +1791,12 @@ ARDOUR_UI::map_transport_state ()
auto_loop_button.set_visual_state (0);
}
if (join_play_range_button.get_active()) {
/* light up both roll and play-selection if they are joined */
roll_button.set_visual_state (1);
play_selection_button.set_visual_state (1);
}
stop_button.set_visual_state (0);
} else {

View file

@ -328,6 +328,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
Gtkmm2ext::TearOff* transport_tearoff;
Gtk::Frame transport_frame;
Gtk::HBox transport_tearoff_hbox;
Gtk::HBox play_range_hbox;
Gtk::VBox play_range_vbox;
Gtk::HBox transport_hbox;
Gtk::Fixed transport_base;
Gtk::Fixed transport_button_base;
@ -385,6 +387,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
BindableButton auto_loop_button;
BindableButton play_selection_button;
BindableButton rec_button;
Gtk::ToggleButton join_play_range_button;
void toggle_external_sync ();
void toggle_time_master ();

View file

@ -178,6 +178,7 @@ ARDOUR_UI::setup_transport ()
play_selection_button.set_name ("TransportButton");
rec_button.set_name ("TransportRecButton");
auto_loop_button.set_name ("TransportButton");
join_play_range_button.set_name ("TransportButton");
auto_return_button.set_name ("TransportButton");
auto_play_button.set_name ("TransportButton");
@ -221,6 +222,9 @@ ARDOUR_UI::setup_transport ()
w = manage (new Image (get_icon (X_("transport_loop"))));
w->show();
auto_loop_button.add (*w);
w = manage (new Image (get_icon (X_("join_tools"))));
w->show ();
join_play_range_button.add (*w);
RefPtr<Action> act;
@ -361,11 +365,17 @@ ARDOUR_UI::setup_transport ()
transport_tearoff_hbox.pack_start (*svbox, false, false, 3);
transport_tearoff_hbox.pack_start (auto_loop_button, false, false);
if (!Profile->get_sae()) {
transport_tearoff_hbox.pack_start (play_selection_button, false, false);
if (Profile->get_sae()) {
transport_tearoff_hbox.pack_start (auto_loop_button);
transport_tearoff_hbox.pack_start (roll_button);
} else {
transport_tearoff_hbox.pack_start (auto_loop_button, false, false);
play_range_hbox.pack_start (play_selection_button, false, false);
play_range_hbox.pack_start (roll_button, false, false);
play_range_vbox.pack_start (play_range_hbox, false, false);
play_range_vbox.pack_start (join_play_range_button, false, false);
transport_tearoff_hbox.pack_start (play_range_vbox, false, false);
}
transport_tearoff_hbox.pack_start (roll_button, false, false);
transport_tearoff_hbox.pack_start (stop_button, false, false);
transport_tearoff_hbox.pack_start (rec_button, false, false, 6);

View file

@ -239,7 +239,7 @@ AutomationLine::modify_point_y (ControlPoint& cp, double y)
void
AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool with_push)
AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool keep_x, bool with_push)
{
double delta = 0.0;
uint32_t last_movable = UINT_MAX;
@ -257,7 +257,7 @@ AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool wi
y = min (1.0, y);
y = _height - (y * _height);
if (cp.can_slide()) {
if (cp.can_slide() && !keep_x) {
/* x-coord cannot move beyond adjacent points or the start/end, and is
already in frames. it needs to be converted to canvas units.
@ -362,15 +362,12 @@ AutomationLine::reset_line_coords (ControlPoint& cp)
}
void
AutomationLine::sync_model_with_view_line (uint32_t start, uint32_t end)
AutomationLine::sync_model_with_view_points (list<ControlPoint*> cp, bool did_push, int64_t distance)
{
ControlPoint *p;
update_pending = true;
for (uint32_t i = start; i <= end; ++i) {
p = nth(i);
sync_model_with_view_point (*p, false, 0);
for (list<ControlPoint*>::iterator i = cp.begin(); i != cp.end(); ++i) {
sync_model_with_view_point (**i, did_push, distance);
}
}
@ -488,6 +485,14 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
double tx = points[pi].x;
double ty = points[pi].y;
if (find (_always_in_view.begin(), _always_in_view.end(), (*model)->when) != _always_in_view.end()) {
add_visible_control_point (view_index, pi, tx, ty, model, npoints);
prev_rx = this_rx;
prev_ry = this_ry;
++view_index;
continue;
}
if (isnan (tx) || isnan (ty)) {
warning << string_compose (_("Ignoring illegal points on AutomationLine \"%1\""),
_name) << endmsg;
@ -667,66 +672,36 @@ AutomationLine::invalidate_point (ALPoints& p, uint32_t index)
p[index].y = DBL_MAX;
}
/** Start dragging a single point.
* @param cp Point to drag.
* @param x Initial x position (frames).
* @param fraction Initial y position (as a fraction of the track height, where 0 is the bottom and 1 the top)
*/
void
AutomationLine::start_drag (ControlPoint* cp, nframes_t x, float fraction)
AutomationLine::start_drag_single (ControlPoint* cp, nframes_t x, float fraction)
{
if (trackview.editor().session() == 0) { /* how? */
return;
}
string str;
if (cp) {
str = _("automation event move");
} else {
str = _("automation range drag");
}
trackview.editor().session()->begin_reversible_command (str);
trackview.editor().session()->begin_reversible_command (_("automation event move"));
trackview.editor().session()->add_command (new MementoCommand<AutomationList>(*alist.get(), &get_state(), 0));
drag_x = x;
drag_distance = 0;
first_drag_fraction = fraction;
last_drag_fraction = fraction;
drags = 0;
did_push = false;
_drag_points.clear ();
_drag_points.push_back (cp);
start_drag_common (x, fraction);
}
/** Start dragging a line vertically (with no change in x)
* @param i1 Control point index of the `left' point on the line.
* @param i2 Control point index of the `right' point on the line.
* @param fraction Initial y position (as a fraction of the track height, where 0 is the bottom and 1 the top)
*/
void
AutomationLine::point_drag (ControlPoint& cp, nframes_t x, float fraction, bool with_push)
AutomationLine::start_drag_line (uint32_t i1, uint32_t i2, float fraction)
{
if (x > drag_x) {
drag_distance += (x - drag_x);
} else {
drag_distance -= (drag_x - x);
}
trackview.editor().session()->begin_reversible_command (_("automation range move"));
trackview.editor().session()->add_command (new MementoCommand<AutomationList>(*alist.get(), &get_state(), 0));
drag_x = x;
_drag_points.clear ();
modify_view_point (cp, x, fraction, with_push);
if (line_points.size() > 1) {
line->property_points() = line_points;
}
drags++;
did_push = with_push;
}
void
AutomationLine::line_drag (uint32_t i1, uint32_t i2, float fraction, bool with_push)
{
double ydelta = fraction - last_drag_fraction;
did_push = with_push;
last_drag_fraction = fraction;
line_drag_cp1 = i1;
line_drag_cp2 = i2;
//check if one of the control points on the line is in a selected range
// check if one of the control points on the line is in a selected range
bool range_found = false;
ControlPoint *cp;
@ -740,38 +715,92 @@ AutomationLine::line_drag (uint32_t i1, uint32_t i2, float fraction, bool with_p
if (range_found) {
for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
if ((*i)->selected()) {
modify_view_point (*(*i), trackview.editor().unit_to_frame ((*i)->get_x()), ((_height - (*i)->get_y()) /_height) + ydelta, with_push);
_drag_points.push_back (*i);
}
}
} else {
ControlPoint *cp;
for (uint32_t i = i1 ; i <= i2; i++) {
cp = nth (i);
modify_view_point (*cp, trackview.editor().unit_to_frame (cp->get_x()), ((_height - cp->get_y()) /_height) + ydelta, with_push);
_drag_points.push_back (nth (i));
}
}
start_drag_common (0, fraction);
}
/** Start dragging multiple points (with no change in x)
* @param cp Points to drag.
* @param fraction Initial y position (as a fraction of the track height, where 0 is the bottom and 1 the top)
*/
void
AutomationLine::start_drag_multiple (list<ControlPoint*> cp, float fraction, XMLNode* state)
{
trackview.editor().session()->begin_reversible_command (_("automation range move"));
trackview.editor().session()->add_command (new MementoCommand<AutomationList>(*alist.get(), state, 0));
_drag_points = cp;
start_drag_common (0, fraction);
}
/** Common parts of starting a drag.
* @param d Description of the drag.
* @param x Starting x position in frames, or 0 if x is being ignored.
* @param fraction Starting y position (as a fraction of the track height, where 0 is the bottom and 1 the top)
*/
void
AutomationLine::start_drag_common (nframes_t x, float fraction)
{
drag_x = x;
drag_distance = 0;
_last_drag_fraction = fraction;
_drag_had_movement = false;
did_push = false;
}
/** Should be called to indicate motion during a drag.
* @param x New x position of the drag in frames, or 0 if x is being ignored.
* @param fraction New y fraction.
*/
void
AutomationLine::drag_motion (nframes_t x, float fraction, bool with_push)
{
int64_t const dx = x - drag_x;
drag_distance += dx;
drag_x = x;
double const dy = fraction - _last_drag_fraction;
_last_drag_fraction = fraction;
for (list<ControlPoint*>::iterator i = _drag_points.begin(); i != _drag_points.end(); ++i) {
modify_view_point (
**i,
trackview.editor().unit_to_frame ((*i)->get_x()) + dx,
((_height - (*i)->get_y()) / _height) + dy,
(x == 0),
with_push
);
}
if (line_points.size() > 1) {
line->property_points() = line_points;
}
drags++;
_drag_had_movement = true;
did_push = with_push;
}
/** Should be called to indicate the end of a drag */
void
AutomationLine::end_drag (ControlPoint* cp)
AutomationLine::end_drag ()
{
if (!drags) {
if (!_drag_had_movement) {
return;
}
alist->freeze ();
if (cp) {
sync_model_with_view_point (*cp, did_push, drag_distance);
} else {
sync_model_with_view_line (line_drag_cp1, line_drag_cp2);
}
sync_model_with_view_points (_drag_points, did_push, drag_distance);
alist->thaw ();
@ -782,7 +811,6 @@ AutomationLine::end_drag (ControlPoint* cp)
trackview.editor().session()->set_dirty ();
}
void
AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int64_t distance)
{
@ -849,7 +877,6 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int
alist->slide (mr.end, drag_distance);
}
}
bool
@ -1316,3 +1343,18 @@ AutomationLine::add_visible_control_point (uint32_t view_index, uint32_t pi, dou
}
}
}
void
AutomationLine::add_always_in_view (double x)
{
_always_in_view.push_back (x);
alist->apply_to_points (*this, &AutomationLine::reset_callback);
}
void
AutomationLine::clear_always_in_view ()
{
_always_in_view.clear ();
alist->apply_to_points (*this, &AutomationLine::reset_callback);
}

View file

@ -74,10 +74,11 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
bool control_points_adjacent (double xval, uint32_t& before, uint32_t& after);
/* dragging API */
virtual void start_drag (ControlPoint*, nframes_t x, float fraction);
virtual void point_drag(ControlPoint&, nframes_t x, float, bool with_push);
virtual void end_drag (ControlPoint*);
virtual void line_drag(uint32_t i1, uint32_t i2, float, bool with_push);
virtual void start_drag_single (ControlPoint*, nframes_t x, float);
virtual void start_drag_line (uint32_t, uint32_t, float);
virtual void start_drag_multiple (std::list<ControlPoint*>, float, XMLNode *);
virtual void drag_motion (nframes_t, float, bool);
virtual void end_drag ();
ControlPoint* nth (uint32_t);
uint32_t npoints() const { return control_points.size(); }
@ -130,6 +131,9 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
void modify_point_y (ControlPoint&, double);
void add_always_in_view (double);
void clear_always_in_view ();
protected:
std::string _name;
@ -164,8 +168,9 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
static bool invalid_point (ALPoints&, uint32_t index);
void determine_visible_control_points (ALPoints&);
void sync_model_with_view_point (ControlPoint&, bool did_push, int64_t distance);
void sync_model_with_view_line (uint32_t, uint32_t);
void sync_model_with_view_point (ControlPoint&, bool, int64_t);
void sync_model_with_view_points (std::list<ControlPoint*>, bool, int64_t);
void start_drag_common (nframes_t, float);
virtual void change_model (ARDOUR::AutomationList::iterator, double x, double y);
@ -177,18 +182,17 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
virtual void add_model_point (ALPoints& tmp_points, double frame, double yfract);
private:
uint32_t drags;
double first_drag_fraction;
double last_drag_fraction;
uint32_t line_drag_cp1;
uint32_t line_drag_cp2;
int64_t drag_x;
int64_t drag_distance;
std::list<ControlPoint*> _drag_points; ///< points we are dragging
bool _drag_had_movement; ///< true if the drag has seen movement, otherwise false
nframes64_t drag_x; ///< last x position of the drag, in frames
nframes64_t drag_distance; ///< total x movement of the drag, in frames
double _last_drag_fraction; ///< last y position of the drag, as a fraction
std::list<double> _always_in_view;
const Evoral::TimeConverter<double, ARDOUR::sframes_t>& _time_converter;
ARDOUR::AutomationList::InterpolationStyle _interpolation;
void modify_view_point (ControlPoint&, double, double, bool with_push);
void modify_view_point (ControlPoint&, double, double, bool, bool with_push);
void reset_line_coords (ControlPoint&);
void add_visible_control_point (uint32_t, uint32_t, double, double, ARDOUR::AutomationList::iterator, uint32_t);

View file

@ -100,6 +100,10 @@ class AutomationTimeAxisView : public TimeAxisView {
boost::shared_ptr<ARDOUR::AutomationControl> control() { return _control; }
boost::shared_ptr<AutomationController> controller() { return _controller; }
ArdourCanvas::Item* base_item () const {
return _base_rect;
}
protected:
boost::shared_ptr<ARDOUR::Route> _route; ///< Parent route
boost::shared_ptr<ARDOUR::AutomationControl> _control; ///< Control

View file

@ -155,15 +155,6 @@ void
ControlPoint::set_size (double sz)
{
_size = sz;
#if 0
if (_size > 6.0) {
item->property_fill() = (gboolean) TRUE;
} else {
item->property_fill() = (gboolean) FALSE;
}
#endif
move_to (_x, _y, _shape);
}

View file

@ -220,8 +220,10 @@ show_me_the_size (Requisition* r, const char* what)
}
Editor::Editor ()
: _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
/* time display buttons */
: minsec_label (_("Mins:Secs"))
, minsec_label (_("Mins:Secs"))
, bbt_label (_("Bars:Beats"))
, timecode_label (_("Timecode"))
, frame_label (_("Samples"))
@ -2314,6 +2316,10 @@ Editor::set_state (const XMLNode& node, int /*version*/)
}
}
if ((prop = node.property ("join-object-range"))) {
join_object_range_button.set_active (string_is_affirmative (prop->value ()));
}
if ((prop = node.property ("edit-point"))) {
set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
}
@ -2461,6 +2467,7 @@ Editor::get_state ()
node->add_property ("region-list-sort-type", enum2str (_regions->sort_type ()));
node->add_property ("mouse-mode", enum2str(mouse_mode));
node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
if (act) {
@ -2752,23 +2759,44 @@ Editor::setup_toolbar ()
mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
// internal_edit_button.set_relief(Gtk::RELIEF_NONE);
join_object_range_button.set_relief(Gtk::RELIEF_NONE);
HBox* mode_box = manage(new HBox);
mode_box->set_border_width (2);
mode_box->set_spacing(4);
mouse_mode_button_box.set_spacing(1);
mouse_mode_button_box.pack_start(mouse_move_button, true, true);
if (!Profile->get_sae()) {
mouse_mode_button_box.pack_start(mouse_select_button, true, true);
/* table containing mode buttons */
Table* mouse_mode_button_table = manage (new Table (Profile->get_sae() ? 4 : 6, 2));
int c = 0;
if (Profile->get_sae()) {
mouse_mode_button_table->attach (mouse_move_button, c, c + 1, 0, 1);
++c;
} else {
mouse_mode_button_table->attach (mouse_move_button, c, c + 1, 0, 1);
mouse_mode_button_table->attach (mouse_select_button, c + 1, c + 2, 0, 1);
mouse_mode_button_table->attach (join_object_range_button, c, c + 2, 1, 2);
c += 2;
}
mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
mouse_mode_button_table->attach (mouse_zoom_button, c, c + 1, 0, 1);
++c;
if (!Profile->get_sae()) {
mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
mouse_mode_button_table->attach (mouse_gain_button, c, c + 1, 0, 1);
++c;
}
mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
mouse_mode_button_box.pack_start(internal_edit_button, true, true);
mouse_mode_button_box.set_homogeneous(true);
mouse_mode_button_table->attach (mouse_timefx_button, c, c + 1, 0, 1);
++c;
mouse_mode_button_table->attach (mouse_audition_button, c, c + 1, 0, 1);
++c;
mouse_mode_button_table->attach (internal_edit_button, c, c + 1, 0, 1);
++c;
vector<string> edit_mode_strings;
edit_mode_strings.push_back (edit_mode_to_string (Slide));
@ -2781,8 +2809,8 @@ Editor::setup_toolbar ()
set_popdown_strings (edit_mode_selector, edit_mode_strings, true);
edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
mode_box->pack_start(edit_mode_selector);
mode_box->pack_start(mouse_mode_button_box);
mode_box->pack_start (edit_mode_selector);
mode_box->pack_start (*mouse_mode_button_table);
mouse_mode_tearoff = manage (new TearOff (*mode_box));
mouse_mode_tearoff->set_name ("MouseModeBase");
@ -2807,6 +2835,7 @@ Editor::setup_toolbar ()
mouse_zoom_button.set_mode (false);
mouse_timefx_button.set_mode (false);
mouse_audition_button.set_mode (false);
join_object_range_button.set_mode (false);
mouse_move_button.set_name ("MouseModeButton");
mouse_select_button.set_name ("MouseModeButton");
@ -2814,8 +2843,8 @@ Editor::setup_toolbar ()
mouse_zoom_button.set_name ("MouseModeButton");
mouse_timefx_button.set_name ("MouseModeButton");
mouse_audition_button.set_name ("MouseModeButton");
internal_edit_button.set_name ("MouseModeButton");
join_object_range_button.set_name ("MouseModeButton");
mouse_move_button.unset_flags (CAN_FOCUS);
mouse_select_button.unset_flags (CAN_FOCUS);
@ -2824,6 +2853,7 @@ Editor::setup_toolbar ()
mouse_timefx_button.unset_flags (CAN_FOCUS);
mouse_audition_button.unset_flags (CAN_FOCUS);
internal_edit_button.unset_flags (CAN_FOCUS);
join_object_range_button.unset_flags (CAN_FOCUS);
/* Zoom */

View file

@ -487,6 +487,19 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
Editing::MouseMode mouse_mode;
bool _internal_editing;
Editing::MouseMode effective_mouse_mode () const;
enum JoinObjectRangeState {
JOIN_OBJECT_RANGE_NONE,
/** `join object/range' mode is active and the mouse is over a place where object mode should happen */
JOIN_OBJECT_RANGE_OBJECT,
/** `join object/range' mode is active and the mouse is over a place where range mode should happen */
JOIN_OBJECT_RANGE_RANGE
};
JoinObjectRangeState _join_object_range_state;
void update_join_object_range_location (double, double);
int post_maximal_editor_width;
int post_maximal_pane_position;
@ -594,6 +607,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void collect_new_region_view (RegionView *);
void collect_and_select_new_region_view (RegionView *);
void select_range_around_region (RegionView *);
Gtk::Menu track_context_menu;
Gtk::Menu track_region_context_menu;
Gtk::Menu track_selection_context_menu;
@ -1492,7 +1507,6 @@ public:
Gtk::Table toolbar_selection_clock_table;
Gtk::Label toolbar_selection_cursor_label;
Gtk::HBox mouse_mode_button_box;
Gtkmm2ext::TearOff* mouse_mode_tearoff;
Gtk::ToggleButton mouse_select_button;
Gtk::ToggleButton mouse_move_button;
@ -1500,6 +1514,7 @@ public:
Gtk::ToggleButton mouse_zoom_button;
Gtk::ToggleButton mouse_timefx_button;
Gtk::ToggleButton mouse_audition_button;
Gtk::ToggleButton join_object_range_button;
void mouse_mode_toggled (Editing::MouseMode m);
bool ignore_mouse_mode_toggle;

View file

@ -683,7 +683,11 @@ Editor::register_actions ()
mouse_select_button.set_name ("MouseModeButton");
mouse_select_button.get_image ()->show ();
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-gain", _("Gain Tool"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
join_object_range_button.set_image (*(manage (new Image (::get_icon ("join_tools")))));
join_object_range_button.set_name ("MouseModeButton");
join_object_range_button.get_image()->show ();
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-gain", _("Gain Tool"), sigc::bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
act->connect_proxy (mouse_gain_button);
mouse_gain_button.set_image (*(manage (new Image (::get_icon("tool_gain")))));
mouse_gain_button.set_label ("");

View file

@ -265,7 +265,6 @@ Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, Reg
return false;
}
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:

View file

@ -40,6 +40,7 @@
#include "canvas-note.h"
#include "selection.h"
#include "midi_selection.h"
#include "automation_time_axis.h"
using namespace std;
using namespace ARDOUR;
@ -2466,15 +2467,12 @@ ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
// the point doesn't 'jump' to the mouse after the first drag
_time_axis_view_grab_x = _point->get_x();
_time_axis_view_grab_y = _point->get_y();
nframes64_t grab_frame = _editor->pixel_to_frame (_time_axis_view_grab_x);
_point->line().parent_group().i2w (_time_axis_view_grab_x, _time_axis_view_grab_y);
_editor->track_canvas->w2c (_time_axis_view_grab_x, _time_axis_view_grab_y, _time_axis_view_grab_x, _time_axis_view_grab_y);
float const fraction = 1 - (_point->get_y() / _point->line().height());
_time_axis_view_grab_frame = _editor->pixel_to_frame (_time_axis_view_grab_x);
_point->line().start_drag_single (_point, grab_frame, fraction);
_point->line().start_drag (_point, _time_axis_view_grab_frame, 0);
float fraction = 1.0 - (_point->get_y() / _point->line().height());
_editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
event->button.x + 10, event->button.y + 10);
@ -2492,18 +2490,16 @@ ControlPointDrag::motion (GdkEvent* event, bool)
dy *= 0.1;
}
/* coordinate in TimeAxisView's space */
double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
// calculate zero crossing point. back off by .01 to stay on the
// positive side of zero
double _unused = 0;
double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
_point->line().parent_group().i2w(_unused, zero_gain_y);
double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
// make sure we hit zero when passing through
if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
cy = zero_gain_y;
}
@ -2517,13 +2513,10 @@ ControlPointDrag::motion (GdkEvent* event, bool)
_cumulative_x_drag = cx - _time_axis_view_grab_x;
_cumulative_y_drag = cy - _time_axis_view_grab_y;
_point->line().parent_group().w2i (cx, cy);
cx = max (0.0, cx);
cy = max (0.0, cy);
cy = min ((double) _point->line().height(), cy);
//translate cx to frames
nframes64_t cx_frames = _editor->unit_to_frame (cx);
if (!_x_constrained) {
@ -2534,7 +2527,7 @@ ControlPointDrag::motion (GdkEvent* event, bool)
bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
_point->line().point_drag (*_point, cx_frames, fraction, push);
_point->line().drag_motion (cx_frames, fraction, push);
_editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
}
@ -2553,7 +2546,7 @@ ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
} else {
motion (event, false);
}
_point->line().end_drag (_point);
_point->line().end_drag ();
}
bool
@ -2594,7 +2587,10 @@ LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
uint32_t before;
uint32_t after;
if (!_line->control_points_adjacent (frame_within_region, before, after)) {
/* no adjacent points */
return;
}
@ -2608,7 +2604,7 @@ LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
double fraction = 1.0 - (cy / _line->height());
_line->start_drag (0, grab_frame(), fraction);
_line->start_drag_line (before, after, fraction);
_editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
event->button.x + 10, event->button.y + 10);
@ -2642,7 +2638,8 @@ LineDrag::motion (GdkEvent* event, bool)
push = true;
}
_line->line_drag (_before, _after, fraction, push);
/* we are ignoring x position for this drag, so we can just pass in 0 */
_line->drag_motion (0, fraction, push);
_editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
}
@ -2651,7 +2648,7 @@ void
LineDrag::finished (GdkEvent* event, bool)
{
motion (event, false);
_line->end_drag (0);
_line->end_drag ();
}
void
@ -2850,6 +2847,8 @@ SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
: Drag (e, i)
, _operation (o)
, _copy (false)
, _original_pointer_time_axis (-1)
, _last_pointer_time_axis (-1)
{
}
@ -2909,6 +2908,8 @@ SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
} else {
_editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
}
_original_pointer_time_axis = _editor->trackview_by_y_position (current_pointer_y ()).first->order ();
}
void
@ -2918,13 +2919,16 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
nframes64_t end = 0;
nframes64_t length;
pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (current_pointer_y ());
if (pending_time_axis.first == 0) {
return;
}
nframes64_t const pending_position = adjusted_current_frame (event);
/* only alter selection if the current frame is
different from the last frame position (adjusted)
*/
/* only alter selection if things have changed */
if (pending_position == last_pointer_frame()) {
if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
return;
}
@ -2969,8 +2973,36 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
_editor->clicked_selection = _editor->selection->set (start, end);
}
}
break;
/* select the track that we're in */
if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
_editor->selection->add (pending_time_axis.first);
_added_time_axes.push_back (pending_time_axis.first);
}
/* deselect any tracks that this drag no longer includes, being careful to only deselect
tracks that we selected in the first place.
*/
int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
list<TimeAxisView*>::iterator i = _added_time_axes.begin();
while (i != _added_time_axes.end()) {
list<TimeAxisView*>::iterator tmp = i;
++tmp;
if ((*i)->order() < min_order || (*i)->order() > max_order) {
_editor->selection->remove (*i);
_added_time_axes.remove (*i);
}
i = tmp;
}
}
break;
case SelectionStartTrim:
@ -3490,3 +3522,96 @@ NoteDrag::finished (GdkEvent* ev, bool moved)
region->note_dropped (cnote, drag_delta_x, drag_delta_note);
}
}
AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
: Drag (e, i)
, _ranges (r)
, _nothing_to_drag (false)
{
_atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
assert (_atav);
_line = _atav->line ();
}
void
AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
{
Drag::start_grab (event, cursor);
list<ControlPoint*> points;
XMLNode* state = &_line->get_state ();
if (_ranges.empty()) {
uint32_t const N = _line->npoints ();
for (uint32_t i = 0; i < N; ++i) {
points.push_back (_line->nth (i));
}
} else {
boost::shared_ptr<AutomationList> the_list = _line->the_list ();
for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
the_list->add (j->start, the_list->eval (j->start));
_line->add_always_in_view (j->start);
the_list->add (j->start + 1, the_list->eval (j->start + 1));
_line->add_always_in_view (j->start + 1);
the_list->add (j->end - 1, the_list->eval (j->end - 1));
_line->add_always_in_view (j->end - 1);
the_list->add (j->end, the_list->eval (j->end));
_line->add_always_in_view (j->end);
}
uint32_t const N = _line->npoints ();
AutomationList::const_iterator j = the_list->begin ();
for (uint32_t i = 0; i < N; ++i) {
ControlPoint* p = _line->nth (i);
list<AudioRange>::const_iterator k = _ranges.begin ();
while (k != _ranges.end() && (k->start >= (*j)->when || k->end <= (*j)->when)) {
++k;
}
if (k != _ranges.end()) {
points.push_back (p);
}
++j;
}
}
if (points.empty()) {
_nothing_to_drag = true;
return;
}
_line->start_drag_multiple (points, 1 - (current_pointer_y() / _line->height ()), state);
}
void
AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
{
if (_nothing_to_drag) {
return;
}
float const f = 1 - (current_pointer_y() / _line->height());
/* we are ignoring x position for this drag, so we can just pass in 0 */
_line->drag_motion (0, f, false);
}
void
AutomationRangeDrag::finished (GdkEvent* event, bool)
{
if (_nothing_to_drag) {
return;
}
motion (event, false);
_line->end_drag ();
_line->clear_always_in_view ();
}

View file

@ -474,7 +474,6 @@ private:
ControlPoint* _point;
double _time_axis_view_grab_x;
double _time_axis_view_grab_y;
nframes64_t _time_axis_view_grab_frame;
double _cumulative_x_drag;
double _cumulative_y_drag;
static double const _zero_gain_fraction;
@ -537,7 +536,7 @@ public:
void finished (GdkEvent *, bool);
};
/** Drag in range select(gc_owner.get()) moAutomatable */
/** Drag in range select mode */
class SelectionDrag : public Drag
{
public:
@ -557,6 +556,9 @@ public:
private:
Operation _operation;
bool _copy;
int _original_pointer_time_axis;
int _last_pointer_time_axis;
std::list<TimeAxisView*> _added_time_axes;
};
/** Range marker drag */
@ -583,16 +585,33 @@ private:
bool _copy;
};
/* Drag of rectangle to set zoom */
/** Drag of rectangle to set zoom */
class MouseZoomDrag : public Drag
{
public:
MouseZoomDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
MouseZoomDrag (Editor* e, ArdourCanvas::Item *i) : Drag (e, i) {}
void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
void motion (GdkEvent *, bool);
void finished (GdkEvent *, bool);
};
/** Drag of a range of automation data, changing value but not position */
class AutomationRangeDrag : public Drag
{
public:
AutomationRangeDrag (Editor *, ArdourCanvas::Item *, std::list<ARDOUR::AudioRange> const &);
void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
void motion (GdkEvent *, bool);
void finished (GdkEvent *, bool);
private:
std::list<ARDOUR::AudioRange> _ranges;
AutomationTimeAxisView* _atav;
boost::shared_ptr<AutomationLine> _line;
bool _nothing_to_drag;
};
#endif /* __gtk2_ardour_editor_drag_h_ */

View file

@ -134,13 +134,11 @@ Editor::event_frame (GdkEvent const * event, double* pcx, double* pcy) const
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
*pcx = event->button.x;
*pcy = event->button.y;
_trackview_group->w2i(*pcx, *pcy);
break;
case GDK_MOTION_NOTIFY:
*pcx = event->motion.x;
*pcy = event->motion.y;
_trackview_group->w2i(*pcx, *pcy);
@ -254,6 +252,17 @@ Editor::set_canvas_cursor ()
}
}
switch (_join_object_range_state) {
case JOIN_OBJECT_RANGE_NONE:
break;
case JOIN_OBJECT_RANGE_OBJECT:
current_canvas_cursor = which_grabber_cursor ();
break;
case JOIN_OBJECT_RANGE_RANGE:
current_canvas_cursor = selector_cursor;
break;
}
if (is_drawable()) {
track_canvas->get_window()->set_cursor(*current_canvas_cursor);
}
@ -315,9 +324,9 @@ Editor::mouse_mode_toggled (MouseMode m)
instant_save ();
if (mouse_mode != MouseRange) {
if (mouse_mode != MouseRange && _join_object_range_state == JOIN_OBJECT_RANGE_NONE) {
/* in all modes except range, hide the range selection,
/* in all modes except range and joined object/range, hide the range selection,
show the object (region) selection.
*/
@ -331,7 +340,7 @@ Editor::mouse_mode_toggled (MouseMode m)
} else {
/*
in range mode, show the range selection.
in range or object/range mode, show the range selection.
*/
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
@ -416,6 +425,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
*/
if (((mouse_mode != MouseObject) &&
(_join_object_range_state != JOIN_OBJECT_RANGE_OBJECT) &&
(mouse_mode != MouseAudition || item_type != RegionItem) &&
(mouse_mode != MouseTimeFX || item_type != RegionItem) &&
(mouse_mode != MouseGain) &&
@ -445,16 +455,21 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
switch (item_type) {
case RegionItem:
if (mouse_mode != MouseRange) {
if (mouse_mode != MouseRange || _join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) {
set_selected_regionview_from_click (press, op, true);
} else if (event->type == GDK_BUTTON_PRESS) {
set_selected_track_as_side_effect ();
selection->clear_tracks ();
set_selected_track_as_side_effect (true);
}
if (_join_object_range_state == JOIN_OBJECT_RANGE_OBJECT && !selection->regions.empty()) {
select_range_around_region (selection->regions.front());
}
break;
case RegionViewNameHighlight:
case RegionViewName:
if (mouse_mode != MouseRange) {
if (mouse_mode != MouseRange || _join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) {
set_selected_regionview_from_click (press, op, true);
} else if (event->type == GDK_BUTTON_PRESS) {
set_selected_track_as_side_effect ();
@ -466,7 +481,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
case FadeInItem:
case FadeOutHandleItem:
case FadeOutItem:
if (mouse_mode != MouseRange) {
if (mouse_mode != MouseRange || _join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) {
set_selected_regionview_from_click (press, op, true);
} else if (event->type == GDK_BUTTON_PRESS) {
set_selected_track_as_side_effect ();
@ -475,7 +490,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
case ControlPointItem:
set_selected_track_as_side_effect ();
if (mouse_mode != MouseRange) {
if (mouse_mode != MouseRange || _join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) {
set_selected_control_point_from_click (op, false);
}
break;
@ -597,7 +612,9 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
break;
}
switch (mouse_mode) {
Editing::MouseMode eff = effective_mouse_mode ();
switch (eff) {
case MouseRange:
switch (item_type) {
case StartSelectionTrimItem:
@ -623,11 +640,21 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
_drag = new SelectionDrag (this, item, SelectionDrag::SelectionMove);
_drag->start_grab (event);
} else {
/* this was debated, but decided the more common action was to
make a new selection */
assert (_drag == 0);
_drag = new SelectionDrag (this, item, SelectionDrag::CreateSelection);
_drag->start_grab (event);
double const y = event->button.y + vertical_adjustment.get_value() - canvas_timebars_vsize;
pair<TimeAxisView*, int> tvp = trackview_by_y_position (y);
if (tvp.first) {
AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (tvp.first);
assert (_drag == 0);
if (join_object_range_button.get_active() && atv) {
/* smart "join" mode: drag automation */
_drag = new AutomationRangeDrag (this, atv->base_item(), selection->time);
} else {
/* this was debated, but decided the more common action was to
make a new selection */
_drag = new SelectionDrag (this, item, SelectionDrag::CreateSelection);
}
_drag->start_grab (event);
}
}
break;
@ -734,14 +761,46 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
_drag = new RegionCreateDrag (this, item, clicked_axisview);
_drag->start_grab (event);
return true;
} else {
assert (_drag == 0);
_drag = new RubberbandSelectDrag (this, item);
_drag->start_grab (event);
}
/* fallthru */
break;
case AutomationTrackItem:
assert (_drag == 0);
_drag = new RubberbandSelectDrag (this, item);
if (join_object_range_button.get_active()) {
/* smart "join" mode: drag automation */
_drag = new AutomationRangeDrag (this, item, selection->time);
} else {
/* otherwise: rubberband drag to select automation points */
_drag = new RubberbandSelectDrag (this, item);
}
_drag->start_grab (event);
break;
case SelectionItem:
{
if (join_object_range_button.get_active()) {
/* we're in "smart" joined mode, and we've clicked on a Selection; if we're
* over an automation track, start a drag of its data */
double const y = event->button.y + vertical_adjustment.get_value() - canvas_timebars_vsize;
pair<TimeAxisView*, int> tvp = trackview_by_y_position (y);
if (tvp.first) {
AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (tvp.first);
if (atv) {
assert (_drag == 0);
_drag = new AutomationRangeDrag (this, atv->base_item(), selection->time);
_drag->start_grab (event);
}
}
}
break;
}
#ifdef WITH_CMT
case ImageFrameHandleStartItem:
imageframe_start_handle_op(item, event) ;
@ -878,7 +937,8 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
bool
Editor::button_press_handler_2 (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
{
switch (mouse_mode) {
Editing::MouseMode const eff = effective_mouse_mode ();
switch (eff) {
case MouseObject:
switch (item_type) {
case RegionItem:
@ -1152,6 +1212,8 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
/* delete events get handled here */
Editing::MouseMode const eff = effective_mouse_mode ();
if (_drag == 0 && Keyboard::is_delete_event (&event->button)) {
switch (item_type) {
@ -1168,13 +1230,13 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
break;
case RegionItem:
if (mouse_mode == MouseObject) {
if (eff == MouseObject) {
remove_clicked_region ();
}
break;
case ControlPointItem:
if (mouse_mode == MouseGain) {
if (eff == MouseGain) {
remove_gain_control_point (item, event);
} else {
remove_control_point (item, event);
@ -1233,7 +1295,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
break;
}
switch (mouse_mode) {
switch (eff) {
case MouseObject:
switch (item_type) {
case AutomationTrackItem:
@ -1305,7 +1367,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
case 2:
switch (mouse_mode) {
switch (eff) {
case MouseObject:
switch (item_type) {
@ -1348,7 +1410,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
}
bool
Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* /*event*/, ItemType item_type)
Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
{
ControlPoint* cp;
Marker * marker;
@ -1544,7 +1606,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* /*event*/, ItemType i
}
bool
Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* /*event*/, ItemType item_type)
Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
{
AutomationLine* al;
ControlPoint* cp;
@ -1661,6 +1723,10 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* /*event*/, ItemType i
break;
}
if (item_type == RegionItem) {
update_join_object_range_location (event->crossing.x, event->crossing.y);
}
return false;
}
@ -1782,6 +1848,12 @@ Editor::motion_handler (ArdourCanvas::Item* /*item*/, GdkEvent* event, bool from
return true;
}
JoinObjectRangeState const old = _join_object_range_state;
update_join_object_range_location (event->motion.x, event->motion.y);
if (_join_object_range_state != old) {
set_canvas_cursor ();
}
bool handled = false;
if (_drag) {
handled = _drag->motion_handler (event, from_autoscroll);
@ -2598,3 +2670,52 @@ Editor::set_internal_edit (bool yn)
}
/** Update _join_object_range_state which indicate whether we are over the top or bottom half of a region view,
* used by the `join object/range' tool mode.
*/
void
Editor::update_join_object_range_location (double x, double y)
{
if (join_object_range_button.get_active() == false || (mouse_mode != MouseRange && mouse_mode != MouseObject)) {
_join_object_range_state = JOIN_OBJECT_RANGE_NONE;
return;
}
if (entered_regionview) {
double cx = x;
double cy = y;
entered_regionview->get_canvas_group()->w2i (cx, cy);
double x1;
double y1;
double x2;
double y2;
entered_regionview->get_canvas_group()->get_bounds (x1, y1, x2, y2);
bool const top_half = cy < (y2 - y1) / 2;
_join_object_range_state = top_half ? JOIN_OBJECT_RANGE_RANGE : JOIN_OBJECT_RANGE_OBJECT;
} else {
if (mouse_mode == MouseObject) {
_join_object_range_state = JOIN_OBJECT_RANGE_OBJECT;
} else if (mouse_mode == MouseRange) {
_join_object_range_state = JOIN_OBJECT_RANGE_RANGE;
}
}
}
Editing::MouseMode
Editor::effective_mouse_mode () const
{
if (_join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) {
return MouseObject;
} else if (_join_object_range_state == JOIN_OBJECT_RANGE_RANGE) {
return MouseRange;
}
return mouse_mode;
}

View file

@ -171,6 +171,9 @@ Editor::select_all_tracks ()
selection->set (visible_views);
}
/** Select clicked_routeview, unless there are no currently selected
* tracks, in which case nothing will happen unless `force' is true.
*/
void
Editor::set_selected_track_as_side_effect (bool force)
{
@ -1392,4 +1395,12 @@ Editor::deselect_all ()
selection->clear ();
}
void
Editor::select_range_around_region (RegionView* rv)
{
selection->set (&rv->get_time_axis_view());
selection->time.clear ();
boost::shared_ptr<Region> r = rv->region ();
selection->set (r->position(), r->position() + r->length());
}

View file

@ -50,9 +50,10 @@ AudioRegionGainLine::AudioRegionGainLine (const string & name, AudioRegionView&
}
void
AudioRegionGainLine::start_drag (ControlPoint* cp, nframes_t x, float fraction)
AudioRegionGainLine::start_drag_single (ControlPoint* cp, nframes_t x, float fraction)
{
AutomationLine::start_drag (cp, x, fraction);
AutomationLine::start_drag_single (cp, x, fraction);
if (!rv.audio_region()->envelope_active()) {
trackview.session()->add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), &rv.audio_region()->get_state(), 0));
rv.audio_region()->set_envelope_active(false);
@ -85,13 +86,13 @@ AudioRegionGainLine::remove_point (ControlPoint& cp)
}
void
AudioRegionGainLine::end_drag (ControlPoint* cp)
AudioRegionGainLine::end_drag ()
{
if (!rv.audio_region()->envelope_active()) {
rv.audio_region()->set_envelope_active(true);
trackview.session()->add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), 0, &rv.audio_region()->get_state()));
}
AutomationLine::end_drag(cp);
AutomationLine::end_drag ();
}

View file

@ -38,8 +38,8 @@ class AudioRegionGainLine : public AutomationLine
public:
AudioRegionGainLine (const std::string & name, AudioRegionView&, ArdourCanvas::Group& parent, boost::shared_ptr<ARDOUR::AutomationList>);
void start_drag (ControlPoint*, nframes_t x, float fraction);
void end_drag (ControlPoint*);
void start_drag_single (ControlPoint*, nframes_t x, float fraction);
void end_drag ();
void remove_point (ControlPoint&);

View file

@ -126,7 +126,7 @@ BasicUI::transport_play (bool from_last_start)
}
if (session->get_play_range ()) {
session->request_play_range (false);
session->request_play_range (0);
}
if (from_last_start && rolling) {