diff --git a/gtk2_ardour/audio_clip_editor.cc b/gtk2_ardour/audio_clip_editor.cc index 88cc34f66d..6f3304dcb9 100644 --- a/gtk2_ardour/audio_clip_editor.cc +++ b/gtk2_ardour/audio_clip_editor.cc @@ -43,7 +43,7 @@ #include "audio_clip_editor.h" #include "audio_clock.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "control_point.h" #include "editor.h" #include "region_view.h" diff --git a/gtk2_ardour/audio_region_operations_box.cc b/gtk2_ardour/audio_region_operations_box.cc index dedbdb9d59..0a3a1042f9 100644 --- a/gtk2_ardour/audio_region_operations_box.cc +++ b/gtk2_ardour/audio_region_operations_box.cc @@ -29,7 +29,7 @@ #include "ardour/session.h" #include "audio_clock.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "control_point.h" #include "editor.h" #include "region_view.h" diff --git a/gtk2_ardour/audio_region_properties_box.cc b/gtk2_ardour/audio_region_properties_box.cc index 5a63697d2c..42d4df00cb 100644 --- a/gtk2_ardour/audio_region_properties_box.cc +++ b/gtk2_ardour/audio_region_properties_box.cc @@ -29,7 +29,7 @@ #include "ardour/session.h" #include "audio_clock.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "control_point.h" #include "editor.h" #include "region_view.h" diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc index 77c969dc20..4930d316c7 100644 --- a/gtk2_ardour/audio_region_view.cc +++ b/gtk2_ardour/audio_region_view.cc @@ -1301,13 +1301,13 @@ AudioRegionView::update_envelope_visibility () } if (trackview.editor().current_mouse_mode() == Editing::MouseDraw || trackview.editor().current_mouse_mode() == Editing::MouseContent ) { - _fx_line->set_visibility (AutomationLine::VisibleAspects(AutomationLine::ControlPoints|AutomationLine::Line)); + _fx_line->set_visibility (EditorAutomationLine::VisibleAspects(EditorAutomationLine::ControlPoints|EditorAutomationLine::Line)); _fx_line->canvas_group().raise_to_top (); } else if (UIConfiguration::instance().get_show_region_gain() || trackview.editor().current_mouse_mode() == Editing::MouseRange ) { - _fx_line->set_visibility (AutomationLine::VisibleAspects(AutomationLine::Line)); + _fx_line->set_visibility (EditorAutomationLine::VisibleAspects(EditorAutomationLine::Line)); _fx_line->canvas_group().raise_to_top (); } else { - _fx_line->set_visibility (AutomationLine::VisibleAspects(0)); + _fx_line->set_visibility (EditorAutomationLine::VisibleAspects(0)); } } diff --git a/gtk2_ardour/audio_region_view.h b/gtk2_ardour/audio_region_view.h index d2bd35771d..9494f51e04 100644 --- a/gtk2_ardour/audio_region_view.h +++ b/gtk2_ardour/audio_region_view.h @@ -41,7 +41,7 @@ #include "line_merger.h" #include "region_view.h" #include "time_axis_view_item.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "enums.h" namespace ARDOUR { @@ -221,7 +221,7 @@ protected: void transients_changed(); - AutomationLine::VisibleAspects automation_line_visibility () const; + EditorAutomationLine::VisibleAspects automation_line_visibility () const; void redisplay (bool) {} private: diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc index 292580c9da..94bc58e726 100644 --- a/gtk2_ardour/audio_time_axis.cc +++ b/gtk2_ardour/audio_time_axis.cc @@ -51,7 +51,7 @@ #include "ardour/panner_shell.h" #include "audio_time_axis.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "enums.h" #include "gui_thread.h" #include "automation_time_axis.h" diff --git a/gtk2_ardour/audio_time_axis.h b/gtk2_ardour/audio_time_axis.h index 2d46664d5c..a0dc6b6d41 100644 --- a/gtk2_ardour/audio_time_axis.h +++ b/gtk2_ardour/audio_time_axis.h @@ -58,7 +58,7 @@ class Selection; class Selectable; class RegionView; class AudioRegionView; -class AutomationLine; +class EditorAutomationLine; class AutomationGainLine; class AutomationPanLine; class TimeSelection; diff --git a/gtk2_ardour/audio_trigger_properties_box.cc b/gtk2_ardour/audio_trigger_properties_box.cc index 109eb4fc0e..8f15390316 100644 --- a/gtk2_ardour/audio_trigger_properties_box.cc +++ b/gtk2_ardour/audio_trigger_properties_box.cc @@ -35,7 +35,7 @@ #include "ardour/session.h" #include "audio_clock.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "control_point.h" #include "editor.h" #include "region_view.h" diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc index 203621a2a4..0aaa56d335 100644 --- a/gtk2_ardour/automation_line.cc +++ b/gtk2_ardour/automation_line.cc @@ -24,33 +24,1491 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include + +#ifdef COMPILER_MSVC +#include + +// 'std::isnan()' is not available in MSVC. +#define isnan_local(val) (bool)_isnan((double)val) +#else +#define isnan_local std::isnan +#endif + +#include +#include + +#include "boost/shared_ptr.hpp" + +#include "pbd/floating.h" +#include "pbd/memento_command.h" +#include "pbd/stl_delete.h" + +#include "ardour/automation_list.h" +#include "ardour/dB.h" +#include "ardour/debug.h" +#include "ardour/parameter_types.h" +#include "ardour/tempo.h" + +#include "temporal/range.h" + +#include "evoral/Curve.h" + +#include "canvas/debug.h" + #include "automation_line.h" +#include "control_point.h" +#include "editing_context.h" +#include "gui_thread.h" +#include "rgb_macros.h" #include "public_editor.h" +#include "selection.h" #include "time_axis_view.h" +#include "point_selection.h" +#include "automation_time_axis.h" +#include "ui_config.h" + +#include "ardour/event_type_map.h" +#include "ardour/session.h" +#include "ardour/value_as_string.h" + +#include "pbd/i18n.h" using namespace std; using namespace ARDOUR; +using namespace PBD; +using namespace Editing; +using namespace Temporal; + +#define SAMPLES_TO_TIME(x) (get_origin().distance (x)) /** @param converter A TimeConverter whose origin_b is the start time of the AutomationList in session samples. - * This will not be deleted by AutomationLine. + * This will not be deleted by EditorAutomationLine. */ -AutomationLine::AutomationLine (const string& name, - TimeAxisView& tv, - ArdourCanvas::Item& parent, - std::shared_ptr al, - const ParameterDescriptor& desc) - : AutomationLineBase (name, tv.editor(), parent, nullptr, al, desc) - , trackview (tv) +AutomationLine::AutomationLine (const string& name, + EditingContext& ec, + ArdourCanvas::Item& parent, + ArdourCanvas::Rectangle* drag_base, + std::shared_ptr al, + const ParameterDescriptor& desc) + :_name (name) + , _height (0) + , _line_color ("automation line") + , _view_index_offset (0) + , alist (al) + , _visible (Line) + , terminal_points_can_slide (true) + , update_pending (false) + , have_reset_timeout (false) + , no_draw (false) + , _is_boolean (false) + , _editing_context (ec) + , _parent_group (parent) + , _drag_base (drag_base) + , _offset (0) + , _maximum_time (timepos_t::max (al->time_domain())) + , _fill (false) + , _desc (desc) { - line->set_data ("trackview", &trackview); + group = new ArdourCanvas::Container (&parent, ArdourCanvas::Duple(0, 1.5)); + CANVAS_DEBUG_NAME (group, "automation line group"); + + line = new ArdourCanvas::PolyLine (group); + CANVAS_DEBUG_NAME (line, "automation line"); + line->set_data ("line", this); + line->set_data ("drag-base", _drag_base); + line->set_outline_width (2.0); + line->set_covers_threshold (4.0); + + line->Event.connect (sigc::mem_fun (*this, &AutomationLine::event_handler)); + + _editing_context.session()->register_with_memento_command_factory(alist->id(), this); + + interpolation_changed (alist->interpolation ()); + + connect_to_list (); } AutomationLine::~AutomationLine () { + delete group; // deletes child items + + for (std::vector::iterator i = control_points.begin(); i != control_points.end(); i++) { + (*i)->unset_item (); + delete *i; + } + control_points.clear (); +} + +timepos_t +AutomationLine::get_origin() const +{ + /* this is the default for all non-derived EditorAutomationLine classes: the + origin is zero, in whatever time domain the list we represent uses. + */ + return timepos_t (the_list()->time_domain()); } bool -AutomationLine::event_handler (GdkEvent* event) +AutomationLine::is_stepped() const { - return trackview.editor().canvas_line_event (event, line, this); + return (_desc.toggled || (alist && alist->interpolation() == AutomationList::Discrete)); +} + +void +AutomationLine::update_visibility () +{ + if (_visible & Line) { + /* Only show the line when there are some points, otherwise we may show an out-of-date line + when automation points have been removed (the line will still follow the shape of the + old points). + */ + if (line_points.size() >= 2) { + line->show(); + } else { + line->hide (); + } + + if (_visible & ControlPoints) { + for (auto & cp : control_points) { + cp->show (); + } + } else if (_visible & SelectedControlPoints) { + for (auto & cp : control_points) { + if (cp->selected()) { + cp->show (); + } else { + cp->hide (); + } + } + } else { + for (auto & cp : control_points) { + cp->hide (); + } + } + + } else { + line->hide (); + for (auto & cp : control_points) { + if (_visible & ControlPoints) { + cp->show (); + } else { + cp->hide (); + } + } + } +} + +bool +AutomationLine::get_uses_gain_mapping () const +{ + switch (_desc.type) { + case GainAutomation: + case BusSendLevel: + case EnvelopeAutomation: + case TrimAutomation: + case SurroundSendLevel: + case InsertReturnLevel: + return true; + default: + return false; + } +} + +void +AutomationLine::hide () +{ + /* leave control points setting unchanged, we are just hiding the + overall line + */ + + set_visibility (AutomationLine::VisibleAspects (_visible & ~Line)); +} + +double +AutomationLine::control_point_box_size () +{ + float uiscale = UIConfiguration::instance().get_ui_scale(); + uiscale = std::max (1.f, powf (uiscale, 1.71)); + + if (_height > TimeAxisView::preset_height (HeightLarger)) { + return rint (8.0 * uiscale); + } else if (_height > (guint32) TimeAxisView::preset_height (HeightNormal)) { + return rint (6.0 * uiscale); + } + return rint (12.0 * uiscale); +} + +void +AutomationLine::set_height (guint32 h) +{ + if (h != _height) { + _height = h; + + double bsz = control_point_box_size(); + + for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { + (*i)->set_size (bsz); + } + + if (_fill) { + line->set_fill_y1 (_height); + } else { + line->set_fill_y1 (0); + } + reset (); + } +} + +void +AutomationLine::set_line_color (string color_name, std::string color_mod) +{ + _line_color = color_name; + _line_color_mod = color_mod; + + uint32_t color = UIConfiguration::instance().color (color_name); + line->set_outline_color (color); + + Gtkmm2ext::SVAModifier mod = UIConfiguration::instance().modifier (color_mod.empty () ? "automation line fill" : color_mod); + + line->set_fill_color ((color & 0xffffff00) + mod.a() * 255); +} + +uint32_t +AutomationLine::get_line_color() const +{ + return UIConfiguration::instance().color (_line_color); +} + +ControlPoint* +AutomationLine::nth (uint32_t n) +{ + if (n < control_points.size()) { + return control_points[n]; + } else { + return 0; + } +} + +ControlPoint const * +AutomationLine::nth (uint32_t n) const +{ + if (n < control_points.size()) { + return control_points[n]; + } else { + return 0; + } +} + +void +AutomationLine::modify_points_y (std::vector const& cps, double y) +{ + /* clamp y-coord appropriately. y is supposed to be a normalized fraction (0.0-1.0), + and needs to be converted to a canvas unit distance. + */ + + y = max (0.0, y); + y = min (1.0, y); + y = _height - (y * _height); + + _editing_context.begin_reversible_command (_("automation event move")); + _editing_context.add_command (new MementoCommand (memento_command_binder(), &get_state(), 0)); + + alist->freeze (); + for (auto const& cp : cps) { + cp->move_to (cp->get_x(), y, ControlPoint::Full); + sync_model_with_view_point (*cp); + } + alist->thaw (); + + for (auto const& cp : cps) { + reset_line_coords (*cp); + } + + if (line_points.size() > 1) { + line->set_steps (line_points, is_stepped()); + } + + update_pending = false; + + _editing_context.add_command (new MementoCommand (memento_command_binder(), 0, &alist->get_state())); + + _editing_context.commit_reversible_command (); + _editing_context.session()->set_dirty (); +} + +void +AutomationLine::reset_line_coords (ControlPoint& cp) +{ + if (cp.view_index() < line_points.size()) { + line_points[cp.view_index() + _view_index_offset].x = cp.get_x (); + line_points[cp.view_index() + _view_index_offset].y = cp.get_y (); + } +} + +bool +AutomationLine::sync_model_with_view_points (list cp) +{ + update_pending = true; + + bool moved = false; + for (auto const & vp : cp) { + moved = sync_model_with_view_point (*vp) || moved; + } + + return moved; +} + +string +AutomationLine::get_verbose_cursor_string (double fraction) const +{ + return fraction_to_string (fraction); +} + +string +AutomationLine::get_verbose_cursor_relative_string (double fraction, double delta) const +{ + std::string s = fraction_to_string (fraction); + std::string d = delta_to_string (delta); + return s + " (" + d + ")"; +} + +/** + * @param fraction y fraction + * @return string representation of this value, using dB if appropriate. + */ +string +AutomationLine::fraction_to_string (double fraction) const +{ + view_to_model_coord_y (fraction); + return ARDOUR::value_as_string (_desc, fraction); +} + +string +AutomationLine::delta_to_string (double delta) const +{ + if (!get_uses_gain_mapping () && _desc.logarithmic) { + return "x " + ARDOUR::value_as_string (_desc, delta); + } else { + return u8"\u0394 " + ARDOUR::value_as_string (_desc, delta); + } +} + +/** + * @param s Value string in the form as returned by fraction_to_string. + * @return Corresponding y fraction. + */ +double +AutomationLine::string_to_fraction (string const & s) const +{ + double v; + sscanf (s.c_str(), "%lf", &v); + + switch (_desc.type) { + case GainAutomation: + case BusSendLevel: + case EnvelopeAutomation: + case TrimAutomation: + case SurroundSendLevel: + case InsertReturnLevel: + if (s == "-inf") { /* translation */ + v = 0; + } else { + v = dB_to_coefficient (v); + } + break; + default: + break; + } + return model_to_view_coord_y (v); +} + +/** Start dragging a single point, possibly adding others if the supplied point is selected and there + * are other selected points. + * + * @param cp Point to drag. + * @param x Initial x position (units). + * @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_single (ControlPoint* cp, double x, float fraction) +{ + _editing_context.add_command (new MementoCommand (memento_command_binder(), &get_state(), 0)); + + _drag_points.clear (); + _drag_points.push_back (cp); + + if (cp->selected ()) { + for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { + if (*i != cp && (*i)->selected()) { + _drag_points.push_back (*i); + } + } + } + + 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::start_drag_line (uint32_t i1, uint32_t i2, float fraction) +{ + _editing_context.add_command (new MementoCommand (memento_command_binder (), &get_state(), 0)); + + _drag_points.clear (); + + for (uint32_t i = i1; i <= i2; i++) { + _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 cp, float fraction, XMLNode* state) +{ + _editing_context.add_command (new MementoCommand (memento_command_binder(), state, 0)); + + _drag_points = cp; + start_drag_common (0, fraction); +} + +struct ControlPointSorter +{ + bool operator() (ControlPoint const * a, ControlPoint const * b) const { + if (floateq (a->get_x(), b->get_x(), 1)) { + return a->view_index() < b->view_index(); + } + return a->get_x() < b->get_x(); + } +}; + +AutomationLine::ContiguousControlPoints::ContiguousControlPoints (AutomationLine& al) + : line (al), before_x (timepos_t (line.the_list()->time_domain())), after_x (timepos_t::max (line.the_list()->time_domain())) +{ +} + +void +AutomationLine::ContiguousControlPoints::compute_x_bounds () +{ + uint32_t sz = size(); + + if (sz > 0 && sz < line.npoints()) { + const TempoMap::SharedPtr map (TempoMap::use()); + + /* determine the limits on x-axis motion for this + contiguous range of control points + */ + + if (front()->view_index() > 0) { + before_x = (*line.nth (front()->view_index() - 1)->model())->when; + before_x += timepos_t (64); + } + + /* if our last point has a point after it in the line, + we have an "after" bound + */ + + if (back()->view_index() < (line.npoints() - 1)) { + after_x = (*line.nth (back()->view_index() + 1)->model())->when; + after_x.shift_earlier (timepos_t (64)); + } + } +} + +Temporal::timecnt_t +AutomationLine::ContiguousControlPoints::clamp_dt (timecnt_t const & dt, timepos_t const & line_limit) +{ + if (empty()) { + return dt; + } + + /* get the maximum distance we can move any of these points along the x-axis + */ + + ControlPoint* reference_point; + + if (dt.magnitude() > 0) { + /* check the last point, since we're moving later in time */ + reference_point = back(); + } else { + /* check the first point, since we're moving earlier in time */ + reference_point = front(); + } + + /* possible position the "reference" point would move to, given dx */ + Temporal::timepos_t possible_pos = (*reference_point->model())->when + dt; // new possible position if we just add the motion + + /* Now clamp that position so that: + * + * - it is not before the origin (zero) + * - it is not beyond the line's own limit (e.g. for region automation) + * - it is not before the preceding point + * - it is not after the following point + */ + + possible_pos = max (possible_pos, Temporal::timepos_t (possible_pos.time_domain())); + possible_pos = min (possible_pos, line_limit); + + possible_pos = max (possible_pos, before_x); // can't move later than following point + possible_pos = min (possible_pos, after_x); // can't move earlier than preceding point + + return (*reference_point->model())->when.distance (possible_pos); +} + +void +AutomationLine::ContiguousControlPoints::move (timecnt_t const & dt, double dvalue) +{ + for (auto & cp : *this) { + // compute y-axis delta + double view_y = 1.0 - cp->get_y() / line.height(); + line.view_to_model_coord_y (view_y); + line.apply_delta (view_y, dvalue); + view_y = line.model_to_view_coord_y (view_y); + view_y = (1.0 - view_y) * line.height(); + + cp->move_to (line.dt_to_dx ((*cp->model())->when, dt), view_y, ControlPoint::Full); + line.reset_line_coords (*cp); + } +} + +/** Common parts of starting a drag. + * @param x Starting x position in units, 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 (double x, float fraction) +{ + _last_drag_fraction = fraction; + _drag_had_movement = false; + did_push = false; + + /* they are probably ordered already, but we have to make sure */ + + _drag_points.sort (ControlPointSorter()); +} + +/** Takes a relative-to-origin position, moves it by dt, and returns a + * relative-to-origin pixel count. + */ +double +AutomationLine::dt_to_dx (timepos_t const & pos, timecnt_t const & dt) +{ + /* convert a shift of pos by dt into an absolute timepos */ + timepos_t const new_pos ((pos + dt + get_origin()).shift_earlier (offset())); + /* convert to pixels */ + double px = _editing_context.time_to_pixel_unrounded (new_pos); + /* convert back to pixels-relative-to-origin */ + px -= _editing_context.time_to_pixel_unrounded (get_origin()); + return px; +} + +/** Should be called to indicate motion during a drag. + * @param x New x position of the drag in canvas units relative to origin, or undefined if ignore_x == true. + * @param fraction New y fraction. + * @return x position and y fraction that were actually used (once clamped). + */ +pair +AutomationLine::drag_motion (timecnt_t const & pdt, float fraction, bool ignore_x, bool with_push, uint32_t& final_index) +{ + if (_drag_points.empty()) { + return pair (fraction, _desc.is_linear () ? 0 : 1); + } + + timecnt_t dt (pdt); + + if (ignore_x) { + dt = timecnt_t (pdt.time_domain()); + } + + double dy = fraction - _last_drag_fraction; + + if (!_drag_had_movement) { + + /* "first move" ... do some stuff that we don't want to do if + no motion ever took place, but need to do before we handle + motion. + */ + + /* partition the points we are dragging into (potentially several) + * set(s) of contiguous points. this will not happen with a normal + * drag, but if the user does a discontiguous selection, it can. + */ + + uint32_t expected_view_index = 0; + CCP contig; + + for (list::iterator i = _drag_points.begin(); i != _drag_points.end(); ++i) { + if (i == _drag_points.begin() || (*i)->view_index() != expected_view_index) { + contig.reset (new ContiguousControlPoints (*this)); + contiguous_points.push_back (contig); + } + contig->push_back (*i); + expected_view_index = (*i)->view_index() + 1; + } + + if (contiguous_points.back()->empty()) { + contiguous_points.pop_back (); + } + + for (auto const & ccp : contiguous_points) { + ccp->compute_x_bounds (); + } + _drag_had_movement = true; + } + + /* OK, now on to the stuff related to *this* motion event. First, for + * each contiguous range, figure out the maximum x-axis motion we are + * allowed (because of neighbouring points that are not moving. + * + * if we are moving forwards with push, we don't need to do this, + * since all later points will move too. + */ + + if (dt.is_negative() || (dt.is_positive() && !with_push)) { + const timepos_t line_limit = get_origin() + maximum_time() + _offset; + for (auto const & ccp : contiguous_points){ + dt = ccp->clamp_dt (dt, line_limit); + } + } + + /* compute deflection */ + double delta_value; + { + double value0 = _last_drag_fraction; + double value1 = _last_drag_fraction + dy; + view_to_model_coord_y (value0); + view_to_model_coord_y (value1); + delta_value = compute_delta (value0, value1); + } + + /* special case -inf */ + if (delta_value == 0 && dy > 0 && !_desc.is_linear ()) { + assert (_desc.lower == 0); + delta_value = 1.0; + } + + /* clamp y */ + for (list::iterator i = _drag_points.begin(); i != _drag_points.end(); ++i) { + double vy = 1.0 - (*i)->get_y() / _height; + view_to_model_coord_y (vy); + const double orig = vy; + apply_delta (vy, delta_value); + if (vy < _desc.lower) { + delta_value = compute_delta (orig, _desc.lower); + } + if (vy > _desc.upper) { + delta_value = compute_delta (orig, _desc.upper); + } + } + + if (!dt.is_zero() || dy) { + /* and now move each section */ + + + for (vector::iterator ccp = contiguous_points.begin(); ccp != contiguous_points.end(); ++ccp) { + (*ccp)->move (dt, delta_value); + } + + if (with_push) { + final_index = contiguous_points.back()->back()->view_index () + 1; + ControlPoint* p; + uint32_t i = final_index; + + while ((p = nth (i)) != 0 && p->can_slide()) { + + p->move_to (dt_to_dx ((*p->model())->when, dt), p->get_y(), ControlPoint::Full); + reset_line_coords (*p); + ++i; + } + } + + /* update actual line coordinates (will queue a redraw) */ + + if (line_points.size() > 1) { + line->set_steps (line_points, is_stepped()); + } + } + + /* calculate effective delta */ + ControlPoint* cp = _drag_points.front(); + double vy = 1.0 - cp->get_y() / (double)_height; + view_to_model_coord_y (vy); + float val = (*(cp->model ()))->value; + float effective_delta = _desc.compute_delta (val, vy); + /* special case recovery from -inf */ + if (val == 0 && effective_delta == 0 && vy > 0) { + assert (!_desc.is_linear ()); + effective_delta = HUGE_VAL; // +Infinity + } + + double const result_frac = _last_drag_fraction + dy; + _last_drag_fraction = result_frac; + did_push = with_push; + + return pair (result_frac, effective_delta); +} + +/** Should be called to indicate the end of a drag */ +void +AutomationLine::end_drag (bool with_push, uint32_t final_index) +{ + if (!_drag_had_movement) { + return; + } + + alist->freeze (); + bool moved = sync_model_with_view_points (_drag_points); + + if (with_push) { + ControlPoint* p; + uint32_t i = final_index; + while ((p = nth (i)) != 0 && p->can_slide()) { + moved = sync_model_with_view_point (*p) || moved; + ++i; + } + } + + alist->thaw (); + + update_pending = false; + + if (moved) { + /* A point has moved as a result of sync (clamped to integer or boolean + value), update line accordingly. */ + line->set_steps (line_points, is_stepped()); + } + + _editing_context.add_command (new MementoCommand(memento_command_binder (), 0, &alist->get_state())); + + _editing_context.session()->set_dirty (); + did_push = false; + + contiguous_points.clear (); +} + +/** + * + * get model coordinates synced with (possibly changed) view coordinates. + * + * For example, we call this in ::end_drag(), when we have probably moved a + * point in the view, and now want to "push" that change back into the + * corresponding model point. + */ +bool +AutomationLine::sync_model_with_view_point (ControlPoint& cp) +{ + /* find out where the visual control point is. + * ControlPoint uses canvas-units. The origin + * is the RegionView's top-left corner. + */ + double view_x = cp.get_x(); + + /* model time is relative to the Region (regardless of region->start offset) */ + timepos_t model_time = (*cp.model())->when; + + const timepos_t origin (get_origin()); + + /* convert to absolute time on timeline */ + const timepos_t absolute_time = model_time + origin; + + /* now convert to pixels relative to start of region, which matches view_x */ + const double model_x = _editing_context.time_to_pixel_unrounded (absolute_time) - _editing_context.time_to_pixel_unrounded (origin); + + if (view_x != model_x) { + + /* convert the current position in the view (units: + * region-relative pixels) into samples, then use that to + * create a timecnt_t that measures the distance from the + * origin for this line. + * + * Note that the offset and origin is irrelevant here, + * pixel_to_sample() islinear only depending on zoom level. + */ + + const timepos_t view_samples (_editing_context.pixel_to_sample (view_x)); + + /* measure distance from RegionView origin (this preserves time domain) */ + + if (model_time.time_domain() == Temporal::AudioTime) { + model_time = timepos_t (timecnt_t (view_samples, origin).samples()); + } else { + model_time = timepos_t (timecnt_t (view_samples, origin).beats()); + } + + /* convert RegionView to Region position (account for region->start() _offset) */ + model_time += _offset; + } + + update_pending = true; + + double view_y = 1.0 - cp.get_y() / (double)_height; + view_to_model_coord_y (view_y); + + alist->modify (cp.model(), model_time, view_y); + + /* convert back from model to view y for clamping position (for integer/boolean/etc) */ + view_y = model_to_view_coord_y (view_y); + const double point_y = _height - (view_y * _height); + if (point_y != cp.get_y()) { + cp.move_to (cp.get_x(), point_y, ControlPoint::Full); + reset_line_coords (cp); + return true; + } + + return false; +} + +bool +AutomationLine::control_points_adjacent (double xval, uint32_t & before, uint32_t& after) +{ + ControlPoint *bcp = 0; + ControlPoint *acp = 0; + double unit_xval; + + unit_xval = _editing_context.sample_to_pixel_unrounded (xval); + + for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { + + if ((*i)->get_x() <= unit_xval) { + + if (!bcp || (*i)->get_x() > bcp->get_x()) { + bcp = *i; + before = bcp->view_index(); + } + + } else if ((*i)->get_x() > unit_xval) { + acp = *i; + after = acp->view_index(); + break; + } + } + + return bcp && acp; +} + +bool +AutomationLine::is_last_point (ControlPoint& cp) +{ + // If the list is not empty, and the point is the last point in the list + + if (alist->empty()) { + return false; + } + + AutomationList::const_iterator i = alist->end(); + --i; + + if (cp.model() == i) { + return true; + } + + return false; +} + +bool +AutomationLine::is_first_point (ControlPoint& cp) +{ + // If the list is not empty, and the point is the first point in the list + + if (!alist->empty() && cp.model() == alist->begin()) { + return true; + } + + return false; +} + +// This is copied into AudioRegionGainLine +void +AutomationLine::remove_point (ControlPoint& cp) +{ + _editing_context.begin_reversible_command (_("remove control point")); + XMLNode &before = alist->get_state(); + + _editing_context.get_selection ().clear_points (); + alist->erase (cp.model()); + + _editing_context.add_command (new MementoCommand (memento_command_binder (), &before, &alist->get_state())); + + _editing_context.commit_reversible_command (); + _editing_context.session()->set_dirty (); +} + +/** Get selectable points within an area. + * @param start Start position in session samples. + * @param end End position in session samples. + * @param bot Bottom y range, as a fraction of line height, where 0 is the bottom of the line. + * @param top Top y range, as a fraction of line height, where 0 is the bottom of the line. + * @param result Filled in with selectable things; in this case, ControlPoints. + */ +void +AutomationLine::get_selectables (timepos_t const & start, timepos_t const & end, double botfrac, double topfrac, list& results) +{ + /* convert fractions to display coordinates with 0 at the top of the track */ + double const bot_track = (1 - topfrac) * _height; // this should StreamView::child_height () for RegionGain + double const top_track = (1 - botfrac) * _height; // --"-- + + for (auto const & cp : control_points) { + + const timepos_t w = session_position ((*cp->model())->when); + + if (w >= start && w <= end && cp->get_y() >= bot_track && cp->get_y() <= top_track) { + results.push_back (cp); + } + } +} + +void +AutomationLine::get_inverted_selectables (Selection&, list& /*results*/) +{ + // hmmm .... +} + +void +AutomationLine::set_selected_points (PointSelection const & points) +{ + for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { + (*i)->set_selected (false); + } + + for (PointSelection::const_iterator i = points.begin(); i != points.end(); ++i) { + (*i)->set_selected (true); + } + + if (points.empty()) { + remove_visibility (SelectedControlPoints); + } else { + add_visibility (SelectedControlPoints); + } + + set_colors (); +} + +void +AutomationLine::set_colors () +{ + set_line_color (_line_color, _line_color_mod); + for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { + (*i)->set_color (); + } +} + +void +AutomationLine::list_changed () +{ + DEBUG_TRACE (DEBUG::Automation, string_compose ("\tline changed, existing update pending? %1\n", update_pending)); + + if (!update_pending) { + update_pending = true; + Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&AutomationLine::queue_reset, this)); + } +} + +void +AutomationLine::tempo_map_changed () +{ + if (alist->time_domain() != Temporal::BeatTime) { + return; + } + + reset (); +} + +void +AutomationLine::reset_callback (const Evoral::ControlList& events) +{ + uint32_t vp = 0; + uint32_t pi = 0; + uint32_t np; + + if (events.empty()) { + for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { + delete *i; + } + control_points.clear (); + line->hide(); + line_points.clear (); + return; + } + + /* hide all existing points, and the line */ + + for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { + (*i)->hide(); + } + + line->hide (); + np = events.size(); + + Evoral::ControlList& e (const_cast (events)); + AutomationList::iterator preceding (e.end()); + AutomationList::iterator following (e.end()); + + for (AutomationList::iterator ai = e.begin(); ai != e.end(); ++ai, ++pi) { + + /* drop points outside our range */ + + if (((*ai)->when < _offset)) { + preceding = ai; + continue; + } + + if ((*ai)->when >= _offset + _maximum_time) { + following = ai; + break; + } + + double ty = model_to_view_coord_y ((*ai)->value); + + if (isnan_local (ty)) { + warning << string_compose (_("Ignoring illegal points on EditorAutomationLine \"%1\""), _name) << endmsg; + continue; + } + + /* convert from canonical view height (0..1.0) to actual + * height coordinates (using X11's top-left rooted system) + */ + + ty = _height - (ty * _height); + + /* tx is currently the distance of this point from + * _offset, which may be either: + * + * a) zero, for an automation line not connected to a + * region + * + * b) some non-zero value, corresponding to the start + * of the region within its source(s). Remember that + * this start is an offset within the source, not a + * position on the timeline. + * + * We need to convert tx to a global position, and to + * do that we need to measure the distance from the + * result of get_origin(), which tells ut the timeline + * position of _offset + */ + + timecnt_t tx = model_to_view_coord_x ((*ai)->when); + + /* convert x-coordinate to a canvas unit coordinate (this takes + * zoom and scroll into account). + */ + + double px = _editing_context.duration_to_pixels_unrounded (tx); + add_visible_control_point (vp, pi, px, ty, ai, np); + vp++; + } + + /* discard extra CP's to avoid confusing ourselves */ + + while (control_points.size() > vp) { + ControlPoint* cp = control_points.back(); + control_points.pop_back (); + delete cp; + } + + if (!terminal_points_can_slide && !control_points.empty()) { + control_points.back()->set_can_slide(false); + } + + if (vp) { + + /* reset the line coordinates given to the CanvasLine */ + + /* 2 extra in case we need hidden points for line start and end */ + + line_points.resize (vp + 2, ArdourCanvas::Duple (0, 0)); + + ArdourCanvas::Points::size_type n = 0; + + /* potentially insert front hidden (line) point to make the line draw from + * zero to the first actual point + */ + + _view_index_offset = 0; + + if (control_points[0]->get_x() != 0 && preceding != e.end()) { + double ty = model_to_view_coord_y (e.unlocked_eval (_offset)); + + if (isnan_local (ty)) { + warning << string_compose (_("Ignoring illegal points on EditorAutomationLine \"%1\""), _name) << endmsg; + + + } else { + line_points[n].y = _height - (ty * _height); + line_points[n].x = 0; + _view_index_offset = 1; + ++n; + } + } + + for (auto const & cp : control_points) { + line_points[n].x = cp->get_x(); + line_points[n].y = cp->get_y(); + ++n; + } + + /* potentially insert final hidden (line) point to make the line draw + * from the last point to the very end + */ + + double px = _editing_context.duration_to_pixels_unrounded (model_to_view_coord_x (_offset + _maximum_time)); + + if (control_points[control_points.size() - 1]->get_x() != px && following != e.end()) { + double ty = model_to_view_coord_y (e.unlocked_eval (_offset + _maximum_time)); + + if (isnan_local (ty)) { + warning << string_compose (_("Ignoring illegal points on EditorAutomationLine \"%1\""), _name) << endmsg; + + + } else { + line_points[n].y = _height - (ty * _height); + line_points[n].x = px; + ++n; + } + } + + line_points.resize (n); + line->set_steps (line_points, is_stepped()); + + update_visibility (); + } + + set_selected_points (_editing_context.get_selection().points); +} + +void +AutomationLine::reset () +{ + DEBUG_TRACE (DEBUG::Automation, "\t\tLINE RESET\n"); + update_pending = false; + have_reset_timeout = false; + + if (no_draw) { + return; + } + + /* TODO: abort any drags in progress, e.g. dragging points while writing automation + * (the control-point model, used by AutomationLine::drag_motion, will be invalid). + * + * Note: reset() may also be called from an aborted drag (LineDrag::aborted) + * maybe abort in list_changed(), interpolation_changed() and ... ? + * XXX + */ + + alist->apply_to_points (*this, &AutomationLine::reset_callback); +} + +void +AutomationLine::queue_reset () +{ + /* this must be called from the GUI thread */ + + if (_editing_context.session()->transport_rolling() && alist->automation_write()) { + /* automation write pass ... defer to a timeout */ + /* redraw in 1/4 second */ + if (!have_reset_timeout) { + DEBUG_TRACE (DEBUG::Automation, "\tqueue timeout\n"); + Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &AutomationLine::reset), false), 250); + have_reset_timeout = true; + } else { + DEBUG_TRACE (DEBUG::Automation, "\ttimeout already queued, change ignored\n"); + } + } else { + reset (); + } +} + +void +AutomationLine::clear () +{ + /* parent must create and commit command */ + XMLNode &before = alist->get_state(); + alist->clear(); + + _editing_context.add_command (new MementoCommand (memento_command_binder (), &before, &alist->get_state())); +} + +void +AutomationLine::set_list (std::shared_ptr list) +{ + alist = list; + queue_reset (); + connect_to_list (); +} + +void +AutomationLine::add_visibility (VisibleAspects va) +{ + VisibleAspects old = _visible; + + _visible = VisibleAspects (_visible | va); + + if (old != _visible) { + update_visibility (); + } +} + +void +AutomationLine::set_visibility (VisibleAspects va) +{ + if (_visible != va) { + _visible = va; + update_visibility (); + } +} + +void +AutomationLine::remove_visibility (VisibleAspects va) +{ + VisibleAspects old = _visible; + + _visible = VisibleAspects (_visible & ~va); + + if (old != _visible) { + update_visibility (); + } +} + +void +AutomationLine::track_entered() +{ + add_visibility (ControlPoints); +} + +void +AutomationLine::track_exited() +{ + remove_visibility (ControlPoints); +} + +XMLNode & +AutomationLine::get_state () const +{ + /* function as a proxy for the model */ + return alist->get_state(); +} + +int +AutomationLine::set_state (const XMLNode &node, int version) +{ + /* function as a proxy for the model */ + return alist->set_state (node, version); +} + +void +AutomationLine::view_to_model_coord_y (double& y) const +{ + if (alist->default_interpolation () != alist->interpolation()) { + switch (alist->interpolation()) { + case AutomationList::Discrete: + /* toggles and MIDI only -- see is_stepped() */ + assert (alist->default_interpolation () == AutomationList::Linear); + break; + case AutomationList::Linear: + y = y * (_desc.upper - _desc.lower) + _desc.lower; + return; + default: + /* types that default to linear, can't be use + * Logarithmic or Exponential interpolation. + * "Curved" is invalid for automation (only x-fads) + */ + assert (0); + break; + } + } + y = _desc.from_interface (y); +} + +double +AutomationLine::compute_delta (double from, double to) const +{ + return _desc.compute_delta (from, to); +} + +void +AutomationLine::apply_delta (double& val, double delta) const +{ + if (val == 0 && !_desc.is_linear () && delta >= 1.0) { + /* recover from -inf */ + val = 1.0 / _height; + view_to_model_coord_y (val); + return; + } + val = _desc.apply_delta (val, delta); +} + +double +AutomationLine::model_to_view_coord_y (double y) const +{ + if (alist->default_interpolation () != alist->interpolation()) { + switch (alist->interpolation()) { + case AutomationList::Discrete: + /* toggles and MIDI only -- see is_stepped */ + assert (alist->default_interpolation () == AutomationList::Linear); + break; + case AutomationList::Linear: + return (y - _desc.lower) / (_desc.upper - _desc.lower); + default: + /* types that default to linear, can't be use + * Logarithmic or Exponential interpolation. + * "Curved" is invalid for automation (only x-fads) + */ + assert (0); + break; + } + } + return _desc.to_interface (y); +} + +timecnt_t +AutomationLine::model_to_view_coord_x (timepos_t const & when) const +{ + /* @param when is a distance (with implicit origin) from the start of the + * source. So we subtract the offset (from the region if this is + * related to a region; zero otherwise) to get the distance (again, + * implicit origin) from the start of the line. + * + * Then we construct a timecnt_t from this duration, and the origin of + * the line on the timeline. + */ + + return timecnt_t (when.earlier (_offset), get_origin()); +} + +/** Called when our list has announced that its interpolation style has changed */ +void +AutomationLine::interpolation_changed (AutomationList::InterpolationStyle style) +{ + if (line_points.size() > 1) { + reset (); + line->set_steps(line_points, is_stepped()); + } +} + +void +AutomationLine::add_visible_control_point (uint32_t view_index, uint32_t pi, double tx, double ty, + AutomationList::iterator model, uint32_t npoints) +{ + ControlPoint::ShapeType shape; + + if (view_index >= control_points.size()) { + + /* make sure we have enough control points */ + + ControlPoint* ncp = new ControlPoint (*this); + ncp->set_size (control_point_box_size ()); + + control_points.push_back (ncp); + } + + if (!terminal_points_can_slide) { + if (pi == 0) { + control_points[view_index]->set_can_slide (false); + if (tx == 0) { + shape = ControlPoint::Start; + } else { + shape = ControlPoint::Full; + } + } else if (pi == npoints - 1) { + control_points[view_index]->set_can_slide (false); + shape = ControlPoint::End; + } else { + control_points[view_index]->set_can_slide (true); + shape = ControlPoint::Full; + } + } else { + control_points[view_index]->set_can_slide (true); + shape = ControlPoint::Full; + } + + control_points[view_index]->reset (tx, ty, model, view_index, shape); + + /* finally, control visibility */ + + if (_visible & ControlPoints) { + control_points[view_index]->show (); + } else { + control_points[view_index]->hide (); + } +} + +void +AutomationLine::dump (std::ostream& ostr) const +{ + for (auto const & cp : control_points) { + if (cp->model() != alist->end()) { + ostr << '#' << cp->view_index() << " @ " << cp->get_x() << ", " << cp->get_y() << " for " << (*cp->model())->value << " @ " << (*(cp->model()))->when << std::endl; + } else { + ostr << "dead point\n"; + } + } +} + +void +AutomationLine::connect_to_list () +{ + _list_connections.drop_connections (); + + alist->StateChanged.connect (_list_connections, invalidator (*this), boost::bind (&AutomationLine::list_changed, this), gui_context()); + + alist->InterpolationChanged.connect ( + _list_connections, invalidator (*this), boost::bind (&AutomationLine::interpolation_changed, this, _1), gui_context()); +} + +MementoCommandBinder* +AutomationLine::memento_command_binder () +{ + return new SimpleMementoCommandBinder (*alist.get()); +} + +/** Set the maximum time that points on this line can be at, relative + * to the start of the track or region that it is on. + */ +void +AutomationLine::set_maximum_time (Temporal::timepos_t const & t) +{ + if (_maximum_time == t) { + return; + } + + _maximum_time = t; + reset (); +} + + +/** @return min and max x positions of points that are in the list, in session samples */ +pair +AutomationLine::get_point_x_range () const +{ + pair r (timepos_t::max (the_list()->time_domain()), timepos_t::zero (the_list()->time_domain())); + + for (auto const & cp : *the_list()) { + const timepos_t w (session_position (cp->when)); + r.first = min (r.first, w); + r.second = max (r.second, w); + } + + return r; +} + +timepos_t +AutomationLine::session_position (timepos_t const & when) const +{ + return when + get_origin(); +} + +void +AutomationLine::set_offset (timepos_t const & off) +{ + _offset = off; + reset (); } diff --git a/gtk2_ardour/automation_line.h b/gtk2_ardour/automation_line.h index d8f4fec417..2754af95f8 100644 --- a/gtk2_ardour/automation_line.h +++ b/gtk2_ardour/automation_line.h @@ -23,8 +23,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef __ardour_automation_line_h__ -#define __ardour_automation_line_h__ +#ifndef __gtk2_ardour_automation_line_base_h__ +#define __gtk2_ardour_automation_line_base_h__ #include #include @@ -45,39 +45,220 @@ #include "canvas/container.h" #include "canvas/poly_line.h" -#include "automation_line_base.h" +namespace ArdourCanvas { + class Rectangle; +} -class AutomationLine; +class EditorAutomationLine; class ControlPoint; class PointSelection; class TimeAxisView; class AutomationTimeAxisView; class Selectable; class Selection; -class PublicEditor; +class EditingContext; - -/** A GUI representation of an ARDOUR::AutomationList within the main editor - * (i.e. in a TimeAxisView - */ - -class AutomationLine : public AutomationLineBase +/** A GUI representation of an ARDOUR::AutomationList */ +class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible { public: - AutomationLine (const std::string& name, - TimeAxisView& tv, - ArdourCanvas::Item& parent, - std::shared_ptr al, - const ARDOUR::ParameterDescriptor& desc); + enum VisibleAspects { + Line = 0x1, + ControlPoints = 0x2, + SelectedControlPoints = 0x4 + }; + AutomationLine (const std::string& name, + EditingContext& ec, + ArdourCanvas::Item& parent, + ArdourCanvas::Rectangle* drag_base, + std::shared_ptr al, + const ARDOUR::ParameterDescriptor& desc); virtual ~AutomationLine (); - TimeAxisView& trackview; + virtual Temporal::timepos_t get_origin () const; - protected: - virtual bool event_handler (GdkEvent*); + ArdourCanvas::Rectangle* drag_base() const { return _drag_base; } + + void queue_reset (); + void reset (); + void clear (); + void set_fill (bool f) { _fill = f; } // owner needs to call set_height + + void set_selected_points (PointSelection const &); + void get_selectables (Temporal::timepos_t const &, Temporal::timepos_t const &, double, double, std::list&); + void get_inverted_selectables (Selection&, std::list& results); + + virtual void remove_point (ControlPoint&); + bool control_points_adjacent (double xval, uint32_t& before, uint32_t& after); + + /* dragging API */ + virtual void start_drag_single (ControlPoint*, double, float); + virtual void start_drag_line (uint32_t, uint32_t, float); + virtual void start_drag_multiple (std::list, float, XMLNode *); + virtual std::pair drag_motion (Temporal::timecnt_t const &, float, bool, bool with_push, uint32_t& final_index); + virtual void end_drag (bool with_push, uint32_t final_index); + virtual void end_draw_merge () {} + + ControlPoint* nth (uint32_t); + ControlPoint const * nth (uint32_t) const; + uint32_t npoints() const { return control_points.size(); } + + std::string name() const { return _name; } + bool visible() const { return _visible != VisibleAspects(0); } + guint32 height() const { return _height; } + + void set_line_color (std::string color, std::string mod = ""); + uint32_t get_line_color() const; + + void set_visibility (VisibleAspects); + void add_visibility (VisibleAspects); + void remove_visibility (VisibleAspects); + + void hide (); + void set_height (guint32); + + bool get_uses_gain_mapping () const; + void tempo_map_changed (); + + ArdourCanvas::Container& canvas_group() const { return *group; } + ArdourCanvas::Item& parent_group() const { return _parent_group; } + ArdourCanvas::Item& grab_item() const { return *line; } + + virtual std::string get_verbose_cursor_string (double) const; + std::string get_verbose_cursor_relative_string (double, double) const; + std::string fraction_to_string (double) const; + std::string delta_to_string (double) const; + double string_to_fraction (std::string const &) const; + + void view_to_model_coord_y (double &) const; + + double model_to_view_coord_y (double) const; + Temporal::timecnt_t model_to_view_coord_x (Temporal::timepos_t const &) const; + + double compute_delta (double from, double to) const; + void apply_delta (double& val, double delta) const; + + void set_list(std::shared_ptr list); + std::shared_ptr the_list() const { return alist; } + + void track_entered(); + void track_exited(); + + bool is_last_point (ControlPoint &); + bool is_first_point (ControlPoint &); + + XMLNode& get_state () const; + int set_state (const XMLNode&, int version); + void set_colors(); + + void modify_points_y (std::vector const&, double); + + virtual MementoCommandBinder* memento_command_binder (); + + std::pair get_point_x_range () const; + + void set_maximum_time (Temporal::timepos_t const &); + Temporal::timepos_t maximum_time () const { + return _maximum_time; + } + + void set_offset (Temporal::timepos_t const &); + Temporal::timepos_t offset () { return _offset; } + void set_width (Temporal::timecnt_t const &); + + Temporal::timepos_t session_position (Temporal::timepos_t const &) const; + void dump (std::ostream&) const; + + double dt_to_dx (Temporal::timepos_t const &, Temporal::timecnt_t const &); + + ARDOUR::ParameterDescriptor const & param() const { return _desc; } + EditingContext& editing_context() const { return _editing_context; } + +protected: + + std::string _name; + guint32 _height; + std::string _line_color; + std::string _line_color_mod; + uint32_t _view_index_offset; + std::shared_ptr alist; + + VisibleAspects _visible; + + bool terminal_points_can_slide; + bool update_pending; + bool have_reset_timeout; + bool no_draw; + bool _is_boolean; + /** true if we did a push at any point during the current drag */ + bool did_push; + + EditingContext& _editing_context; + ArdourCanvas::Item& _parent_group; + ArdourCanvas::Rectangle* _drag_base; + ArdourCanvas::Container* group; + ArdourCanvas::PolyLine* line; /* line */ + ArdourCanvas::Points line_points; /* coordinates for canvas line */ + std::vector control_points; /* visible control points */ + + class ContiguousControlPoints : public std::list { + public: + ContiguousControlPoints (AutomationLine& al); + Temporal::timecnt_t clamp_dt (Temporal::timecnt_t const & dx, Temporal::timepos_t const & region_limit); + void move (Temporal::timecnt_t const &, double dvalue); + void compute_x_bounds (); + private: + AutomationLine& line; + Temporal::timepos_t before_x; + Temporal::timepos_t after_x; + }; + + friend class ContiguousControlPoints; + + typedef std::shared_ptr CCP; + std::vector contiguous_points; + + bool sync_model_with_view_point (ControlPoint&); + bool sync_model_with_view_points (std::list); + void start_drag_common (double, float); + + void reset_callback (const Evoral::ControlList&); + void list_changed (); + + virtual bool event_handler (GdkEvent*) = 0; + +private: + std::list _drag_points; ///< points we are dragging + std::list _push_points; ///< additional points we are dragging if "push" is enabled + bool _drag_had_movement; ///< true if the drag has seen movement, otherwise false + double _last_drag_fraction; ///< last y position of the drag, as a fraction + /** offset from the start of the automation list to the start of the line, so that + * a +ve offset means that the 0 on the line is at _offset in the list + */ + Temporal::timepos_t _offset; + + bool is_stepped() const; + void update_visibility (); + 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 (); + void connect_to_list (); + void interpolation_changed (ARDOUR::AutomationList::InterpolationStyle); + + PBD::ScopedConnectionList _list_connections; + + /** maximum time that a point on this line can be at, relative to the position of its region or start of its track */ + Temporal::timepos_t _maximum_time; + + bool _fill; + + const ARDOUR::ParameterDescriptor _desc; + + friend class AudioRegionGainLine; + friend class RegionFxLine; }; -#endif /* __ardour_automation_line_h__ */ +#endif /* __gtk2_ardour_automation_line_base_h__ */ diff --git a/gtk2_ardour/automation_line_base.cc b/gtk2_ardour/automation_line_base.cc deleted file mode 100644 index 3ba06484bd..0000000000 --- a/gtk2_ardour/automation_line_base.cc +++ /dev/null @@ -1,1514 +0,0 @@ -/* - * Copyright (C) 2005-2017 Paul Davis - * Copyright (C) 2005 Karsten Wiese - * Copyright (C) 2005 Taybin Rutkin - * Copyright (C) 2006 Hans Fugal - * Copyright (C) 2007-2012 Carl Hetherington - * Copyright (C) 2007-2015 David Robillard - * Copyright (C) 2007 Doug McLain - * Copyright (C) 2013-2017 Robin Gareus - * Copyright (C) 2014-2016 Nick Mainsbridge - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -#ifdef COMPILER_MSVC -#include - -// 'std::isnan()' is not available in MSVC. -#define isnan_local(val) (bool)_isnan((double)val) -#else -#define isnan_local std::isnan -#endif - -#include -#include - -#include "boost/shared_ptr.hpp" - -#include "pbd/floating.h" -#include "pbd/memento_command.h" -#include "pbd/stl_delete.h" - -#include "ardour/automation_list.h" -#include "ardour/dB.h" -#include "ardour/debug.h" -#include "ardour/parameter_types.h" -#include "ardour/tempo.h" - -#include "temporal/range.h" - -#include "evoral/Curve.h" - -#include "canvas/debug.h" - -#include "automation_line_base.h" -#include "control_point.h" -#include "editing_context.h" -#include "gui_thread.h" -#include "rgb_macros.h" -#include "public_editor.h" -#include "selection.h" -#include "time_axis_view.h" -#include "point_selection.h" -#include "automation_time_axis.h" -#include "ui_config.h" - -#include "ardour/event_type_map.h" -#include "ardour/session.h" -#include "ardour/value_as_string.h" - -#include "pbd/i18n.h" - -using namespace std; -using namespace ARDOUR; -using namespace PBD; -using namespace Editing; -using namespace Temporal; - -#define SAMPLES_TO_TIME(x) (get_origin().distance (x)) - -/** @param converter A TimeConverter whose origin_b is the start time of the AutomationList in session samples. - * This will not be deleted by AutomationLine. - */ -AutomationLineBase::AutomationLineBase (const string& name, - EditingContext& ec, - ArdourCanvas::Item& parent, - ArdourCanvas::Rectangle* drag_base, - std::shared_ptr al, - const ParameterDescriptor& desc) - :_name (name) - , _height (0) - , _line_color ("automation line") - , _view_index_offset (0) - , alist (al) - , _visible (Line) - , terminal_points_can_slide (true) - , update_pending (false) - , have_reset_timeout (false) - , no_draw (false) - , _is_boolean (false) - , _editing_context (ec) - , _parent_group (parent) - , _drag_base (drag_base) - , _offset (0) - , _maximum_time (timepos_t::max (al->time_domain())) - , _fill (false) - , _desc (desc) -{ - group = new ArdourCanvas::Container (&parent, ArdourCanvas::Duple(0, 1.5)); - CANVAS_DEBUG_NAME (group, "automation line group"); - - line = new ArdourCanvas::PolyLine (group); - CANVAS_DEBUG_NAME (line, "automation line"); - line->set_data ("line", this); - line->set_data ("drag-base", _drag_base); - line->set_outline_width (2.0); - line->set_covers_threshold (4.0); - - line->Event.connect (sigc::mem_fun (*this, &AutomationLineBase::event_handler)); - - _editing_context.session()->register_with_memento_command_factory(alist->id(), this); - - interpolation_changed (alist->interpolation ()); - - connect_to_list (); -} - -AutomationLineBase::~AutomationLineBase () -{ - delete group; // deletes child items - - for (std::vector::iterator i = control_points.begin(); i != control_points.end(); i++) { - (*i)->unset_item (); - delete *i; - } - control_points.clear (); -} - -timepos_t -AutomationLineBase::get_origin() const -{ - /* this is the default for all non-derived AutomationLine classes: the - origin is zero, in whatever time domain the list we represent uses. - */ - return timepos_t (the_list()->time_domain()); -} - -bool -AutomationLineBase::is_stepped() const -{ - return (_desc.toggled || (alist && alist->interpolation() == AutomationList::Discrete)); -} - -void -AutomationLineBase::update_visibility () -{ - if (_visible & Line) { - /* Only show the line when there are some points, otherwise we may show an out-of-date line - when automation points have been removed (the line will still follow the shape of the - old points). - */ - if (line_points.size() >= 2) { - line->show(); - } else { - line->hide (); - } - - if (_visible & ControlPoints) { - for (auto & cp : control_points) { - cp->show (); - } - } else if (_visible & SelectedControlPoints) { - for (auto & cp : control_points) { - if (cp->selected()) { - cp->show (); - } else { - cp->hide (); - } - } - } else { - for (auto & cp : control_points) { - cp->hide (); - } - } - - } else { - line->hide (); - for (auto & cp : control_points) { - if (_visible & ControlPoints) { - cp->show (); - } else { - cp->hide (); - } - } - } -} - -bool -AutomationLineBase::get_uses_gain_mapping () const -{ - switch (_desc.type) { - case GainAutomation: - case BusSendLevel: - case EnvelopeAutomation: - case TrimAutomation: - case SurroundSendLevel: - case InsertReturnLevel: - return true; - default: - return false; - } -} - -void -AutomationLineBase::hide () -{ - /* leave control points setting unchanged, we are just hiding the - overall line - */ - - set_visibility (AutomationLineBase::VisibleAspects (_visible & ~Line)); -} - -double -AutomationLineBase::control_point_box_size () -{ - float uiscale = UIConfiguration::instance().get_ui_scale(); - uiscale = std::max (1.f, powf (uiscale, 1.71)); - - if (_height > TimeAxisView::preset_height (HeightLarger)) { - return rint (8.0 * uiscale); - } else if (_height > (guint32) TimeAxisView::preset_height (HeightNormal)) { - return rint (6.0 * uiscale); - } - return rint (12.0 * uiscale); -} - -void -AutomationLineBase::set_height (guint32 h) -{ - if (h != _height) { - _height = h; - - double bsz = control_point_box_size(); - - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { - (*i)->set_size (bsz); - } - - if (_fill) { - line->set_fill_y1 (_height); - } else { - line->set_fill_y1 (0); - } - reset (); - } -} - -void -AutomationLineBase::set_line_color (string color_name, std::string color_mod) -{ - _line_color = color_name; - _line_color_mod = color_mod; - - uint32_t color = UIConfiguration::instance().color (color_name); - line->set_outline_color (color); - - Gtkmm2ext::SVAModifier mod = UIConfiguration::instance().modifier (color_mod.empty () ? "automation line fill" : color_mod); - - line->set_fill_color ((color & 0xffffff00) + mod.a() * 255); -} - -uint32_t -AutomationLineBase::get_line_color() const -{ - return UIConfiguration::instance().color (_line_color); -} - -ControlPoint* -AutomationLineBase::nth (uint32_t n) -{ - if (n < control_points.size()) { - return control_points[n]; - } else { - return 0; - } -} - -ControlPoint const * -AutomationLineBase::nth (uint32_t n) const -{ - if (n < control_points.size()) { - return control_points[n]; - } else { - return 0; - } -} - -void -AutomationLineBase::modify_points_y (std::vector const& cps, double y) -{ - /* clamp y-coord appropriately. y is supposed to be a normalized fraction (0.0-1.0), - and needs to be converted to a canvas unit distance. - */ - - y = max (0.0, y); - y = min (1.0, y); - y = _height - (y * _height); - - _editing_context.begin_reversible_command (_("automation event move")); - _editing_context.add_command (new MementoCommand (memento_command_binder(), &get_state(), 0)); - - alist->freeze (); - for (auto const& cp : cps) { - cp->move_to (cp->get_x(), y, ControlPoint::Full); - sync_model_with_view_point (*cp); - } - alist->thaw (); - - for (auto const& cp : cps) { - reset_line_coords (*cp); - } - - if (line_points.size() > 1) { - line->set_steps (line_points, is_stepped()); - } - - update_pending = false; - - _editing_context.add_command (new MementoCommand (memento_command_binder(), 0, &alist->get_state())); - - _editing_context.commit_reversible_command (); - _editing_context.session()->set_dirty (); -} - -void -AutomationLineBase::reset_line_coords (ControlPoint& cp) -{ - if (cp.view_index() < line_points.size()) { - line_points[cp.view_index() + _view_index_offset].x = cp.get_x (); - line_points[cp.view_index() + _view_index_offset].y = cp.get_y (); - } -} - -bool -AutomationLineBase::sync_model_with_view_points (list cp) -{ - update_pending = true; - - bool moved = false; - for (auto const & vp : cp) { - moved = sync_model_with_view_point (*vp) || moved; - } - - return moved; -} - -string -AutomationLineBase::get_verbose_cursor_string (double fraction) const -{ - return fraction_to_string (fraction); -} - -string -AutomationLineBase::get_verbose_cursor_relative_string (double fraction, double delta) const -{ - std::string s = fraction_to_string (fraction); - std::string d = delta_to_string (delta); - return s + " (" + d + ")"; -} - -/** - * @param fraction y fraction - * @return string representation of this value, using dB if appropriate. - */ -string -AutomationLineBase::fraction_to_string (double fraction) const -{ - view_to_model_coord_y (fraction); - return ARDOUR::value_as_string (_desc, fraction); -} - -string -AutomationLineBase::delta_to_string (double delta) const -{ - if (!get_uses_gain_mapping () && _desc.logarithmic) { - return "x " + ARDOUR::value_as_string (_desc, delta); - } else { - return u8"\u0394 " + ARDOUR::value_as_string (_desc, delta); - } -} - -/** - * @param s Value string in the form as returned by fraction_to_string. - * @return Corresponding y fraction. - */ -double -AutomationLineBase::string_to_fraction (string const & s) const -{ - double v; - sscanf (s.c_str(), "%lf", &v); - - switch (_desc.type) { - case GainAutomation: - case BusSendLevel: - case EnvelopeAutomation: - case TrimAutomation: - case SurroundSendLevel: - case InsertReturnLevel: - if (s == "-inf") { /* translation */ - v = 0; - } else { - v = dB_to_coefficient (v); - } - break; - default: - break; - } - return model_to_view_coord_y (v); -} - -/** Start dragging a single point, possibly adding others if the supplied point is selected and there - * are other selected points. - * - * @param cp Point to drag. - * @param x Initial x position (units). - * @param fraction Initial y position (as a fraction of the track height, where 0 is the bottom and 1 the top) - */ -void -AutomationLineBase::start_drag_single (ControlPoint* cp, double x, float fraction) -{ - _editing_context.add_command (new MementoCommand (memento_command_binder(), &get_state(), 0)); - - _drag_points.clear (); - _drag_points.push_back (cp); - - if (cp->selected ()) { - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { - if (*i != cp && (*i)->selected()) { - _drag_points.push_back (*i); - } - } - } - - 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 -AutomationLineBase::start_drag_line (uint32_t i1, uint32_t i2, float fraction) -{ - _editing_context.add_command (new MementoCommand (memento_command_binder (), &get_state(), 0)); - - _drag_points.clear (); - - for (uint32_t i = i1; i <= i2; i++) { - _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 -AutomationLineBase::start_drag_multiple (list cp, float fraction, XMLNode* state) -{ - _editing_context.add_command (new MementoCommand (memento_command_binder(), state, 0)); - - _drag_points = cp; - start_drag_common (0, fraction); -} - -struct ControlPointSorter -{ - bool operator() (ControlPoint const * a, ControlPoint const * b) const { - if (floateq (a->get_x(), b->get_x(), 1)) { - return a->view_index() < b->view_index(); - } - return a->get_x() < b->get_x(); - } -}; - -AutomationLineBase::ContiguousControlPoints::ContiguousControlPoints (AutomationLineBase& al) - : line (al), before_x (timepos_t (line.the_list()->time_domain())), after_x (timepos_t::max (line.the_list()->time_domain())) -{ -} - -void -AutomationLineBase::ContiguousControlPoints::compute_x_bounds () -{ - uint32_t sz = size(); - - if (sz > 0 && sz < line.npoints()) { - const TempoMap::SharedPtr map (TempoMap::use()); - - /* determine the limits on x-axis motion for this - contiguous range of control points - */ - - if (front()->view_index() > 0) { - before_x = (*line.nth (front()->view_index() - 1)->model())->when; - before_x += timepos_t (64); - } - - /* if our last point has a point after it in the line, - we have an "after" bound - */ - - if (back()->view_index() < (line.npoints() - 1)) { - after_x = (*line.nth (back()->view_index() + 1)->model())->when; - after_x.shift_earlier (timepos_t (64)); - } - } -} - -Temporal::timecnt_t -AutomationLineBase::ContiguousControlPoints::clamp_dt (timecnt_t const & dt, timepos_t const & line_limit) -{ - if (empty()) { - return dt; - } - - /* get the maximum distance we can move any of these points along the x-axis - */ - - ControlPoint* reference_point; - - if (dt.magnitude() > 0) { - /* check the last point, since we're moving later in time */ - reference_point = back(); - } else { - /* check the first point, since we're moving earlier in time */ - reference_point = front(); - } - - /* possible position the "reference" point would move to, given dx */ - Temporal::timepos_t possible_pos = (*reference_point->model())->when + dt; // new possible position if we just add the motion - - /* Now clamp that position so that: - * - * - it is not before the origin (zero) - * - it is not beyond the line's own limit (e.g. for region automation) - * - it is not before the preceding point - * - it is not after the following point - */ - - possible_pos = max (possible_pos, Temporal::timepos_t (possible_pos.time_domain())); - possible_pos = min (possible_pos, line_limit); - - possible_pos = max (possible_pos, before_x); // can't move later than following point - possible_pos = min (possible_pos, after_x); // can't move earlier than preceding point - - return (*reference_point->model())->when.distance (possible_pos); -} - -void -AutomationLineBase::ContiguousControlPoints::move (timecnt_t const & dt, double dvalue) -{ - for (auto & cp : *this) { - // compute y-axis delta - double view_y = 1.0 - cp->get_y() / line.height(); - line.view_to_model_coord_y (view_y); - line.apply_delta (view_y, dvalue); - view_y = line.model_to_view_coord_y (view_y); - view_y = (1.0 - view_y) * line.height(); - - cp->move_to (line.dt_to_dx ((*cp->model())->when, dt), view_y, ControlPoint::Full); - line.reset_line_coords (*cp); - } -} - -/** Common parts of starting a drag. - * @param x Starting x position in units, 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 -AutomationLineBase::start_drag_common (double x, float fraction) -{ - _last_drag_fraction = fraction; - _drag_had_movement = false; - did_push = false; - - /* they are probably ordered already, but we have to make sure */ - - _drag_points.sort (ControlPointSorter()); -} - -/** Takes a relative-to-origin position, moves it by dt, and returns a - * relative-to-origin pixel count. - */ -double -AutomationLineBase::dt_to_dx (timepos_t const & pos, timecnt_t const & dt) -{ - /* convert a shift of pos by dt into an absolute timepos */ - timepos_t const new_pos ((pos + dt + get_origin()).shift_earlier (offset())); - /* convert to pixels */ - double px = _editing_context.time_to_pixel_unrounded (new_pos); - /* convert back to pixels-relative-to-origin */ - px -= _editing_context.time_to_pixel_unrounded (get_origin()); - return px; -} - -/** Should be called to indicate motion during a drag. - * @param x New x position of the drag in canvas units relative to origin, or undefined if ignore_x == true. - * @param fraction New y fraction. - * @return x position and y fraction that were actually used (once clamped). - */ -pair -AutomationLineBase::drag_motion (timecnt_t const & pdt, float fraction, bool ignore_x, bool with_push, uint32_t& final_index) -{ - if (_drag_points.empty()) { - return pair (fraction, _desc.is_linear () ? 0 : 1); - } - - timecnt_t dt (pdt); - - if (ignore_x) { - dt = timecnt_t (pdt.time_domain()); - } - - double dy = fraction - _last_drag_fraction; - - if (!_drag_had_movement) { - - /* "first move" ... do some stuff that we don't want to do if - no motion ever took place, but need to do before we handle - motion. - */ - - /* partition the points we are dragging into (potentially several) - * set(s) of contiguous points. this will not happen with a normal - * drag, but if the user does a discontiguous selection, it can. - */ - - uint32_t expected_view_index = 0; - CCP contig; - - for (list::iterator i = _drag_points.begin(); i != _drag_points.end(); ++i) { - if (i == _drag_points.begin() || (*i)->view_index() != expected_view_index) { - contig.reset (new ContiguousControlPoints (*this)); - contiguous_points.push_back (contig); - } - contig->push_back (*i); - expected_view_index = (*i)->view_index() + 1; - } - - if (contiguous_points.back()->empty()) { - contiguous_points.pop_back (); - } - - for (auto const & ccp : contiguous_points) { - ccp->compute_x_bounds (); - } - _drag_had_movement = true; - } - - /* OK, now on to the stuff related to *this* motion event. First, for - * each contiguous range, figure out the maximum x-axis motion we are - * allowed (because of neighbouring points that are not moving. - * - * if we are moving forwards with push, we don't need to do this, - * since all later points will move too. - */ - - if (dt.is_negative() || (dt.is_positive() && !with_push)) { - const timepos_t line_limit = get_origin() + maximum_time() + _offset; - for (auto const & ccp : contiguous_points){ - dt = ccp->clamp_dt (dt, line_limit); - } - } - - /* compute deflection */ - double delta_value; - { - double value0 = _last_drag_fraction; - double value1 = _last_drag_fraction + dy; - view_to_model_coord_y (value0); - view_to_model_coord_y (value1); - delta_value = compute_delta (value0, value1); - } - - /* special case -inf */ - if (delta_value == 0 && dy > 0 && !_desc.is_linear ()) { - assert (_desc.lower == 0); - delta_value = 1.0; - } - - /* clamp y */ - for (list::iterator i = _drag_points.begin(); i != _drag_points.end(); ++i) { - double vy = 1.0 - (*i)->get_y() / _height; - view_to_model_coord_y (vy); - const double orig = vy; - apply_delta (vy, delta_value); - if (vy < _desc.lower) { - delta_value = compute_delta (orig, _desc.lower); - } - if (vy > _desc.upper) { - delta_value = compute_delta (orig, _desc.upper); - } - } - - if (!dt.is_zero() || dy) { - /* and now move each section */ - - - for (vector::iterator ccp = contiguous_points.begin(); ccp != contiguous_points.end(); ++ccp) { - (*ccp)->move (dt, delta_value); - } - - if (with_push) { - final_index = contiguous_points.back()->back()->view_index () + 1; - ControlPoint* p; - uint32_t i = final_index; - - while ((p = nth (i)) != 0 && p->can_slide()) { - - p->move_to (dt_to_dx ((*p->model())->when, dt), p->get_y(), ControlPoint::Full); - reset_line_coords (*p); - ++i; - } - } - - /* update actual line coordinates (will queue a redraw) */ - - if (line_points.size() > 1) { - line->set_steps (line_points, is_stepped()); - } - } - - /* calculate effective delta */ - ControlPoint* cp = _drag_points.front(); - double vy = 1.0 - cp->get_y() / (double)_height; - view_to_model_coord_y (vy); - float val = (*(cp->model ()))->value; - float effective_delta = _desc.compute_delta (val, vy); - /* special case recovery from -inf */ - if (val == 0 && effective_delta == 0 && vy > 0) { - assert (!_desc.is_linear ()); - effective_delta = HUGE_VAL; // +Infinity - } - - double const result_frac = _last_drag_fraction + dy; - _last_drag_fraction = result_frac; - did_push = with_push; - - return pair (result_frac, effective_delta); -} - -/** Should be called to indicate the end of a drag */ -void -AutomationLineBase::end_drag (bool with_push, uint32_t final_index) -{ - if (!_drag_had_movement) { - return; - } - - alist->freeze (); - bool moved = sync_model_with_view_points (_drag_points); - - if (with_push) { - ControlPoint* p; - uint32_t i = final_index; - while ((p = nth (i)) != 0 && p->can_slide()) { - moved = sync_model_with_view_point (*p) || moved; - ++i; - } - } - - alist->thaw (); - - update_pending = false; - - if (moved) { - /* A point has moved as a result of sync (clamped to integer or boolean - value), update line accordingly. */ - line->set_steps (line_points, is_stepped()); - } - - _editing_context.add_command (new MementoCommand(memento_command_binder (), 0, &alist->get_state())); - - _editing_context.session()->set_dirty (); - did_push = false; - - contiguous_points.clear (); -} - -/** - * - * get model coordinates synced with (possibly changed) view coordinates. - * - * For example, we call this in ::end_drag(), when we have probably moved a - * point in the view, and now want to "push" that change back into the - * corresponding model point. - */ -bool -AutomationLineBase::sync_model_with_view_point (ControlPoint& cp) -{ - /* find out where the visual control point is. - * ControlPoint uses canvas-units. The origin - * is the RegionView's top-left corner. - */ - double view_x = cp.get_x(); - - /* model time is relative to the Region (regardless of region->start offset) */ - timepos_t model_time = (*cp.model())->when; - - const timepos_t origin (get_origin()); - - /* convert to absolute time on timeline */ - const timepos_t absolute_time = model_time + origin; - - /* now convert to pixels relative to start of region, which matches view_x */ - const double model_x = _editing_context.time_to_pixel_unrounded (absolute_time) - _editing_context.time_to_pixel_unrounded (origin); - - if (view_x != model_x) { - - /* convert the current position in the view (units: - * region-relative pixels) into samples, then use that to - * create a timecnt_t that measures the distance from the - * origin for this line. - * - * Note that the offset and origin is irrelevant here, - * pixel_to_sample() islinear only depending on zoom level. - */ - - const timepos_t view_samples (_editing_context.pixel_to_sample (view_x)); - - /* measure distance from RegionView origin (this preserves time domain) */ - - if (model_time.time_domain() == Temporal::AudioTime) { - model_time = timepos_t (timecnt_t (view_samples, origin).samples()); - } else { - model_time = timepos_t (timecnt_t (view_samples, origin).beats()); - } - - /* convert RegionView to Region position (account for region->start() _offset) */ - model_time += _offset; - } - - update_pending = true; - - double view_y = 1.0 - cp.get_y() / (double)_height; - view_to_model_coord_y (view_y); - - alist->modify (cp.model(), model_time, view_y); - - /* convert back from model to view y for clamping position (for integer/boolean/etc) */ - view_y = model_to_view_coord_y (view_y); - const double point_y = _height - (view_y * _height); - if (point_y != cp.get_y()) { - cp.move_to (cp.get_x(), point_y, ControlPoint::Full); - reset_line_coords (cp); - return true; - } - - return false; -} - -bool -AutomationLineBase::control_points_adjacent (double xval, uint32_t & before, uint32_t& after) -{ - ControlPoint *bcp = 0; - ControlPoint *acp = 0; - double unit_xval; - - unit_xval = _editing_context.sample_to_pixel_unrounded (xval); - - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { - - if ((*i)->get_x() <= unit_xval) { - - if (!bcp || (*i)->get_x() > bcp->get_x()) { - bcp = *i; - before = bcp->view_index(); - } - - } else if ((*i)->get_x() > unit_xval) { - acp = *i; - after = acp->view_index(); - break; - } - } - - return bcp && acp; -} - -bool -AutomationLineBase::is_last_point (ControlPoint& cp) -{ - // If the list is not empty, and the point is the last point in the list - - if (alist->empty()) { - return false; - } - - AutomationList::const_iterator i = alist->end(); - --i; - - if (cp.model() == i) { - return true; - } - - return false; -} - -bool -AutomationLineBase::is_first_point (ControlPoint& cp) -{ - // If the list is not empty, and the point is the first point in the list - - if (!alist->empty() && cp.model() == alist->begin()) { - return true; - } - - return false; -} - -// This is copied into AudioRegionGainLine -void -AutomationLineBase::remove_point (ControlPoint& cp) -{ - _editing_context.begin_reversible_command (_("remove control point")); - XMLNode &before = alist->get_state(); - - _editing_context.get_selection ().clear_points (); - alist->erase (cp.model()); - - _editing_context.add_command (new MementoCommand (memento_command_binder (), &before, &alist->get_state())); - - _editing_context.commit_reversible_command (); - _editing_context.session()->set_dirty (); -} - -/** Get selectable points within an area. - * @param start Start position in session samples. - * @param end End position in session samples. - * @param bot Bottom y range, as a fraction of line height, where 0 is the bottom of the line. - * @param top Top y range, as a fraction of line height, where 0 is the bottom of the line. - * @param result Filled in with selectable things; in this case, ControlPoints. - */ -void -AutomationLineBase::get_selectables (timepos_t const & start, timepos_t const & end, double botfrac, double topfrac, list& results) -{ - /* convert fractions to display coordinates with 0 at the top of the track */ - double const bot_track = (1 - topfrac) * _height; // this should StreamView::child_height () for RegionGain - double const top_track = (1 - botfrac) * _height; // --"-- - - for (auto const & cp : control_points) { - - const timepos_t w = session_position ((*cp->model())->when); - - if (w >= start && w <= end && cp->get_y() >= bot_track && cp->get_y() <= top_track) { - results.push_back (cp); - } - } -} - -void -AutomationLineBase::get_inverted_selectables (Selection&, list& /*results*/) -{ - // hmmm .... -} - -void -AutomationLineBase::set_selected_points (PointSelection const & points) -{ - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { - (*i)->set_selected (false); - } - - for (PointSelection::const_iterator i = points.begin(); i != points.end(); ++i) { - (*i)->set_selected (true); - } - - if (points.empty()) { - remove_visibility (SelectedControlPoints); - } else { - add_visibility (SelectedControlPoints); - } - - set_colors (); -} - -void -AutomationLineBase::set_colors () -{ - set_line_color (_line_color, _line_color_mod); - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { - (*i)->set_color (); - } -} - -void -AutomationLineBase::list_changed () -{ - DEBUG_TRACE (DEBUG::Automation, string_compose ("\tline changed, existing update pending? %1\n", update_pending)); - - if (!update_pending) { - update_pending = true; - Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&AutomationLineBase::queue_reset, this)); - } -} - -void -AutomationLineBase::tempo_map_changed () -{ - if (alist->time_domain() != Temporal::BeatTime) { - return; - } - - reset (); -} - -void -AutomationLineBase::reset_callback (const Evoral::ControlList& events) -{ - uint32_t vp = 0; - uint32_t pi = 0; - uint32_t np; - - if (events.empty()) { - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { - delete *i; - } - control_points.clear (); - line->hide(); - line_points.clear (); - return; - } - - /* hide all existing points, and the line */ - - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { - (*i)->hide(); - } - - line->hide (); - np = events.size(); - - Evoral::ControlList& e (const_cast (events)); - AutomationList::iterator preceding (e.end()); - AutomationList::iterator following (e.end()); - - for (AutomationList::iterator ai = e.begin(); ai != e.end(); ++ai, ++pi) { - - /* drop points outside our range */ - - if (((*ai)->when < _offset)) { - preceding = ai; - continue; - } - - if ((*ai)->when >= _offset + _maximum_time) { - following = ai; - break; - } - - double ty = model_to_view_coord_y ((*ai)->value); - - if (isnan_local (ty)) { - warning << string_compose (_("Ignoring illegal points on AutomationLine \"%1\""), _name) << endmsg; - continue; - } - - /* convert from canonical view height (0..1.0) to actual - * height coordinates (using X11's top-left rooted system) - */ - - ty = _height - (ty * _height); - - /* tx is currently the distance of this point from - * _offset, which may be either: - * - * a) zero, for an automation line not connected to a - * region - * - * b) some non-zero value, corresponding to the start - * of the region within its source(s). Remember that - * this start is an offset within the source, not a - * position on the timeline. - * - * We need to convert tx to a global position, and to - * do that we need to measure the distance from the - * result of get_origin(), which tells ut the timeline - * position of _offset - */ - - timecnt_t tx = model_to_view_coord_x ((*ai)->when); - - /* convert x-coordinate to a canvas unit coordinate (this takes - * zoom and scroll into account). - */ - - double px = _editing_context.duration_to_pixels_unrounded (tx); - add_visible_control_point (vp, pi, px, ty, ai, np); - vp++; - } - - /* discard extra CP's to avoid confusing ourselves */ - - while (control_points.size() > vp) { - ControlPoint* cp = control_points.back(); - control_points.pop_back (); - delete cp; - } - - if (!terminal_points_can_slide && !control_points.empty()) { - control_points.back()->set_can_slide(false); - } - - if (vp) { - - /* reset the line coordinates given to the CanvasLine */ - - /* 2 extra in case we need hidden points for line start and end */ - - line_points.resize (vp + 2, ArdourCanvas::Duple (0, 0)); - - ArdourCanvas::Points::size_type n = 0; - - /* potentially insert front hidden (line) point to make the line draw from - * zero to the first actual point - */ - - _view_index_offset = 0; - - if (control_points[0]->get_x() != 0 && preceding != e.end()) { - double ty = model_to_view_coord_y (e.unlocked_eval (_offset)); - - if (isnan_local (ty)) { - warning << string_compose (_("Ignoring illegal points on AutomationLine \"%1\""), _name) << endmsg; - - - } else { - line_points[n].y = _height - (ty * _height); - line_points[n].x = 0; - _view_index_offset = 1; - ++n; - } - } - - for (auto const & cp : control_points) { - line_points[n].x = cp->get_x(); - line_points[n].y = cp->get_y(); - ++n; - } - - /* potentially insert final hidden (line) point to make the line draw - * from the last point to the very end - */ - - double px = _editing_context.duration_to_pixels_unrounded (model_to_view_coord_x (_offset + _maximum_time)); - - if (control_points[control_points.size() - 1]->get_x() != px && following != e.end()) { - double ty = model_to_view_coord_y (e.unlocked_eval (_offset + _maximum_time)); - - if (isnan_local (ty)) { - warning << string_compose (_("Ignoring illegal points on AutomationLine \"%1\""), _name) << endmsg; - - - } else { - line_points[n].y = _height - (ty * _height); - line_points[n].x = px; - ++n; - } - } - - line_points.resize (n); - line->set_steps (line_points, is_stepped()); - - update_visibility (); - } - - set_selected_points (_editing_context.get_selection().points); -} - -void -AutomationLineBase::reset () -{ - DEBUG_TRACE (DEBUG::Automation, "\t\tLINE RESET\n"); - update_pending = false; - have_reset_timeout = false; - - if (no_draw) { - return; - } - - /* TODO: abort any drags in progress, e.g. dragging points while writing automation - * (the control-point model, used by AutomationLineBase::drag_motion, will be invalid). - * - * Note: reset() may also be called from an aborted drag (LineDrag::aborted) - * maybe abort in list_changed(), interpolation_changed() and ... ? - * XXX - */ - - alist->apply_to_points (*this, &AutomationLineBase::reset_callback); -} - -void -AutomationLineBase::queue_reset () -{ - /* this must be called from the GUI thread */ - - if (_editing_context.session()->transport_rolling() && alist->automation_write()) { - /* automation write pass ... defer to a timeout */ - /* redraw in 1/4 second */ - if (!have_reset_timeout) { - DEBUG_TRACE (DEBUG::Automation, "\tqueue timeout\n"); - Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &AutomationLineBase::reset), false), 250); - have_reset_timeout = true; - } else { - DEBUG_TRACE (DEBUG::Automation, "\ttimeout already queued, change ignored\n"); - } - } else { - reset (); - } -} - -void -AutomationLineBase::clear () -{ - /* parent must create and commit command */ - XMLNode &before = alist->get_state(); - alist->clear(); - - _editing_context.add_command (new MementoCommand (memento_command_binder (), &before, &alist->get_state())); -} - -void -AutomationLineBase::set_list (std::shared_ptr list) -{ - alist = list; - queue_reset (); - connect_to_list (); -} - -void -AutomationLineBase::add_visibility (VisibleAspects va) -{ - VisibleAspects old = _visible; - - _visible = VisibleAspects (_visible | va); - - if (old != _visible) { - update_visibility (); - } -} - -void -AutomationLineBase::set_visibility (VisibleAspects va) -{ - if (_visible != va) { - _visible = va; - update_visibility (); - } -} - -void -AutomationLineBase::remove_visibility (VisibleAspects va) -{ - VisibleAspects old = _visible; - - _visible = VisibleAspects (_visible & ~va); - - if (old != _visible) { - update_visibility (); - } -} - -void -AutomationLineBase::track_entered() -{ - add_visibility (ControlPoints); -} - -void -AutomationLineBase::track_exited() -{ - remove_visibility (ControlPoints); -} - -XMLNode & -AutomationLineBase::get_state () const -{ - /* function as a proxy for the model */ - return alist->get_state(); -} - -int -AutomationLineBase::set_state (const XMLNode &node, int version) -{ - /* function as a proxy for the model */ - return alist->set_state (node, version); -} - -void -AutomationLineBase::view_to_model_coord_y (double& y) const -{ - if (alist->default_interpolation () != alist->interpolation()) { - switch (alist->interpolation()) { - case AutomationList::Discrete: - /* toggles and MIDI only -- see is_stepped() */ - assert (alist->default_interpolation () == AutomationList::Linear); - break; - case AutomationList::Linear: - y = y * (_desc.upper - _desc.lower) + _desc.lower; - return; - default: - /* types that default to linear, can't be use - * Logarithmic or Exponential interpolation. - * "Curved" is invalid for automation (only x-fads) - */ - assert (0); - break; - } - } - y = _desc.from_interface (y); -} - -double -AutomationLineBase::compute_delta (double from, double to) const -{ - return _desc.compute_delta (from, to); -} - -void -AutomationLineBase::apply_delta (double& val, double delta) const -{ - if (val == 0 && !_desc.is_linear () && delta >= 1.0) { - /* recover from -inf */ - val = 1.0 / _height; - view_to_model_coord_y (val); - return; - } - val = _desc.apply_delta (val, delta); -} - -double -AutomationLineBase::model_to_view_coord_y (double y) const -{ - if (alist->default_interpolation () != alist->interpolation()) { - switch (alist->interpolation()) { - case AutomationList::Discrete: - /* toggles and MIDI only -- see is_stepped */ - assert (alist->default_interpolation () == AutomationList::Linear); - break; - case AutomationList::Linear: - return (y - _desc.lower) / (_desc.upper - _desc.lower); - default: - /* types that default to linear, can't be use - * Logarithmic or Exponential interpolation. - * "Curved" is invalid for automation (only x-fads) - */ - assert (0); - break; - } - } - return _desc.to_interface (y); -} - -timecnt_t -AutomationLineBase::model_to_view_coord_x (timepos_t const & when) const -{ - /* @param when is a distance (with implicit origin) from the start of the - * source. So we subtract the offset (from the region if this is - * related to a region; zero otherwise) to get the distance (again, - * implicit origin) from the start of the line. - * - * Then we construct a timecnt_t from this duration, and the origin of - * the line on the timeline. - */ - - return timecnt_t (when.earlier (_offset), get_origin()); -} - -/** Called when our list has announced that its interpolation style has changed */ -void -AutomationLineBase::interpolation_changed (AutomationList::InterpolationStyle style) -{ - if (line_points.size() > 1) { - reset (); - line->set_steps(line_points, is_stepped()); - } -} - -void -AutomationLineBase::add_visible_control_point (uint32_t view_index, uint32_t pi, double tx, double ty, - AutomationList::iterator model, uint32_t npoints) -{ - ControlPoint::ShapeType shape; - - if (view_index >= control_points.size()) { - - /* make sure we have enough control points */ - - ControlPoint* ncp = new ControlPoint (*this); - ncp->set_size (control_point_box_size ()); - - control_points.push_back (ncp); - } - - if (!terminal_points_can_slide) { - if (pi == 0) { - control_points[view_index]->set_can_slide (false); - if (tx == 0) { - shape = ControlPoint::Start; - } else { - shape = ControlPoint::Full; - } - } else if (pi == npoints - 1) { - control_points[view_index]->set_can_slide (false); - shape = ControlPoint::End; - } else { - control_points[view_index]->set_can_slide (true); - shape = ControlPoint::Full; - } - } else { - control_points[view_index]->set_can_slide (true); - shape = ControlPoint::Full; - } - - control_points[view_index]->reset (tx, ty, model, view_index, shape); - - /* finally, control visibility */ - - if (_visible & ControlPoints) { - control_points[view_index]->show (); - } else { - control_points[view_index]->hide (); - } -} - -void -AutomationLineBase::dump (std::ostream& ostr) const -{ - for (auto const & cp : control_points) { - if (cp->model() != alist->end()) { - ostr << '#' << cp->view_index() << " @ " << cp->get_x() << ", " << cp->get_y() << " for " << (*cp->model())->value << " @ " << (*(cp->model()))->when << std::endl; - } else { - ostr << "dead point\n"; - } - } -} - -void -AutomationLineBase::connect_to_list () -{ - _list_connections.drop_connections (); - - alist->StateChanged.connect (_list_connections, invalidator (*this), boost::bind (&AutomationLineBase::list_changed, this), gui_context()); - - alist->InterpolationChanged.connect ( - _list_connections, invalidator (*this), boost::bind (&AutomationLineBase::interpolation_changed, this, _1), gui_context()); -} - -MementoCommandBinder* -AutomationLineBase::memento_command_binder () -{ - return new SimpleMementoCommandBinder (*alist.get()); -} - -/** Set the maximum time that points on this line can be at, relative - * to the start of the track or region that it is on. - */ -void -AutomationLineBase::set_maximum_time (Temporal::timepos_t const & t) -{ - if (_maximum_time == t) { - return; - } - - _maximum_time = t; - reset (); -} - - -/** @return min and max x positions of points that are in the list, in session samples */ -pair -AutomationLineBase::get_point_x_range () const -{ - pair r (timepos_t::max (the_list()->time_domain()), timepos_t::zero (the_list()->time_domain())); - - for (auto const & cp : *the_list()) { - const timepos_t w (session_position (cp->when)); - r.first = min (r.first, w); - r.second = max (r.second, w); - } - - return r; -} - -timepos_t -AutomationLineBase::session_position (timepos_t const & when) const -{ - return when + get_origin(); -} - -void -AutomationLineBase::set_offset (timepos_t const & off) -{ - _offset = off; - reset (); -} diff --git a/gtk2_ardour/automation_line_base.h b/gtk2_ardour/automation_line_base.h deleted file mode 100644 index 4bbd1671ca..0000000000 --- a/gtk2_ardour/automation_line_base.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 2005-2017 Paul Davis - * Copyright (C) 2005 Karsten Wiese - * Copyright (C) 2005 Nick Mainsbridge - * Copyright (C) 2005 Taybin Rutkin - * Copyright (C) 2006 Hans Fugal - * Copyright (C) 2007-2012 Carl Hetherington - * Copyright (C) 2007-2015 David Robillard - * Copyright (C) 2014-2017 Robin Gareus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef __gtk2_ardour_automation_line_base_h__ -#define __gtk2_ardour_automation_line_base_h__ - -#include -#include -#include -#include - -#include - -#include "pbd/undo.h" -#include "pbd/statefuldestructible.h" -#include "pbd/memento_command.h" - -#include "ardour/automation_list.h" -#include "ardour/parameter_descriptor.h" -#include "ardour/types.h" - -#include "canvas/types.h" -#include "canvas/container.h" -#include "canvas/poly_line.h" - -namespace ArdourCanvas { - class Rectangle; -} - -class AutomationLine; -class ControlPoint; -class PointSelection; -class TimeAxisView; -class AutomationTimeAxisView; -class Selectable; -class Selection; -class EditingContext; - -/** A GUI representation of an ARDOUR::AutomationList */ -class AutomationLineBase : public sigc::trackable, public PBD::StatefulDestructible -{ -public: - enum VisibleAspects { - Line = 0x1, - ControlPoints = 0x2, - SelectedControlPoints = 0x4 - }; - - AutomationLineBase (const std::string& name, - EditingContext& ec, - ArdourCanvas::Item& parent, - ArdourCanvas::Rectangle* drag_base, - std::shared_ptr al, - const ARDOUR::ParameterDescriptor& desc); - - virtual ~AutomationLineBase (); - - virtual Temporal::timepos_t get_origin () const; - - ArdourCanvas::Rectangle* drag_base() const { return _drag_base; } - - void queue_reset (); - void reset (); - void clear (); - void set_fill (bool f) { _fill = f; } // owner needs to call set_height - - void set_selected_points (PointSelection const &); - void get_selectables (Temporal::timepos_t const &, Temporal::timepos_t const &, double, double, std::list&); - void get_inverted_selectables (Selection&, std::list& results); - - virtual void remove_point (ControlPoint&); - bool control_points_adjacent (double xval, uint32_t& before, uint32_t& after); - - /* dragging API */ - virtual void start_drag_single (ControlPoint*, double, float); - virtual void start_drag_line (uint32_t, uint32_t, float); - virtual void start_drag_multiple (std::list, float, XMLNode *); - virtual std::pair drag_motion (Temporal::timecnt_t const &, float, bool, bool with_push, uint32_t& final_index); - virtual void end_drag (bool with_push, uint32_t final_index); - virtual void end_draw_merge () {} - - ControlPoint* nth (uint32_t); - ControlPoint const * nth (uint32_t) const; - uint32_t npoints() const { return control_points.size(); } - - std::string name() const { return _name; } - bool visible() const { return _visible != VisibleAspects(0); } - guint32 height() const { return _height; } - - void set_line_color (std::string color, std::string mod = ""); - uint32_t get_line_color() const; - - void set_visibility (VisibleAspects); - void add_visibility (VisibleAspects); - void remove_visibility (VisibleAspects); - - void hide (); - void set_height (guint32); - - bool get_uses_gain_mapping () const; - void tempo_map_changed (); - - ArdourCanvas::Container& canvas_group() const { return *group; } - ArdourCanvas::Item& parent_group() const { return _parent_group; } - ArdourCanvas::Item& grab_item() const { return *line; } - - virtual std::string get_verbose_cursor_string (double) const; - std::string get_verbose_cursor_relative_string (double, double) const; - std::string fraction_to_string (double) const; - std::string delta_to_string (double) const; - double string_to_fraction (std::string const &) const; - - void view_to_model_coord_y (double &) const; - - double model_to_view_coord_y (double) const; - Temporal::timecnt_t model_to_view_coord_x (Temporal::timepos_t const &) const; - - double compute_delta (double from, double to) const; - void apply_delta (double& val, double delta) const; - - void set_list(std::shared_ptr list); - std::shared_ptr the_list() const { return alist; } - - void track_entered(); - void track_exited(); - - bool is_last_point (ControlPoint &); - bool is_first_point (ControlPoint &); - - XMLNode& get_state () const; - int set_state (const XMLNode&, int version); - void set_colors(); - - void modify_points_y (std::vector const&, double); - - virtual MementoCommandBinder* memento_command_binder (); - - std::pair get_point_x_range () const; - - void set_maximum_time (Temporal::timepos_t const &); - Temporal::timepos_t maximum_time () const { - return _maximum_time; - } - - void set_offset (Temporal::timepos_t const &); - Temporal::timepos_t offset () { return _offset; } - void set_width (Temporal::timecnt_t const &); - - Temporal::timepos_t session_position (Temporal::timepos_t const &) const; - void dump (std::ostream&) const; - - double dt_to_dx (Temporal::timepos_t const &, Temporal::timecnt_t const &); - - ARDOUR::ParameterDescriptor const & param() const { return _desc; } - EditingContext& editing_context() const { return _editing_context; } - -protected: - - std::string _name; - guint32 _height; - std::string _line_color; - std::string _line_color_mod; - uint32_t _view_index_offset; - std::shared_ptr alist; - - VisibleAspects _visible; - - bool terminal_points_can_slide; - bool update_pending; - bool have_reset_timeout; - bool no_draw; - bool _is_boolean; - /** true if we did a push at any point during the current drag */ - bool did_push; - - EditingContext& _editing_context; - ArdourCanvas::Item& _parent_group; - ArdourCanvas::Rectangle* _drag_base; - ArdourCanvas::Container* group; - ArdourCanvas::PolyLine* line; /* line */ - ArdourCanvas::Points line_points; /* coordinates for canvas line */ - std::vector control_points; /* visible control points */ - - class ContiguousControlPoints : public std::list { - public: - ContiguousControlPoints (AutomationLineBase& al); - Temporal::timecnt_t clamp_dt (Temporal::timecnt_t const & dx, Temporal::timepos_t const & region_limit); - void move (Temporal::timecnt_t const &, double dvalue); - void compute_x_bounds (); - private: - AutomationLineBase& line; - Temporal::timepos_t before_x; - Temporal::timepos_t after_x; - }; - - friend class ContiguousControlPoints; - - typedef std::shared_ptr CCP; - std::vector contiguous_points; - - bool sync_model_with_view_point (ControlPoint&); - bool sync_model_with_view_points (std::list); - void start_drag_common (double, float); - - void reset_callback (const Evoral::ControlList&); - void list_changed (); - - virtual bool event_handler (GdkEvent*) = 0; - -private: - std::list _drag_points; ///< points we are dragging - std::list _push_points; ///< additional points we are dragging if "push" is enabled - bool _drag_had_movement; ///< true if the drag has seen movement, otherwise false - double _last_drag_fraction; ///< last y position of the drag, as a fraction - /** offset from the start of the automation list to the start of the line, so that - * a +ve offset means that the 0 on the line is at _offset in the list - */ - Temporal::timepos_t _offset; - - bool is_stepped() const; - void update_visibility (); - 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 (); - void connect_to_list (); - void interpolation_changed (ARDOUR::AutomationList::InterpolationStyle); - - PBD::ScopedConnectionList _list_connections; - - /** maximum time that a point on this line can be at, relative to the position of its region or start of its track */ - Temporal::timepos_t _maximum_time; - - bool _fill; - - const ARDOUR::ParameterDescriptor _desc; - - friend class AudioRegionGainLine; - friend class RegionFxLine; -}; - -#endif /* __gtk2_ardour_automation_line_base_h__ */ - diff --git a/gtk2_ardour/automation_region_view.cc b/gtk2_ardour/automation_region_view.cc index c0223e4df6..edadbb2fd8 100644 --- a/gtk2_ardour/automation_region_view.cc +++ b/gtk2_ardour/automation_region_view.cc @@ -96,14 +96,14 @@ AutomationRegionView::init (bool /*wfd*/) void AutomationRegionView::create_line (std::shared_ptr list) { - _line = std::shared_ptr (new MidiAutomationLine( + _line = std::shared_ptr (new MidiAutomationLine( ARDOUR::EventTypeMap::instance().to_symbol(list->parameter()), trackview, *get_canvas_group(), list, std::dynamic_pointer_cast (_region), _parameter)); _line->set_colors(); _line->set_height ((uint32_t)rint(trackview.current_height() - 2.5 - NAME_HIGHLIGHT_SIZE)); - _line->set_visibility (AutomationLine::VisibleAspects (AutomationLine::Line|AutomationLine::ControlPoints)); + _line->set_visibility (EditorAutomationLine::VisibleAspects (EditorAutomationLine::Line|EditorAutomationLine::ControlPoints)); _line->set_maximum_time (timepos_t (_region->length())); _line->set_offset (_region->start ()); } diff --git a/gtk2_ardour/automation_region_view.h b/gtk2_ardour/automation_region_view.h index 1a2f62c98b..8e3f0d11ce 100644 --- a/gtk2_ardour/automation_region_view.h +++ b/gtk2_ardour/automation_region_view.h @@ -25,7 +25,7 @@ #include "region_view.h" #include "automation_time_axis.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "enums.h" #include "line_merger.h" @@ -61,7 +61,7 @@ public: inline AutomationTimeAxisView* automation_view() const { return dynamic_cast(&trackview); } - std::shared_ptr line() { return _line; } + std::shared_ptr line() { return _line; } // We are a ghost. Meta ghosts? Crazy talk. virtual GhostRegion* add_ghost(TimeAxisView&) { return 0; } @@ -91,7 +91,7 @@ protected: private: Evoral::Parameter _parameter; - std::shared_ptr _line; + std::shared_ptr _line; PBD::ScopedConnection _mouse_mode_connection; }; diff --git a/gtk2_ardour/automation_streamview.cc b/gtk2_ardour/automation_streamview.cc index 3232219a82..2ef475b8a8 100644 --- a/gtk2_ardour/automation_streamview.cc +++ b/gtk2_ardour/automation_streamview.cc @@ -129,7 +129,7 @@ AutomationStreamView::add_region_view_internal (std::shared_ptr region, /* setup automation state for this region */ if (_automation_view.parameter().type() != MidiVelocityAutomation) { - std::shared_ptr line = dynamic_cast(region_view)->line (); + std::shared_ptr line = dynamic_cast(region_view)->line (); if (line && line->the_list()) { line->the_list()->set_automation_state (automation_state ()); } @@ -209,7 +209,7 @@ AutomationStreamView::automation_state () const return _pending_automation_state; } - std::shared_ptr line = ((AutomationRegionView*) region_views.front())->line (); + std::shared_ptr line = ((AutomationRegionView*) region_views.front())->line (); if (!line || !line->the_list()) { return Off; } @@ -289,10 +289,10 @@ AutomationStreamView::set_selected_points (PointSelection& ps) } } -list > +list > AutomationStreamView::get_lines () const { - list > lines; + list > lines; for (auto const & rv : region_views) { AutomationRegionView* arv = dynamic_cast (rv); diff --git a/gtk2_ardour/automation_streamview.h b/gtk2_ardour/automation_streamview.h index 45b5da42ab..e79b56aafe 100644 --- a/gtk2_ardour/automation_streamview.h +++ b/gtk2_ardour/automation_streamview.h @@ -66,7 +66,7 @@ public: void get_selectables (Temporal::timepos_t const &, Temporal::timepos_t const &, double, double, std::list &, bool within = false); void set_selected_points (PointSelection &); - std::list > get_lines () const; + std::list > get_lines () const; bool paste (Temporal::timepos_t const & pos, unsigned paste_count, diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc index 98246c5a70..a33356c38a 100644 --- a/gtk2_ardour/automation_time_axis.cc +++ b/gtk2_ardour/automation_time_axis.cc @@ -60,7 +60,7 @@ #include "gui_thread.h" #include "mergeable_line.h" #include "route_time_axis.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "paste_context.h" #include "public_editor.h" #include "selection.h" @@ -340,8 +340,8 @@ AutomationTimeAxisView::add_contents (bool show_regions) assert (_control); - std::shared_ptr line ( - new AutomationLine ( + std::shared_ptr line ( + new EditorAutomationLine ( ARDOUR::EventTypeMap::instance().to_symbol(_parameter), *this, *_canvas_display, @@ -987,7 +987,7 @@ AutomationTimeAxisView::clear_lines () } void -AutomationTimeAxisView::add_line (std::shared_ptr line) +AutomationTimeAxisView::add_line (std::shared_ptr line) { if (_control && line) { assert(line->the_list() == _control->list()); @@ -1008,7 +1008,7 @@ AutomationTimeAxisView::add_line (std::shared_ptr line) /* pick up the current state */ automation_state_changed (); - line->add_visibility (AutomationLine::Line); + line->add_visibility (EditorAutomationLine::Line); } bool @@ -1084,10 +1084,10 @@ AutomationTimeAxisView::has_automation () const return ( (_line && _line->npoints() > 0) || (_view && _view->has_automation()) ); } -list > +list > AutomationTimeAxisView::lines () const { - list > lines; + list > lines; if (_line) { lines.push_back (_line); @@ -1167,7 +1167,7 @@ AutomationTimeAxisView::parse_state_id ( void AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) { - list > lines; + list > lines; if (_line) { cut_copy_clear_one (*_line, selection, op); @@ -1179,7 +1179,7 @@ AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) } void -AutomationTimeAxisView::cut_copy_clear_one (AutomationLineBase& line, Selection& selection, CutCopyOp op) +AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op) { std::shared_ptr what_we_got; std::shared_ptr alist (line.the_list()); diff --git a/gtk2_ardour/automation_time_axis.h b/gtk2_ardour/automation_time_axis.h index 077d10e4bf..4000bbc0ed 100644 --- a/gtk2_ardour/automation_time_axis.h +++ b/gtk2_ardour/automation_time_axis.h @@ -54,8 +54,8 @@ class PublicEditor; class TimeSelection; class RegionSelection; class PointSelection; -class AutomationLineBase; class AutomationLine; +class EditorAutomationLine; class Selection; class Selectable; class AutomationStreamView; @@ -92,11 +92,11 @@ public: void clear_lines (); - /** @return Our AutomationLine, if this view has one, or 0 if it uses AutomationRegionViews */ - std::shared_ptr line() { return _line; } + /** @return Our EditorAutomationLine, if this view has one, or 0 if it uses AutomationRegionViews */ + std::shared_ptr line() { return _line; } - /** @return All AutomationLines associated with this view */ - std::list > lines () const; + /** @return All EditorAutomationLines associated with this view */ + std::list > lines () const; AutomationStreamView* automation_view() const { return _view; } @@ -167,7 +167,7 @@ protected: Evoral::Parameter _parameter; ArdourCanvas::Rectangle* _base_rect; - std::shared_ptr _line; + std::shared_ptr _line; std::string _name; @@ -194,7 +194,7 @@ protected: bool _show_regions; - void add_line (std::shared_ptr); + void add_line (std::shared_ptr); void clear_clicked (); void hide_clicked (); @@ -203,7 +203,7 @@ protected: void build_display_menu (); - void cut_copy_clear_one (AutomationLineBase&, Selection&, Editing::CutCopyOp); + void cut_copy_clear_one (AutomationLine&, Selection&, Editing::CutCopyOp); bool paste_one (Temporal::timepos_t const &, unsigned, float times, const Selection&, ItemCounts& counts, bool greedy=false); void route_going_away (); diff --git a/gtk2_ardour/control_point.cc b/gtk2_ardour/control_point.cc index 3c6a173779..26e0ea56cf 100644 --- a/gtk2_ardour/control_point.cc +++ b/gtk2_ardour/control_point.cc @@ -19,7 +19,7 @@ */ #include "control_point.h" -#include "automation_line_base.h" +#include "automation_line.h" #include "public_editor.h" #include "ui_config.h" @@ -33,7 +33,7 @@ using namespace PBD; PBD::Signal1 ControlPoint::CatchDeletion; -ControlPoint::ControlPoint (AutomationLineBase& al) +ControlPoint::ControlPoint (AutomationLine& al) : _line (al) { _model = al.the_list()->end(); diff --git a/gtk2_ardour/control_point.h b/gtk2_ardour/control_point.h index 98cb6bc7bc..fa6f7920de 100644 --- a/gtk2_ardour/control_point.h +++ b/gtk2_ardour/control_point.h @@ -29,7 +29,7 @@ #include "selectable.h" -class AutomationLineBase; +class AutomationLine; class ControlPoint; class PointSelection; class TimeAxisView; @@ -46,7 +46,7 @@ namespace ArdourCanvas { class ControlPoint : public Selectable { public: - ControlPoint (AutomationLineBase& al); + ControlPoint (AutomationLine& al); ControlPoint (const ControlPoint&, bool dummy_arg_to_force_special_copy_constructor); virtual ~ControlPoint (); @@ -80,17 +80,17 @@ public: ArdourCanvas::Item& item() const; - /* used from ~AutomationLine */ + /* used from ~EditorAutomationLine */ void unset_item () { _item = 0 ; } ARDOUR::AutomationList::iterator model() const { return _model; } - AutomationLineBase& line() const { return _line; } + AutomationLine& line() const { return _line; } static PBD::Signal1 CatchDeletion; private: ArdourCanvas::Rectangle * _item; - AutomationLineBase& _line; + AutomationLine& _line; ARDOUR::AutomationList::iterator _model; uint32_t _view_index; bool _can_slide; diff --git a/gtk2_ardour/control_point_dialog.cc b/gtk2_ardour/control_point_dialog.cc index 97f463b504..ac82cfd076 100644 --- a/gtk2_ardour/control_point_dialog.cc +++ b/gtk2_ardour/control_point_dialog.cc @@ -21,7 +21,7 @@ #include "gtkmm2ext/gtk_ui.h" -#include "automation_line_base.h" +#include "automation_line.h" #include "control_point.h" #include "control_point_dialog.h" diff --git a/gtk2_ardour/editing_context.cc b/gtk2_ardour/editing_context.cc index cccdd5af71..2f47657934 100644 --- a/gtk2_ardour/editing_context.cc +++ b/gtk2_ardour/editing_context.cc @@ -34,7 +34,7 @@ #include "actions.h" #include "ardour_ui.h" -#include "automation_line_base.h" +#include "automation_line.h" #include "control_point.h" #include "edit_note_dialog.h" #include "editing_context.h" @@ -2656,7 +2656,7 @@ EditingContext::get_draw_length_as_beats (bool& success, timepos_t const & posit void EditingContext::select_automation_line (GdkEventButton* event, ArdourCanvas::Item* item, ARDOUR::SelectionOperation op) { - AutomationLineBase* al = reinterpret_cast (item->get_data ("line")); + AutomationLine* al = reinterpret_cast (item->get_data ("line")); std::list selectables; double mx = event->x; double my = event->y; diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index cf0b56e978..697853eb22 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -109,7 +109,7 @@ class AudioClock; class AudioRegionView; class AudioStreamView; class AudioTimeAxisView; -class AutomationLine; +class EditorAutomationLine; class AutomationSelection; class AutomationTimeAxisView; class BundleManager; @@ -1494,7 +1494,7 @@ private: bool canvas_control_point_event (GdkEvent* event,ArdourCanvas::Item*, ControlPoint*); bool canvas_velocity_event (GdkEvent* event,ArdourCanvas::Item*); bool canvas_velocity_base_event (GdkEvent* event,ArdourCanvas::Item*); - bool canvas_line_event (GdkEvent* event,ArdourCanvas::Item*, AutomationLine*); + bool canvas_line_event (GdkEvent* event,ArdourCanvas::Item*, EditorAutomationLine*); bool canvas_selection_rect_event (GdkEvent* event,ArdourCanvas::Item*, SelectionRect*); bool canvas_selection_start_trim_event (GdkEvent* event,ArdourCanvas::Item*, SelectionRect*); bool canvas_selection_end_trim_event (GdkEvent* event,ArdourCanvas::Item*, SelectionRect*); diff --git a/gtk2_ardour/editor_automation_line.cc b/gtk2_ardour/editor_automation_line.cc new file mode 100644 index 0000000000..a6025c8cd9 --- /dev/null +++ b/gtk2_ardour/editor_automation_line.cc @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2005-2017 Paul Davis + * Copyright (C) 2005 Karsten Wiese + * Copyright (C) 2005 Taybin Rutkin + * Copyright (C) 2006 Hans Fugal + * Copyright (C) 2007-2012 Carl Hetherington + * Copyright (C) 2007-2015 David Robillard + * Copyright (C) 2007 Doug McLain + * Copyright (C) 2013-2017 Robin Gareus + * Copyright (C) 2014-2016 Nick Mainsbridge + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "editor_automation_line.h" +#include "public_editor.h" +#include "time_axis_view.h" + +using namespace std; +using namespace ARDOUR; + +/** @param converter A TimeConverter whose origin_b is the start time of the AutomationList in session samples. + * This will not be deleted by EditorAutomationLine. + */ +EditorAutomationLine::EditorAutomationLine (const string& name, + TimeAxisView& tv, + ArdourCanvas::Item& parent, + std::shared_ptr al, + const ParameterDescriptor& desc) + : AutomationLine (name, tv.editor(), parent, nullptr, al, desc) + , trackview (tv) +{ + line->set_data ("trackview", &trackview); +} + +EditorAutomationLine::~EditorAutomationLine () +{ +} + +bool +EditorAutomationLine::event_handler (GdkEvent* event) +{ + return trackview.editor().canvas_line_event (event, line, this); +} diff --git a/gtk2_ardour/editor_automation_line.h b/gtk2_ardour/editor_automation_line.h new file mode 100644 index 0000000000..ad384aa4e7 --- /dev/null +++ b/gtk2_ardour/editor_automation_line.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2005-2017 Paul Davis + * Copyright (C) 2005 Karsten Wiese + * Copyright (C) 2005 Nick Mainsbridge + * Copyright (C) 2005 Taybin Rutkin + * Copyright (C) 2006 Hans Fugal + * Copyright (C) 2007-2012 Carl Hetherington + * Copyright (C) 2007-2015 David Robillard + * Copyright (C) 2014-2017 Robin Gareus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __ardour_automation_line_h__ +#define __ardour_automation_line_h__ + +#include +#include +#include +#include + +#include + +#include "pbd/undo.h" +#include "pbd/statefuldestructible.h" +#include "pbd/memento_command.h" + +#include "ardour/automation_list.h" +#include "ardour/parameter_descriptor.h" +#include "ardour/types.h" + +#include "canvas/types.h" +#include "canvas/container.h" +#include "canvas/poly_line.h" + +#include "automation_line.h" + +class AutomationLine; +class ControlPoint; +class PointSelection; +class TimeAxisView; +class AutomationTimeAxisView; +class Selectable; +class Selection; +class PublicEditor; + + +/** A GUI representation of an ARDOUR::AutomationList within the main editor + * (i.e. in a TimeAxisView + */ + +class EditorAutomationLine : public AutomationLine +{ +public: + EditorAutomationLine (const std::string& name, + TimeAxisView& tv, + ArdourCanvas::Item& parent, + std::shared_ptr al, + const ARDOUR::ParameterDescriptor& desc); + + + virtual ~EditorAutomationLine (); + + TimeAxisView& trackview; + + protected: + virtual bool event_handler (GdkEvent*); +}; + +#endif /* __ardour_automation_line_h__ */ + diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc index dad5267474..10214a1b07 100644 --- a/gtk2_ardour/editor_canvas.cc +++ b/gtk2_ardour/editor_canvas.cc @@ -1262,7 +1262,7 @@ Editor::which_canvas_cursor(ItemType type) const case GainLineItem: cursor = _cursors->cross_hair; break; - case AutomationLineItem: + case EditorAutomationLineItem: cursor = _cursors->cross_hair; break; case StartSelectionTrimItem: @@ -1431,7 +1431,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ } break; - case AutomationLineItem: + case EditorAutomationLineItem: if (mouse_mode == MouseDraw || mouse_mode == MouseObject) { ArdourCanvas::Line *line = dynamic_cast (item); if (line) { @@ -1523,7 +1523,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ switch (item_type) { case GainLineItem: - case AutomationLineItem: + case EditorAutomationLineItem: case ControlPointItem: /* these do not affect the current entered track state */ clear_entered_track = false; @@ -1544,7 +1544,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ bool Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) { - AutomationLine* al; + EditorAutomationLine* al; ArdourMarker *marker; TempoMarker *t_marker; MeterMarker *m_marker; @@ -1563,8 +1563,8 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) break; case GainLineItem: - case AutomationLineItem: - al = reinterpret_cast (item->get_data ("line")); + case EditorAutomationLineItem: + al = reinterpret_cast (item->get_data ("line")); { ArdourCanvas::Line *line = dynamic_cast (item); if (line) { diff --git a/gtk2_ardour/editor_canvas_events.cc b/gtk2_ardour/editor_canvas_events.cc index 033c048e36..82be775b44 100644 --- a/gtk2_ardour/editor_canvas_events.cc +++ b/gtk2_ardour/editor_canvas_events.cc @@ -47,9 +47,9 @@ #include "audio_streamview.h" #include "audio_time_axis.h" #include "region_gain_line.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "automation_time_axis.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "control_point.h" #include "editor_drag.h" #include "midi_time_axis.h" @@ -636,7 +636,7 @@ Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, C case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: clicked_control_point = cp; - clicked_axisview = &dynamic_cast (&cp->line())->trackview; + clicked_axisview = &dynamic_cast (&cp->line())->trackview; clicked_routeview = dynamic_cast(clicked_axisview); clicked_regionview = 0; break; @@ -660,7 +660,7 @@ Editor::canvas_velocity_base_event (GdkEvent *event, ArdourCanvas::Item* item) } bool -Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al) +Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, EditorAutomationLine* al) { ItemType type; RegionFxLine* rfl; @@ -670,7 +670,7 @@ Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, Automation clicked_regionview = &rfl->region_view (); } } else { - type = AutomationLineItem; + type = EditorAutomationLineItem; if (event->type == GDK_BUTTON_PRESS) { clicked_regionview = 0; } diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 741486f600..b7e8148e45 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -4935,7 +4935,7 @@ ControlPointDrag::active (Editing::MouseMode m) } /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */ - return dynamic_cast (&(_point->line ())) != 0; + return dynamic_cast (&(_point->line ())) != 0; } LineDrag::LineDrag (Editor& e, ArdourCanvas::Item* i) @@ -4962,7 +4962,7 @@ LineDrag::~LineDrag () void LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) { - _line = reinterpret_cast (_item->get_data ("line")); + _line = reinterpret_cast (_item->get_data ("line")); assert (_line); _item = &_line->grab_item (); @@ -6399,7 +6399,7 @@ AutomationRangeDrag::AutomationRangeDrag (EditingContext& ec, list { DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n"); - list> lines; + list> lines; for (list::const_iterator i = v.begin (); i != v.end (); ++i) { if (AudioRegionView* audio_view = dynamic_cast (*i)) { @@ -6414,16 +6414,16 @@ AutomationRangeDrag::AutomationRangeDrag (EditingContext& ec, list setup (lines); } -/** @param lines AutomationLines to drag. - * @param offset Offset from the session start to the points in the AutomationLines. +/** @param lines EditorAutomationLines to drag. + * @param offset Offset from the session start to the points in the EditorAutomationLines. */ void -AutomationRangeDrag::setup (list> const& lines) +AutomationRangeDrag::setup (list> const& lines) { /* find the lines that overlap the ranges being dragged */ - list>::const_iterator i = lines.begin (); + list>::const_iterator i = lines.begin (); while (i != lines.end ()) { - list>::const_iterator j = i; + list>::const_iterator j = i; ++j; pair r = (*i)->get_point_x_range (); @@ -6458,7 +6458,7 @@ AutomationRangeDrag::setup (list> const& lin i = j; } - /* Now ::lines contains the AutomationLines that somehow overlap our drag */ + /* Now ::lines contains the EditorAutomationLines that somehow overlap our drag */ } double @@ -7306,7 +7306,7 @@ FreehandLineDrag::motion (GdkEvent* ev, bool firs dragging_line = new ArdourCanvas::PolyLine (parent ? parent : item()); dragging_line->set_ignore_events (true); dragging_line->set_outline_width (2.0); - dragging_line->set_outline_color (UIConfiguration::instance().color ("automation line")); // XXX -> get color from AutomationLine + dragging_line->set_outline_color (UIConfiguration::instance().color ("automation line")); // XXX -> get color from EditorAutomationLine dragging_line->raise_to_top (); /* for freehand drawing, we only support left->right direction, for now. */ diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index d5dac0dd4e..34a6060493 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -84,7 +84,7 @@ class TempoMarker; class TempoCurve; class ControlPoint; class AudioRegionView; -class AutomationLineBase; +class AutomationLine; class AutomationTimeAxisView; class VelocityDisplay; @@ -1250,7 +1250,7 @@ public: private: - AutomationLineBase* _line; + AutomationLine* _line; double _fixed_grab_x; double _fixed_grab_y; double _cumulative_y_drag; @@ -1487,7 +1487,7 @@ public: } private: - void setup (std::list > const &); + void setup (std::list > const &); double y_fraction (double global_y_position) const; double value (std::shared_ptr list, Temporal::timepos_t const & x) const; @@ -1495,7 +1495,7 @@ private: /** A line that is part of the drag */ struct Line { - std::shared_ptr line; ///< the line + std::shared_ptr line; ///< the line std::list points; ///< points to drag on the line std::pair range; ///< the range of all points on the line, in session time XMLNode* state; ///< the XML state node before the drag diff --git a/gtk2_ardour/editor_items.h b/gtk2_ardour/editor_items.h index 81d90d7764..bf3fc2f83a 100644 --- a/gtk2_ardour/editor_items.h +++ b/gtk2_ardour/editor_items.h @@ -35,7 +35,7 @@ enum ItemType { SelectionItem, ControlPointItem, GainLineItem, - AutomationLineItem, + EditorAutomationLineItem, MeterMarkerItem, BBTMarkerItem, TempoCurveItem, diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index fad1463cc4..def211c310 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -516,7 +516,7 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it case GainLineItem: if (eff_mouse_mode != MouseRange) { - AutomationLine* argl = reinterpret_cast (item->get_data ("line")); + EditorAutomationLine* argl = reinterpret_cast (item->get_data ("line")); std::list selectables; uint32_t before, after; @@ -559,7 +559,7 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it } break; - case AutomationLineItem: + case EditorAutomationLineItem: if (eff_mouse_mode != MouseRange && eff_mouse_mode != MouseDraw) { select_automation_line (&event->button, item, op); } @@ -857,7 +857,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT return true; break; - case AutomationLineItem: + case EditorAutomationLineItem: _drags->set (new LineDrag (*this, item), event); return true; break; @@ -998,7 +998,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT return true; break; - case AutomationLineItem: + case EditorAutomationLineItem: _drags->set (new LineDrag (*this, item), event); return true; break; @@ -1158,7 +1158,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; } - case AutomationLineItem: + case EditorAutomationLineItem: /* fallthrough */ case AutomationTrackItem: { @@ -1640,7 +1640,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case PlayheadCursorItem: case MarkerItem: case GainLineItem: - case AutomationLineItem: + case EditorAutomationLineItem: case StartSelectionTrimItem: case EndSelectionTrimItem: case SelectionMarkerItem: @@ -1918,7 +1918,7 @@ Editor::can_remove_control_point (ArdourCanvas::Item* item) abort(); /*NOTREACHED*/ } - AutomationLineBase& line (control_point->line()); + AutomationLine& line (control_point->line()); if (dynamic_cast (&line)) { /* we shouldn't remove the first or last gain point in region gain lines */ if (line.is_last_point(*control_point) || line.is_first_point(*control_point)) { diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 53fb4fade5..be1dae137f 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -89,7 +89,7 @@ #include "audio_region_view.h" #include "audio_streamview.h" #include "audio_time_axis.h" -#include "automation_line_base.h" +#include "automation_line.h" #include "automation_time_axis.h" #include "control_point.h" #include "debug.h" @@ -4817,10 +4817,10 @@ Editor::cut_copy (CutCopyOp op) struct AutomationRecord { AutomationRecord () : state (0) , line (nullptr) {} - AutomationRecord (XMLNode* s, const AutomationLineBase* l) : state (s) , line (l) {} + AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {} XMLNode* state; ///< state before any operation - const AutomationLineBase* line; ///< line this came from + const AutomationLine* line; ///< line this came from std::shared_ptr copy; ///< copied events for the cut buffer }; @@ -4843,7 +4843,7 @@ Editor::cut_copy_points (Editing::CutCopyOp op, timepos_t const & earliest_time) timepos_t earliest (earliest_time); /* XXX: not ideal, as there may be more than one track involved in the point selection */ - AutomationLine* line = dynamic_cast (&selection->points.front()->line()); + EditorAutomationLine* line = dynamic_cast (&selection->points.front()->line()); assert (line); _last_cut_copy_source_track = &line->trackview; @@ -4856,7 +4856,7 @@ Editor::cut_copy_points (Editing::CutCopyOp op, timepos_t const & earliest_time) /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */ for (auto & selected_point : selection->points) { - const AutomationLineBase& line (selected_point->line()); + const AutomationLine& line (selected_point->line()); const std::shared_ptr al = line.the_list(); if (lists.find (al) == lists.end ()) { /* We haven't seen this list yet, so make a record for it. This includes @@ -4909,7 +4909,7 @@ Editor::cut_copy_points (Editing::CutCopyOp op, timepos_t const & earliest_time) /* Remove each selected point from its AutomationList */ for (auto & selected_point : selection->points) { - AutomationLineBase& line (selected_point->line ()); + AutomationLine& line (selected_point->line ()); std::shared_ptr al = line.the_list(); bool erase = true; diff --git a/gtk2_ardour/editor_selection.cc b/gtk2_ardour/editor_selection.cc index afb731c2c1..c6ee337fe8 100644 --- a/gtk2_ardour/editor_selection.cc +++ b/gtk2_ardour/editor_selection.cc @@ -45,7 +45,7 @@ #include "audio_time_axis.h" #include "audio_region_view.h" #include "audio_streamview.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "control_point.h" #include "editor_regions.h" #include "editor_cursors.h" diff --git a/gtk2_ardour/enums.cc b/gtk2_ardour/enums.cc index fd63d5160b..a168369671 100644 --- a/gtk2_ardour/enums.cc +++ b/gtk2_ardour/enums.cc @@ -160,7 +160,7 @@ setup_gtk_ardour_enums () REGISTER_ENUM (SelectionItem); REGISTER_ENUM (ControlPointItem); REGISTER_ENUM (GainLineItem); - REGISTER_ENUM (AutomationLineItem); + REGISTER_ENUM (EditorAutomationLineItem); REGISTER_ENUM (MeterMarkerItem); REGISTER_ENUM (TempoCurveItem); REGISTER_ENUM (TempoMarkerItem); diff --git a/gtk2_ardour/mergeable_line.cc b/gtk2_ardour/mergeable_line.cc index 442c72edfe..b19dbcfb72 100644 --- a/gtk2_ardour/mergeable_line.cc +++ b/gtk2_ardour/mergeable_line.cc @@ -20,7 +20,7 @@ #include "ardour/session.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "editing_context.h" #include "mergeable_line.h" #include "route_time_axis.h" diff --git a/gtk2_ardour/mergeable_line.h b/gtk2_ardour/mergeable_line.h index 04806eb6cc..cf875cd1b6 100644 --- a/gtk2_ardour/mergeable_line.h +++ b/gtk2_ardour/mergeable_line.h @@ -26,7 +26,7 @@ #include "ardour/types.h" -class AutomationLine; +class EditorAutomationLine; class RouteTimeAxisView; class EditingContext; @@ -38,7 +38,7 @@ class AutomationControl; class MergeableLine { public: - MergeableLine (std::shared_ptr l, std::shared_ptr c, + MergeableLine (std::shared_ptr l, std::shared_ptr c, std::function tf, std::function asc, std::function ctc) @@ -53,7 +53,7 @@ class MergeableLine void merge_drawn_line (EditingContext& e, ARDOUR::Session& s, Evoral::ControlList::OrderedPoints& points, bool thin); private: - std::shared_ptr _line; + std::shared_ptr _line; std::shared_ptr _control; std::function time_filter; std::function automation_state_callback; diff --git a/gtk2_ardour/midi_automation_line.cc b/gtk2_ardour/midi_automation_line.cc index 7fc0ed41cd..5b622a1096 100644 --- a/gtk2_ardour/midi_automation_line.cc +++ b/gtk2_ardour/midi_automation_line.cc @@ -38,7 +38,7 @@ MidiAutomationLine::MidiAutomationLine ( std::shared_ptr list, std::shared_ptr region, Evoral::Parameter parameter) - : AutomationLine (name, tav, parent, list, parameter) + : EditorAutomationLine (name, tav, parent, list, parameter) , _region (region) , _parameter (parameter) { @@ -72,26 +72,26 @@ MidiAutomationLine::get_verbose_cursor_string (double fraction) const using namespace MIDI::Name; if (_parameter.type() != ARDOUR::MidiCCAutomation) { - return AutomationLine::get_verbose_cursor_string(fraction); + return EditorAutomationLine::get_verbose_cursor_string(fraction); } MidiTimeAxisView* const mtv = dynamic_cast(trackview.get_parent()); if (!mtv) { - return AutomationLine::get_verbose_cursor_string(fraction); + return EditorAutomationLine::get_verbose_cursor_string(fraction); } const uint8_t channel = mtv->get_preferred_midi_channel(); std::shared_ptr value_names = mtv->route()->instrument_info().value_name_list_by_control (channel, _parameter.id()); if (!value_names) { - return AutomationLine::get_verbose_cursor_string(fraction); + return EditorAutomationLine::get_verbose_cursor_string(fraction); } const uint16_t cc_value = floor(std::max(std::min(fraction * 127.0, 127.0), 0.0)); std::shared_ptr value = value_names->max_value_below(cc_value); if (!value) { - return AutomationLine::get_verbose_cursor_string(fraction); + return EditorAutomationLine::get_verbose_cursor_string(fraction); } return value->name(); diff --git a/gtk2_ardour/midi_automation_line.h b/gtk2_ardour/midi_automation_line.h index 3e7fc664b1..a22ad7d50d 100644 --- a/gtk2_ardour/midi_automation_line.h +++ b/gtk2_ardour/midi_automation_line.h @@ -18,7 +18,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "automation_line.h" +#include "editor_automation_line.h" namespace ARDOUR { class MidiRegion; @@ -27,7 +27,7 @@ namespace ARDOUR { /** Stub class so that lines for MIDI AutomationRegionViews can use the correct * MementoCommandBinder. */ -class MidiAutomationLine : public AutomationLine +class MidiAutomationLine : public EditorAutomationLine { public: MidiAutomationLine (const std::string&, TimeAxisView&, ArdourCanvas::Item&, diff --git a/gtk2_ardour/midi_clip_editor.cc b/gtk2_ardour/midi_clip_editor.cc index e0b0c54ee7..b2ee93dd1f 100644 --- a/gtk2_ardour/midi_clip_editor.cc +++ b/gtk2_ardour/midi_clip_editor.cc @@ -35,7 +35,7 @@ #include "widgets/ardour_button.h" #include "audio_clock.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "control_point.h" #include "editor.h" #include "midi_cue_editor.h" diff --git a/gtk2_ardour/midi_cue_automation_line.cc b/gtk2_ardour/midi_cue_automation_line.cc index 1f9b0fc909..9856804823 100644 --- a/gtk2_ardour/midi_cue_automation_line.cc +++ b/gtk2_ardour/midi_cue_automation_line.cc @@ -29,7 +29,7 @@ MidiCueAutomationLine::MidiCueAutomationLine (const std::string& ArdourCanvas::Rectangle* drag_base, std::shared_ptr al, const ARDOUR::ParameterDescriptor& desc) -: AutomationLineBase (name, ec, parent, drag_base, al, desc) +: AutomationLine (name, ec, parent, drag_base, al, desc) { _drag_base->set_data ("line", this); _drag_base->Event.connect (sigc::mem_fun (*this, &MidiCueAutomationLine::base_event_handler)); @@ -44,5 +44,5 @@ MidiCueAutomationLine::base_event_handler (GdkEvent* ev) bool MidiCueAutomationLine::event_handler (GdkEvent* ev) { - return _editing_context.typed_event (line, ev, AutomationLineItem); + return _editing_context.typed_event (line, ev, EditorAutomationLineItem); } diff --git a/gtk2_ardour/midi_cue_automation_line.h b/gtk2_ardour/midi_cue_automation_line.h index 4b8902d4cf..c079ff66f1 100644 --- a/gtk2_ardour/midi_cue_automation_line.h +++ b/gtk2_ardour/midi_cue_automation_line.h @@ -19,9 +19,9 @@ #ifndef __gtk2_ardour_midi_cue_automation_line_h__ #define __gtk2_ardour_midi_cue_automation_line_h__ -#include "automation_line_base.h" +#include "automation_line.h" -class MidiCueAutomationLine : public AutomationLineBase +class MidiCueAutomationLine : public AutomationLine { public: MidiCueAutomationLine (const std::string& name, diff --git a/gtk2_ardour/midi_cue_editor.cc b/gtk2_ardour/midi_cue_editor.cc index b0d371a77c..6fb0f1b365 100644 --- a/gtk2_ardour/midi_cue_editor.cc +++ b/gtk2_ardour/midi_cue_editor.cc @@ -544,7 +544,7 @@ MidiCueEditor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event return true; break; - case AutomationLineItem: { + case EditorAutomationLineItem: { ARDOUR::SelectionOperation op = ArdourKeyboard::selection_type (event->button.state); select_automation_line (&event->button, item, op); return true; @@ -1525,7 +1525,7 @@ MidiCueEditor::which_canvas_cursor (ItemType type) const case GainLineItem: cursor = _cursors->cross_hair; break; - case AutomationLineItem: + case EditorAutomationLineItem: cursor = _cursors->cross_hair; break; case StartSelectionTrimItem: @@ -1566,18 +1566,18 @@ MidiCueEditor::which_canvas_cursor (ItemType type) const bool MidiCueEditor::enter_handler (ArdourCanvas::Item* item, GdkEvent* ev, ItemType item_type) { - AutomationLine* al; + EditorAutomationLine* al; choose_canvas_cursor_on_entry (item_type); switch (item_type) { case AutomationTrackItem: /* item is the base rectangle */ - al = reinterpret_cast (item->get_data ("line")); + al = reinterpret_cast (item->get_data ("line")); al->track_entered (); break; - case AutomationLineItem: + case EditorAutomationLineItem: { ArdourCanvas::Line *line = dynamic_cast (item); @@ -1596,7 +1596,7 @@ MidiCueEditor::enter_handler (ArdourCanvas::Item* item, GdkEvent* ev, ItemType i bool MidiCueEditor::leave_handler (ArdourCanvas::Item* item, GdkEvent* ev, ItemType item_type) { - AutomationLine* al; + EditorAutomationLine* al; if (!_enter_stack.empty()) { _enter_stack.pop_back(); @@ -1607,8 +1607,8 @@ MidiCueEditor::leave_handler (ArdourCanvas::Item* item, GdkEvent* ev, ItemType i _verbose_cursor->hide (); break; - case AutomationLineItem: - al = reinterpret_cast (item->get_data ("line")); + case EditorAutomationLineItem: + al = reinterpret_cast (item->get_data ("line")); { ArdourCanvas::Line *line = dynamic_cast (item); if (line) { diff --git a/gtk2_ardour/midi_region_operations_box.cc b/gtk2_ardour/midi_region_operations_box.cc index eaaa517426..2005c9ac87 100644 --- a/gtk2_ardour/midi_region_operations_box.cc +++ b/gtk2_ardour/midi_region_operations_box.cc @@ -29,7 +29,7 @@ #include "ardour/session.h" #include "audio_clock.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "control_point.h" #include "editor.h" #include "region_view.h" diff --git a/gtk2_ardour/midi_region_properties_box.cc b/gtk2_ardour/midi_region_properties_box.cc index 353e9b8e6f..5cfec3451b 100644 --- a/gtk2_ardour/midi_region_properties_box.cc +++ b/gtk2_ardour/midi_region_properties_box.cc @@ -31,7 +31,7 @@ #include "widgets/ardour_button.h" #include "audio_clock.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "control_point.h" #include "editor.h" #include "region_view.h" diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index f9dce309d1..e204f10c2a 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -39,7 +39,7 @@ #include "midi_time_axis.h" #include "midi_view.h" #include "time_axis_view_item.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "enums.h" namespace ARDOUR { diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc index ea25f61e63..642ca8c914 100644 --- a/gtk2_ardour/midi_time_axis.cc +++ b/gtk2_ardour/midi_time_axis.cc @@ -76,7 +76,7 @@ #include "ardour/velocity_control.h" #include "ardour_message.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "automation_time_axis.h" #include "editor.h" #include "enums.h" diff --git a/gtk2_ardour/midi_trigger_properties_box.cc b/gtk2_ardour/midi_trigger_properties_box.cc index b2e61dfb3a..05d26fda1e 100644 --- a/gtk2_ardour/midi_trigger_properties_box.cc +++ b/gtk2_ardour/midi_trigger_properties_box.cc @@ -31,7 +31,7 @@ #include "widgets/ardour_button.h" #include "audio_clock.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "control_point.h" #include "editor.h" #include "region_view.h" diff --git a/gtk2_ardour/midi_view.h b/gtk2_ardour/midi_view.h index 0aaf5ddd53..10de1513f3 100644 --- a/gtk2_ardour/midi_view.h +++ b/gtk2_ardour/midi_view.h @@ -42,7 +42,7 @@ #include "region_view.h" #include "midi_view_background.h" #include "time_axis_view_item.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "enums.h" namespace ARDOUR { diff --git a/gtk2_ardour/multi_region_properties_box.cc b/gtk2_ardour/multi_region_properties_box.cc index d3633c64cb..fe5680ead0 100644 --- a/gtk2_ardour/multi_region_properties_box.cc +++ b/gtk2_ardour/multi_region_properties_box.cc @@ -29,7 +29,7 @@ #include "ardour/session.h" #include "audio_clock.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "control_point.h" #include "editor.h" #include "region_view.h" diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index 1bfbadc887..3d21cd979f 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -86,7 +86,7 @@ namespace Gtk { } class AudioRegionView; -class AutomationLine; +class EditorAutomationLine; class AutomationTimeAxisView; class ControlPoint; class DragManager; @@ -361,7 +361,7 @@ public: virtual bool canvas_control_point_event (GdkEvent* event, ArdourCanvas::Item*, ControlPoint*) = 0; virtual bool canvas_velocity_event (GdkEvent* event, ArdourCanvas::Item*) = 0; virtual bool canvas_velocity_base_event (GdkEvent* event, ArdourCanvas::Item*) = 0; - virtual bool canvas_line_event (GdkEvent* event, ArdourCanvas::Item*, AutomationLine*) = 0; + virtual bool canvas_line_event (GdkEvent* event, ArdourCanvas::Item*, EditorAutomationLine*) = 0; virtual bool canvas_selection_rect_event (GdkEvent* event, ArdourCanvas::Item*, SelectionRect*) = 0; virtual bool canvas_selection_start_trim_event (GdkEvent* event, ArdourCanvas::Item*, SelectionRect*) = 0; virtual bool canvas_selection_end_trim_event (GdkEvent* event, ArdourCanvas::Item*, SelectionRect*) = 0; diff --git a/gtk2_ardour/region_fx_line.cc b/gtk2_ardour/region_fx_line.cc index 8b86d67fb6..6515f2c2e1 100644 --- a/gtk2_ardour/region_fx_line.cc +++ b/gtk2_ardour/region_fx_line.cc @@ -27,7 +27,7 @@ using namespace ARDOUR; RegionFxLine::RegionFxLine (std::string const& name, RegionView& r, ArdourCanvas::Container& parent, std::shared_ptr l, ParameterDescriptor const& d) - : AutomationLine (name, r.get_time_axis_view(), parent, l, d) + : EditorAutomationLine (name, r.get_time_axis_view(), parent, l, d) , _rv (r) { terminal_points_can_slide = false; @@ -35,7 +35,7 @@ RegionFxLine::RegionFxLine (std::string const& name, RegionView& r, ArdourCanvas } RegionFxLine::RegionFxLine (std::string const& name, RegionView& r, ArdourCanvas::Container& parent, std::shared_ptr ac) - : AutomationLine (name, r.get_time_axis_view(), parent, ac->alist (), ac->desc ()) + : EditorAutomationLine (name, r.get_time_axis_view(), parent, ac->alist (), ac->desc ()) , _rv (r) , _ac (ac) { @@ -70,14 +70,14 @@ void RegionFxLine::end_drag (bool with_push, uint32_t final_index) { enable_automation (); - AutomationLine::end_drag (with_push, final_index); + EditorAutomationLine::end_drag (with_push, final_index); } void RegionFxLine::end_draw_merge () { enable_automation (); - AutomationLine::end_draw_merge (); + EditorAutomationLine::end_draw_merge (); } void diff --git a/gtk2_ardour/region_fx_line.h b/gtk2_ardour/region_fx_line.h index 84aec3f0d7..b1e45f9c3a 100644 --- a/gtk2_ardour/region_fx_line.h +++ b/gtk2_ardour/region_fx_line.h @@ -19,11 +19,11 @@ #ifndef __ardour_gtk_region_fx_line_h__ #define __ardour_gtk_region_fx_line_h__ -#include "automation_line.h" +#include "editor_automation_line.h" class RegionView; -class RegionFxLine : public AutomationLine +class RegionFxLine : public EditorAutomationLine { public: RegionFxLine (std::string const&, RegionView&, ArdourCanvas::Container&, std::shared_ptr, ARDOUR::ParameterDescriptor const&); diff --git a/gtk2_ardour/region_properties_box.cc b/gtk2_ardour/region_properties_box.cc index e7d2f90a1f..16d3b55b19 100644 --- a/gtk2_ardour/region_properties_box.cc +++ b/gtk2_ardour/region_properties_box.cc @@ -29,7 +29,7 @@ #include "ardour/session.h" #include "audio_clock.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "control_point.h" #include "editor.h" #include "region_view.h" diff --git a/gtk2_ardour/region_view.h b/gtk2_ardour/region_view.h index 2f8006016f..fda4ea3b47 100644 --- a/gtk2_ardour/region_view.h +++ b/gtk2_ardour/region_view.h @@ -36,7 +36,7 @@ #include "canvas/fwd.h" #include "time_axis_view_item.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "enums.h" #include "marker.h" diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 7f9fa9d273..b7e0c7631d 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -1968,7 +1968,7 @@ RouteTimeAxisView::add_existing_processor_automation_curves (std::weak_ptr::iterator i = existing.begin(); i != existing.end(); ++i) { Evoral::Parameter param (*i); - std::shared_ptr al; + std::shared_ptr al; std::shared_ptr control = std::dynamic_pointer_cast(processor->control(*i, false)); if (!control || control->flags () & Controllable::HiddenControl) { @@ -2227,7 +2227,7 @@ RouteTimeAxisView::processors_changed (RouteProcessorChange c) } } -std::shared_ptr +std::shared_ptr RouteTimeAxisView::find_processor_automation_curve (std::shared_ptr processor, Evoral::Parameter what) { ProcessorAutomationNode* pan; @@ -2238,7 +2238,7 @@ RouteTimeAxisView::find_processor_automation_curve (std::shared_ptr p } } - return std::shared_ptr(); + return std::shared_ptr(); } void @@ -2606,7 +2606,7 @@ RouteTimeAxisView::automation_child(Evoral::Parameter param, PBD::ID ctrl_id) return std::shared_ptr(); } -std::shared_ptr +std::shared_ptr RouteTimeAxisView::automation_child_by_alist_id (PBD::ID alist_id) { for (list::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) { diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h index 549de78252..eb709a21d0 100644 --- a/gtk2_ardour/route_time_axis.h +++ b/gtk2_ardour/route_time_axis.h @@ -69,7 +69,7 @@ class Selection; class RegionSelection; class Selectable; class AutomationTimeAxisView; -class AutomationLine; +class EditorAutomationLine; class TimeSelection; class RouteGroupMenu; class ItemCounts; @@ -201,13 +201,13 @@ protected: std::shared_ptr find_atav_by_ctrl (std::shared_ptr, bool route_owned_only = true); - std::shared_ptr + std::shared_ptr find_processor_automation_curve (std::shared_ptr i, Evoral::Parameter); void add_processor_automation_curve (std::shared_ptr r, Evoral::Parameter); void add_existing_processor_automation_curves (std::weak_ptr); - std::shared_ptr automation_child_by_alist_id (PBD::ID); + std::shared_ptr automation_child_by_alist_id (PBD::ID); void reset_processor_automation_curves (); @@ -270,7 +270,7 @@ protected: std::map, Gtk::CheckMenuItem*> ctrl_item_map; - typedef std::vector > ProcessorAutomationCurves; + typedef std::vector > ProcessorAutomationCurves; ProcessorAutomationCurves processor_automation_curves; /** parameter -> menu item map for the plugin automation menu */ ParameterMenuMap _subplugin_menu_map; diff --git a/gtk2_ardour/selection.cc b/gtk2_ardour/selection.cc index 5ddd08bbaf..baccc2473b 100644 --- a/gtk2_ardour/selection.cc +++ b/gtk2_ardour/selection.cc @@ -37,7 +37,7 @@ #include "control_protocol/control_protocol.h" #include "audio_region_view.h" -#include "automation_line_base.h" +#include "automation_line.h" #include "debug.h" #include "gui_thread.h" #include "midi_cut_buffer.h" @@ -540,7 +540,7 @@ Selection::add (std::shared_ptr cl) } /* The original may change so we must store a copy (not a pointer) here. - * e.g AutomationLine rewrites the list with gain mapping. + * e.g EditorAutomationLine rewrites the list with gain mapping. * the downside is that we can't perform duplicate checks. * This code was changed in response to #6842 */ @@ -1165,7 +1165,7 @@ Selection::get_state () const } for (auto & cp : points) { - AutomationLine* al = dynamic_cast (&cp->line()); + EditorAutomationLine* al = dynamic_cast (&cp->line()); assert (al); AutomationTimeAxisView* atv = dynamic_cast (&al->trackview); if (atv) { @@ -1315,7 +1315,7 @@ Selection::set_state (XMLNode const & node, int) vector cps; if (stv) { - std::shared_ptr li = stv->automation_child_by_alist_id (alist_id); + std::shared_ptr li = stv->automation_child_by_alist_id (alist_id); if (li) { ControlPoint* cp = li->nth(view_index); if (cp) { diff --git a/gtk2_ardour/selection.h b/gtk2_ardour/selection.h index f3b6c13ed2..fd73c4f05a 100644 --- a/gtk2_ardour/selection.h +++ b/gtk2_ardour/selection.h @@ -52,7 +52,7 @@ class RegionView; class Selectable; class EditingContext; class MidiRegionView; -class AutomationLine; +class EditorAutomationLine; class ControlPoint; diff --git a/gtk2_ardour/selection_properties_box.cc b/gtk2_ardour/selection_properties_box.cc index 7b70beac7d..4ea6f98290 100644 --- a/gtk2_ardour/selection_properties_box.cc +++ b/gtk2_ardour/selection_properties_box.cc @@ -29,7 +29,7 @@ #include "ardour/session.h" #include "audio_clock.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "control_point.h" #include "editor.h" #include "region_view.h" diff --git a/gtk2_ardour/streamview.cc b/gtk2_ardour/streamview.cc index 7e560d4f08..aac13c57ba 100644 --- a/gtk2_ardour/streamview.cc +++ b/gtk2_ardour/streamview.cc @@ -621,7 +621,7 @@ StreamView::get_selectables (timepos_t const & start, timepos_t const & end, dou if (_trackview.editor().internal_editing()) { AudioRegionView* arv = dynamic_cast (*i); if (arv && arv->fx_line ()) { - /* Note: AutomationLine::get_selectables() uses trackview.current_height (), + /* Note: EditorAutomationLine::get_selectables() uses trackview.current_height (), * disregarding Stacked layer display height */ double const c = height; // child_height (); // XXX diff --git a/gtk2_ardour/stripable_time_axis.cc b/gtk2_ardour/stripable_time_axis.cc index 92cb4053ff..c95de6558c 100644 --- a/gtk2_ardour/stripable_time_axis.cc +++ b/gtk2_ardour/stripable_time_axis.cc @@ -25,7 +25,7 @@ #include "public_editor.h" #include "stripable_time_axis.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "pbd/i18n.h" @@ -192,7 +192,7 @@ StripableTimeAxisView::automation_child(Evoral::Parameter param, PBD::ID) } } -std::shared_ptr +std::shared_ptr StripableTimeAxisView::automation_child_by_alist_id (PBD::ID alist_id) { for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) { @@ -203,7 +203,7 @@ StripableTimeAxisView::automation_child_by_alist_id (PBD::ID alist_id) } } } - return std::shared_ptr (); + return std::shared_ptr (); } void diff --git a/gtk2_ardour/stripable_time_axis.h b/gtk2_ardour/stripable_time_axis.h index 8844bcb6b7..ddd78f26ba 100644 --- a/gtk2_ardour/stripable_time_axis.h +++ b/gtk2_ardour/stripable_time_axis.h @@ -38,7 +38,7 @@ public: virtual void create_automation_child (const Evoral::Parameter& param, bool show) = 0; virtual std::shared_ptr automation_child (Evoral::Parameter param, PBD::ID ctrl_id = PBD::ID(0)); - virtual std::shared_ptr automation_child_by_alist_id (PBD::ID); + virtual std::shared_ptr automation_child_by_alist_id (PBD::ID); void request_redraw (); diff --git a/gtk2_ardour/time_info_box.cc b/gtk2_ardour/time_info_box.cc index 1985812ea9..86d89371c3 100644 --- a/gtk2_ardour/time_info_box.cc +++ b/gtk2_ardour/time_info_box.cc @@ -30,7 +30,7 @@ #include "ardour/session.h" #include "audio_clock.h" -#include "automation_line.h" +#include "editor_automation_line.h" #include "control_point.h" #include "editor.h" #include "region_view.h" diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index afb17f2e82..0ed5ccc007 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -49,7 +49,6 @@ gtk2_ardour_sources = [ 'audio_time_axis.cc', 'automation_controller.cc', 'automation_line.cc', - 'automation_line_base.cc', 'automation_region_view.cc', 'automation_streamview.cc', 'automation_time_axis.cc', @@ -78,6 +77,7 @@ gtk2_ardour_sources = [ 'editing_context.cc', 'editor.cc', 'editor_actions.cc', + 'editor_automation_line.cc', 'editor_audio_import.cc', 'editor_pt_import.cc', 'editor_audiotrack.cc',