diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc index 120fa176a8e..ca66fe8fb85 100644 --- a/gtk2_ardour/automation_line.cc +++ b/gtk2_ardour/automation_line.cc @@ -394,26 +394,58 @@ AutomationLine::delta_to_string (double delta) const * @return Corresponding y fraction. */ double -AutomationLine::string_to_fraction (string const & s) const +AutomationLine::string_to_fraction (string const & s, double const old_fraction) const { - double v; - sscanf (s.c_str(), "%lf", &v); - + bool is_db = false; switch (_desc.type) { case GainAutomation: case BusSendLevel: case EnvelopeAutomation: case TrimAutomation: case InsertReturnLevel: - if (s == "-inf") { /* translation */ - v = 0; - } else { - v = dB_to_coefficient (v); - } + is_db = true; break; default: break; } + double v; + if ((s.length() > 2) && index("+-*/", s[0]) && (s[1] == '=')) { + v = old_fraction; + view_to_model_coord_y (v); + if (is_db) { + v = accurate_coefficient_to_dB(v); + } + double op_v; + sscanf (s.c_str() + 2, "%lf", &op_v); + if (op_v != 0.f) { + switch (s[0]) { + case '+': + v += op_v; + break; + case '-': + v -= op_v; + break; + case '*': + v *= op_v; + break; + case '/': + if (op_v > 1.0) { + v /= op_v; + } + break; + } + } + } else { + sscanf (s.c_str(), "%lf", &v); + } + + if (is_db) { + if (s == "-inf") { /* translation */ + v = 0; + } else { + v = dB_to_coefficient (v); + } + } return model_to_view_coord_y (v); } diff --git a/gtk2_ardour/automation_line.h b/gtk2_ardour/automation_line.h index 8c3ca154c58..553c0fc5823 100644 --- a/gtk2_ardour/automation_line.h +++ b/gtk2_ardour/automation_line.h @@ -125,7 +125,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible 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; + double string_to_fraction (std::string const &, double old_fraction) const; void view_to_model_coord_y (double &) const; diff --git a/gtk2_ardour/control_point_dialog.cc b/gtk2_ardour/control_point_dialog.cc index ac82cfd0762..a49d0bb0cda 100644 --- a/gtk2_ardour/control_point_dialog.cc +++ b/gtk2_ardour/control_point_dialog.cc @@ -90,9 +90,11 @@ ControlPointDialog::ControlPointDialog (ControlPoint* p, bool multi) } double -ControlPointDialog::get_y_fraction () const +ControlPointDialog::get_y_fraction (ControlPoint* p) const { - return point_->line().string_to_fraction (value_.get_text ()); + double const old_fraction = 1.0 - (p->get_y () / p->line().height ()); + + return point_->line().string_to_fraction (value_.get_text (), old_fraction); } bool diff --git a/gtk2_ardour/control_point_dialog.h b/gtk2_ardour/control_point_dialog.h index c0ef2627cbf..73961ae8dbb 100644 --- a/gtk2_ardour/control_point_dialog.h +++ b/gtk2_ardour/control_point_dialog.h @@ -29,7 +29,7 @@ class ControlPointDialog : public ArdourDialog public: ControlPointDialog (ControlPoint *, bool multi); - double get_y_fraction () const; + double get_y_fraction (ControlPoint *) const; bool all_selected_points () const; diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 40af6606286..6141e1c8b4c 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -2514,11 +2514,11 @@ Editor::edit_control_point (ArdourCanvas::Item* item) } if (d.all_selected_points ()) { - p->line().modify_points_y (cps, d.get_y_fraction ()); + p->line().modify_points_y (cps, d.get_y_fraction (p)); // FIXME: multi edit somehow? } else { cps.clear (); cps.push_back (p); - p->line().modify_points_y (cps, d.get_y_fraction ()); + p->line().modify_points_y (cps, d.get_y_fraction (p)); } }