From 3120bae8b41f3eecad25534ab6953e1b123ab9de Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 22 Mar 2012 16:41:23 +0000 Subject: Don't leave internal edit mode when clicking on an automation region view (#4747). git-svn-id: svn://localhost/ardour2/branches/3.0@11749 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/automation_line.cc | 41 ++++++++++++++++++++++++------------ gtk2_ardour/automation_line.h | 9 ++++---- gtk2_ardour/editor_drag.cc | 37 +++++++++++++++++++++++--------- gtk2_ardour/editor_drag.h | 14 +++++++++--- gtk2_ardour/editor_mouse.cc | 21 +++++++++++++----- gtk2_ardour/midi_automation_line.cc | 2 +- gtk2_ardour/midi_automation_line.h | 2 +- gtk2_ardour/region_gain_line.cc | 2 ++ gtk2_ardour/region_gain_line.h | 2 +- libs/evoral/evoral/TimeConverter.hpp | 11 +++++++++- 10 files changed, 101 insertions(+), 40 deletions(-) diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc index 7206f2dfdc..2ee64e5706 100644 --- a/gtk2_ardour/automation_line.cc +++ b/gtk2_ardour/automation_line.cc @@ -55,19 +55,28 @@ using namespace PBD; using namespace Editing; using namespace Gnome; // for Canvas -static const Evoral::IdentityConverter default_converter; - +/** @param converter A TimeConverter whose origin_b is the start time of the AutomationList in session frames. + * This will not be deleted by AutomationLine. + */ AutomationLine::AutomationLine (const string& name, TimeAxisView& tv, ArdourCanvas::Group& parent, boost::shared_ptr al, - const Evoral::TimeConverter* converter) + Evoral::TimeConverter* converter) : trackview (tv) , _name (name) , alist (al) + , _time_converter (converter ? converter : new Evoral::IdentityConverter) , _parent_group (parent) , _offset (0) - , _time_converter (converter ? (*converter) : default_converter) , _maximum_time (max_framepos) { + if (converter) { + _time_converter = converter; + _our_time_converter = false; + } else { + _time_converter = new Evoral::IdentityConverter; + _our_time_converter = true; + } + points_visible = false; update_pending = false; _uses_gain_mapping = false; @@ -103,6 +112,10 @@ AutomationLine::~AutomationLine () { vector_delete (&control_points); delete group; + + if (_our_time_converter) { + delete _time_converter; + } } bool @@ -225,7 +238,7 @@ AutomationLine::modify_point_y (ControlPoint& cp, double y) y = min (1.0, y); y = _height - (y * _height); - double const x = trackview.editor().frame_to_unit (_time_converter.to((*cp.model())->when) - _offset); + double const x = trackview.editor().frame_to_unit (_time_converter->to((*cp.model())->when) - _offset); trackview.editor().session()->begin_reversible_command (_("automation event move")); trackview.editor().session()->add_command ( @@ -286,11 +299,11 @@ AutomationLine::model_representation (ControlPoint& cp, ModelRepresentation& mr) /* if xval has not changed, set it directly from the model to avoid rounding errors */ - if (mr.xval == trackview.editor().frame_to_unit(_time_converter.to((*cp.model())->when)) - _offset) { + if (mr.xval == trackview.editor().frame_to_unit(_time_converter->to((*cp.model())->when)) - _offset) { mr.xval = (*cp.model())->when - _offset; } else { mr.xval = trackview.editor().unit_to_frame (mr.xval); - mr.xval = _time_converter.from (mr.xval + _offset); + mr.xval = _time_converter->from (mr.xval + _offset); } /* convert y to model units; the x was already done above @@ -994,7 +1007,7 @@ AutomationLine::get_selectables ( (as it is the session frame position of the start of the source) */ - framepos_t const session_frames_when = _time_converter.to (model_when) + _time_converter.origin_b (); + framepos_t const session_frames_when = _time_converter->to (model_when) + _time_converter->origin_b (); if (session_frames_when >= start && session_frames_when <= end && (*i)->get_y() >= bot_track && (*i)->get_y() <= top_track) { results.push_back (*i); @@ -1025,8 +1038,8 @@ AutomationLine::point_selection_to_control_points (PointSelection const & s) for (vector::iterator j = control_points.begin(); j != control_points.end(); ++j) { - double const rstart = trackview.editor().frame_to_unit (_time_converter.to (i->start) - _offset); - double const rend = trackview.editor().frame_to_unit (_time_converter.to (i->end) - _offset); + double const rstart = trackview.editor().frame_to_unit (_time_converter->to (i->start) - _offset); + double const rend = trackview.editor().frame_to_unit (_time_converter->to (i->end) - _offset); if ((*j)->get_x() >= rstart && (*j)->get_x() <= rend) { if ((*j)->get_y() >= bot && (*j)->get_y() <= top) { @@ -1212,7 +1225,7 @@ AutomationLine::set_state (const XMLNode &node, int version) void AutomationLine::view_to_model_coord (double& x, double& y) const { - x = _time_converter.from (x); + x = _time_converter->from (x); view_to_model_coord_y (y); } @@ -1254,7 +1267,7 @@ AutomationLine::model_to_view_coord (double& x, double& y) const y = y / (double)alist->parameter().max(); /* ... like this */ } - x = _time_converter.to (x) - _offset; + x = _time_converter->to (x) - _offset; } /** Called when our list has announced that its interpolation style has changed */ @@ -1373,8 +1386,8 @@ AutomationLine::get_point_x_range () const pair r (max_framepos, 0); for (AutomationList::const_iterator i = the_list()->begin(); i != the_list()->end(); ++i) { - r.first = min (r.first, _time_converter.to ((*i)->when) + _offset + _time_converter.origin_b ()); - r.second = max (r.second, _time_converter.to ((*i)->when) + _offset + _time_converter.origin_b ()); + r.first = min (r.first, _time_converter->to ((*i)->when) + _offset + _time_converter->origin_b ()); + r.second = max (r.second, _time_converter->to ((*i)->when) + _offset + _time_converter->origin_b ()); } return r; diff --git a/gtk2_ardour/automation_line.h b/gtk2_ardour/automation_line.h index 3a28362195..5ca2c83cd6 100644 --- a/gtk2_ardour/automation_line.h +++ b/gtk2_ardour/automation_line.h @@ -59,7 +59,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible public: AutomationLine (const std::string& name, TimeAxisView&, ArdourCanvas::Group&, boost::shared_ptr, - const Evoral::TimeConverter* converter = 0); + Evoral::TimeConverter* converter = 0); virtual ~AutomationLine (); void queue_reset (); @@ -135,7 +135,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible virtual MementoCommandBinder* memento_command_binder (); const Evoral::TimeConverter& time_converter () const { - return _time_converter; + return *_time_converter; } std::pair get_point_x_range () const; @@ -155,6 +155,9 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible uint32_t _line_color; boost::shared_ptr alist; + Evoral::TimeConverter* _time_converter; + /** true if _time_converter belongs to us (ie we should delete it) */ + bool _our_time_converter; bool _visible : 1; bool _uses_gain_mapping : 1; @@ -207,8 +210,6 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible */ ARDOUR::framecnt_t _offset; - const Evoral::TimeConverter& _time_converter; - void reset_line_coords (ControlPoint&); void add_visible_control_point (uint32_t, uint32_t, double, double, ARDOUR::AutomationList::iterator, uint32_t); double control_point_box_size (); diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 3d05fc296e..04c6494d9d 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -4076,26 +4076,43 @@ NoteDrag::aborted (bool) /* XXX: TODO */ } -AutomationRangeDrag::AutomationRangeDrag (Editor* editor, ArdourCanvas::Item* item, list const & r) - : Drag (editor, item) +/** Make an AutomationRangeDrag for lines in an AutomationTimeAxisView */ +AutomationRangeDrag::AutomationRangeDrag (Editor* editor, AutomationTimeAxisView* atv, list const & r) + : Drag (editor, atv->base_item ()) , _ranges (r) , _nothing_to_drag (false) { DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n"); - _atav = reinterpret_cast (_item->get_data ("trackview")); - assert (_atav); + setup (atv->lines ()); +} + +/** Make an AutomationRangeDrag for region gain lines */ +AutomationRangeDrag::AutomationRangeDrag (Editor* editor, AudioRegionView* rv, list 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 > lines = _atav->lines (); + list > lines; + lines.push_back (rv->get_gain_line ()); + setup (lines); +} - /* find those that overlap the ranges being dragged */ - list >::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 > const & lines) +{ + /* find the lines that overlap the ranges being dragged */ + list >::const_iterator i = lines.begin (); while (i != lines.end ()) { - list >::iterator j = i; + list >::const_iterator j = i; ++j; - pair const r = (*i)->get_point_x_range (); + pair r = (*i)->get_point_x_range (); /* check this range against all the AudioRanges that we are using */ list::const_iterator k = _ranges.begin (); diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index f39f5cfcb3..2c806126bd 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -932,11 +932,14 @@ private: bool _zoom_out; }; -/** Drag of a range of automation data, changing value but not position */ +/** Drag of a range of automation data (either on an automation track or region gain), + * changing value but not position. + */ class AutomationRangeDrag : public Drag { public: - AutomationRangeDrag (Editor *, ArdourCanvas::Item *, std::list const &); + AutomationRangeDrag (Editor *, AutomationTimeAxisView *, std::list const &); + AutomationRangeDrag (Editor *, AudioRegionView *, std::list const &); void start_grab (GdkEvent *, Gdk::Cursor* c = 0); void motion (GdkEvent *, bool); @@ -947,9 +950,14 @@ public: return false; } + bool active (Editing::MouseMode) { + return true; + } + private: + void setup (std::list > const &); + std::list _ranges; - AutomationTimeAxisView* _atav; /** A line that is part of the drag */ struct Line { diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 0842403d73..5ee05336a4 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -456,9 +456,9 @@ Editor::mouse_mode_toggled (MouseMode m) instant_save (); if (!internal_editing()) { - if (mouse_mode != MouseRange && _join_object_range_state == JOIN_OBJECT_RANGE_NONE) { + if (mouse_mode != MouseRange && mouse_mode != MouseGain && _join_object_range_state == JOIN_OBJECT_RANGE_NONE) { - /* in all modes except range and joined object/range, hide the range selection, + /* in all modes except range, gain and joined object/range, hide the range selection, show the object (region) selection. */ @@ -824,7 +824,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT AutomationTimeAxisView* atv = dynamic_cast (tvp.first); if (smart_mode_action->get_active() && atv) { /* smart "join" mode: drag automation */ - _drags->set (new AutomationRangeDrag (this, atv->base_item(), selection->time), event, _cursors->up_down); + _drags->set (new AutomationRangeDrag (this, atv, selection->time), event, _cursors->up_down); } else { /* this was debated, but decided the more common action was to make a new selection */ @@ -1040,7 +1040,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT /* if we're over an automation track, start a drag of its data */ AutomationTimeAxisView* atv = dynamic_cast (tvp.first); if (atv) { - _drags->set (new AutomationRangeDrag (this, atv->base_item(), selection->time), event, _cursors->up_down); + _drags->set (new AutomationRangeDrag (this, atv, selection->time), event, _cursors->up_down); } /* if we're over a track and a region, and in the `object' part of a region, @@ -1119,6 +1119,17 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT return true; break; + case SelectionItem: + { + AudioRegionView* arv = dynamic_cast (clicked_regionview); + if (arv) { + _drags->set (new AutomationRangeDrag (this, arv, selection->time), event, _cursors->up_down); + _drags->start_grab (event); + } + return true; + break; + } + case AutomationLineItem: _drags->set (new LineDrag (this, item), event); break; @@ -1286,7 +1297,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp break; case RegionItem: - if (!dynamic_cast (clicked_regionview)) { + if (!dynamic_cast (clicked_regionview) && !dynamic_cast (clicked_regionview)) { leave_internal_edit_mode = true; } break; diff --git a/gtk2_ardour/midi_automation_line.cc b/gtk2_ardour/midi_automation_line.cc index 6599e8a966..359c516485 100755 --- a/gtk2_ardour/midi_automation_line.cc +++ b/gtk2_ardour/midi_automation_line.cc @@ -29,7 +29,7 @@ MidiAutomationLine::MidiAutomationLine ( boost::shared_ptr list, boost::shared_ptr region, Evoral::Parameter parameter, - const Evoral::TimeConverter* converter) + Evoral::TimeConverter* converter) : AutomationLine (name, tav, group, list, converter) , _region (region) , _parameter (parameter) diff --git a/gtk2_ardour/midi_automation_line.h b/gtk2_ardour/midi_automation_line.h index fb9171824a..aafe966028 100755 --- a/gtk2_ardour/midi_automation_line.h +++ b/gtk2_ardour/midi_automation_line.h @@ -30,7 +30,7 @@ public: boost::shared_ptr, boost::shared_ptr, Evoral::Parameter, - const Evoral::TimeConverter* converter = 0); + Evoral::TimeConverter* converter = 0); MementoCommandBinder* memento_command_binder (); diff --git a/gtk2_ardour/region_gain_line.cc b/gtk2_ardour/region_gain_line.cc index 40b2773b6d..bc360f25d6 100644 --- a/gtk2_ardour/region_gain_line.cc +++ b/gtk2_ardour/region_gain_line.cc @@ -44,6 +44,8 @@ AudioRegionGainLine::AudioRegionGainLine (const string & name, AudioRegionView& // If this isn't true something is horribly wrong, and we'll get catastrophic gain values assert(l->parameter().type() == EnvelopeAutomation); + _time_converter->set_origin_b (r.region()->position() - r.region()->start()); + group->raise_to_top (); group->property_y() = 2; set_uses_gain_mapping (true); diff --git a/gtk2_ardour/region_gain_line.h b/gtk2_ardour/region_gain_line.h index c781f20228..12f5c45abb 100644 --- a/gtk2_ardour/region_gain_line.h +++ b/gtk2_ardour/region_gain_line.h @@ -43,7 +43,7 @@ class AudioRegionGainLine : public AutomationLine void remove_point (ControlPoint&); - private: +private: AudioRegionView& rv; }; diff --git a/libs/evoral/evoral/TimeConverter.hpp b/libs/evoral/evoral/TimeConverter.hpp index 3f30570905..da765c4b78 100644 --- a/libs/evoral/evoral/TimeConverter.hpp +++ b/libs/evoral/evoral/TimeConverter.hpp @@ -25,6 +25,12 @@ namespace Evoral { * * Think of the conversion method names as if they are written in-between * the two template parameters (i.e. "A B"). + * + * _origin_b should be the origin for conversion in the units of B. + * That is, there is some point in time _origin_b, such that: + * + * to() converts a time _origin_b + a into an offset from _origin_b in units of B. + * from() converts a time _origin_b + b into an offset from _origin_b in units of A. */ template class TimeConverter { @@ -52,7 +58,10 @@ protected: }; -/** A stub TimeConverter that simple statically casts between types. */ +/** A stub TimeConverter that simple statically casts between types. + * _origin_b has no bearing here, as there is no time conversion + * going on. + */ template class IdentityConverter : public TimeConverter { public: -- cgit v1.2.3