mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-08 07:45:00 +01:00
First cut of some Pro-tools inspired editing features; linked play/play range
and linked object/range modes. git-svn-id: svn://localhost/ardour2/branches/3.0@6431 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
6572f421a4
commit
f5acf93672
18 changed files with 582 additions and 186 deletions
|
|
@ -1558,8 +1558,13 @@ ARDOUR_UI::transport_roll ()
|
|||
|
||||
if (_session->get_play_loop()) {
|
||||
_session->request_play_loop (false, true);
|
||||
} else if (_session->get_play_range ()) {
|
||||
_session->request_play_range (false, true);
|
||||
} else if (_session->get_play_range () && !join_play_range_button.get_active()) {
|
||||
/* stop playing a range if we currently are */
|
||||
_session->request_play_range (0, true);
|
||||
}
|
||||
|
||||
if (join_play_range_button.get_active()) {
|
||||
_session->request_play_range (&editor->get_selection().time, true);
|
||||
}
|
||||
|
||||
if (!rolling) {
|
||||
|
|
@ -1619,6 +1624,10 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
|
|||
if (rolling) {
|
||||
_session->request_stop (with_abort, true);
|
||||
} else {
|
||||
if (join_play_range_button.get_active()) {
|
||||
_session->request_play_range (&editor->get_selection().time, true);
|
||||
}
|
||||
|
||||
_session->request_transport_speed (1.0f);
|
||||
}
|
||||
}
|
||||
|
|
@ -1761,6 +1770,8 @@ ARDOUR_UI::map_transport_state ()
|
|||
|
||||
if (sp != 0.0) {
|
||||
|
||||
/* we're rolling */
|
||||
|
||||
if (_session->get_play_range()) {
|
||||
|
||||
play_selection_button.set_visual_state (1);
|
||||
|
|
@ -1780,6 +1791,12 @@ ARDOUR_UI::map_transport_state ()
|
|||
auto_loop_button.set_visual_state (0);
|
||||
}
|
||||
|
||||
if (join_play_range_button.get_active()) {
|
||||
/* light up both roll and play-selection if they are joined */
|
||||
roll_button.set_visual_state (1);
|
||||
play_selection_button.set_visual_state (1);
|
||||
}
|
||||
|
||||
stop_button.set_visual_state (0);
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -328,6 +328,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
|
|||
Gtkmm2ext::TearOff* transport_tearoff;
|
||||
Gtk::Frame transport_frame;
|
||||
Gtk::HBox transport_tearoff_hbox;
|
||||
Gtk::HBox play_range_hbox;
|
||||
Gtk::VBox play_range_vbox;
|
||||
Gtk::HBox transport_hbox;
|
||||
Gtk::Fixed transport_base;
|
||||
Gtk::Fixed transport_button_base;
|
||||
|
|
@ -385,6 +387,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
|
|||
BindableButton auto_loop_button;
|
||||
BindableButton play_selection_button;
|
||||
BindableButton rec_button;
|
||||
Gtk::ToggleButton join_play_range_button;
|
||||
|
||||
void toggle_external_sync ();
|
||||
void toggle_time_master ();
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ ARDOUR_UI::setup_transport ()
|
|||
play_selection_button.set_name ("TransportButton");
|
||||
rec_button.set_name ("TransportRecButton");
|
||||
auto_loop_button.set_name ("TransportButton");
|
||||
join_play_range_button.set_name ("TransportButton");
|
||||
|
||||
auto_return_button.set_name ("TransportButton");
|
||||
auto_play_button.set_name ("TransportButton");
|
||||
|
|
@ -221,6 +222,9 @@ ARDOUR_UI::setup_transport ()
|
|||
w = manage (new Image (get_icon (X_("transport_loop"))));
|
||||
w->show();
|
||||
auto_loop_button.add (*w);
|
||||
w = manage (new Image (get_icon (X_("join_tools"))));
|
||||
w->show ();
|
||||
join_play_range_button.add (*w);
|
||||
|
||||
RefPtr<Action> act;
|
||||
|
||||
|
|
@ -361,11 +365,17 @@ ARDOUR_UI::setup_transport ()
|
|||
|
||||
transport_tearoff_hbox.pack_start (*svbox, false, false, 3);
|
||||
|
||||
transport_tearoff_hbox.pack_start (auto_loop_button, false, false);
|
||||
if (!Profile->get_sae()) {
|
||||
transport_tearoff_hbox.pack_start (play_selection_button, false, false);
|
||||
if (Profile->get_sae()) {
|
||||
transport_tearoff_hbox.pack_start (auto_loop_button);
|
||||
transport_tearoff_hbox.pack_start (roll_button);
|
||||
} else {
|
||||
transport_tearoff_hbox.pack_start (auto_loop_button, false, false);
|
||||
play_range_hbox.pack_start (play_selection_button, false, false);
|
||||
play_range_hbox.pack_start (roll_button, false, false);
|
||||
play_range_vbox.pack_start (play_range_hbox, false, false);
|
||||
play_range_vbox.pack_start (join_play_range_button, false, false);
|
||||
transport_tearoff_hbox.pack_start (play_range_vbox, false, false);
|
||||
}
|
||||
transport_tearoff_hbox.pack_start (roll_button, false, false);
|
||||
transport_tearoff_hbox.pack_start (stop_button, false, false);
|
||||
transport_tearoff_hbox.pack_start (rec_button, false, false, 6);
|
||||
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ AutomationLine::modify_point_y (ControlPoint& cp, double y)
|
|||
|
||||
|
||||
void
|
||||
AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool with_push)
|
||||
AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool keep_x, bool with_push)
|
||||
{
|
||||
double delta = 0.0;
|
||||
uint32_t last_movable = UINT_MAX;
|
||||
|
|
@ -257,7 +257,7 @@ AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool wi
|
|||
y = min (1.0, y);
|
||||
y = _height - (y * _height);
|
||||
|
||||
if (cp.can_slide()) {
|
||||
if (cp.can_slide() && !keep_x) {
|
||||
|
||||
/* x-coord cannot move beyond adjacent points or the start/end, and is
|
||||
already in frames. it needs to be converted to canvas units.
|
||||
|
|
@ -362,15 +362,12 @@ AutomationLine::reset_line_coords (ControlPoint& cp)
|
|||
}
|
||||
|
||||
void
|
||||
AutomationLine::sync_model_with_view_line (uint32_t start, uint32_t end)
|
||||
AutomationLine::sync_model_with_view_points (list<ControlPoint*> cp, bool did_push, int64_t distance)
|
||||
{
|
||||
ControlPoint *p;
|
||||
|
||||
update_pending = true;
|
||||
|
||||
for (uint32_t i = start; i <= end; ++i) {
|
||||
p = nth(i);
|
||||
sync_model_with_view_point (*p, false, 0);
|
||||
for (list<ControlPoint*>::iterator i = cp.begin(); i != cp.end(); ++i) {
|
||||
sync_model_with_view_point (**i, did_push, distance);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -488,6 +485,14 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
|
|||
double tx = points[pi].x;
|
||||
double ty = points[pi].y;
|
||||
|
||||
if (find (_always_in_view.begin(), _always_in_view.end(), (*model)->when) != _always_in_view.end()) {
|
||||
add_visible_control_point (view_index, pi, tx, ty, model, npoints);
|
||||
prev_rx = this_rx;
|
||||
prev_ry = this_ry;
|
||||
++view_index;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isnan (tx) || isnan (ty)) {
|
||||
warning << string_compose (_("Ignoring illegal points on AutomationLine \"%1\""),
|
||||
_name) << endmsg;
|
||||
|
|
@ -667,66 +672,36 @@ AutomationLine::invalidate_point (ALPoints& p, uint32_t index)
|
|||
p[index].y = DBL_MAX;
|
||||
}
|
||||
|
||||
/** Start dragging a single point.
|
||||
* @param cp Point to drag.
|
||||
* @param x Initial x position (frames).
|
||||
* @param fraction Initial y position (as a fraction of the track height, where 0 is the bottom and 1 the top)
|
||||
*/
|
||||
void
|
||||
AutomationLine::start_drag (ControlPoint* cp, nframes_t x, float fraction)
|
||||
AutomationLine::start_drag_single (ControlPoint* cp, nframes_t x, float fraction)
|
||||
{
|
||||
if (trackview.editor().session() == 0) { /* how? */
|
||||
return;
|
||||
}
|
||||
|
||||
string str;
|
||||
|
||||
if (cp) {
|
||||
str = _("automation event move");
|
||||
} else {
|
||||
str = _("automation range drag");
|
||||
}
|
||||
|
||||
trackview.editor().session()->begin_reversible_command (str);
|
||||
trackview.editor().session()->begin_reversible_command (_("automation event move"));
|
||||
trackview.editor().session()->add_command (new MementoCommand<AutomationList>(*alist.get(), &get_state(), 0));
|
||||
|
||||
drag_x = x;
|
||||
drag_distance = 0;
|
||||
first_drag_fraction = fraction;
|
||||
last_drag_fraction = fraction;
|
||||
drags = 0;
|
||||
did_push = false;
|
||||
_drag_points.clear ();
|
||||
_drag_points.push_back (cp);
|
||||
start_drag_common (x, fraction);
|
||||
}
|
||||
|
||||
/** Start dragging a line vertically (with no change in x)
|
||||
* @param i1 Control point index of the `left' point on the line.
|
||||
* @param i2 Control point index of the `right' point on the line.
|
||||
* @param fraction Initial y position (as a fraction of the track height, where 0 is the bottom and 1 the top)
|
||||
*/
|
||||
void
|
||||
AutomationLine::point_drag (ControlPoint& cp, nframes_t x, float fraction, bool with_push)
|
||||
AutomationLine::start_drag_line (uint32_t i1, uint32_t i2, float fraction)
|
||||
{
|
||||
if (x > drag_x) {
|
||||
drag_distance += (x - drag_x);
|
||||
} else {
|
||||
drag_distance -= (drag_x - x);
|
||||
}
|
||||
trackview.editor().session()->begin_reversible_command (_("automation range move"));
|
||||
trackview.editor().session()->add_command (new MementoCommand<AutomationList>(*alist.get(), &get_state(), 0));
|
||||
|
||||
drag_x = x;
|
||||
_drag_points.clear ();
|
||||
|
||||
modify_view_point (cp, x, fraction, with_push);
|
||||
|
||||
if (line_points.size() > 1) {
|
||||
line->property_points() = line_points;
|
||||
}
|
||||
|
||||
drags++;
|
||||
did_push = with_push;
|
||||
}
|
||||
|
||||
void
|
||||
AutomationLine::line_drag (uint32_t i1, uint32_t i2, float fraction, bool with_push)
|
||||
{
|
||||
double ydelta = fraction - last_drag_fraction;
|
||||
|
||||
did_push = with_push;
|
||||
|
||||
last_drag_fraction = fraction;
|
||||
|
||||
line_drag_cp1 = i1;
|
||||
line_drag_cp2 = i2;
|
||||
|
||||
//check if one of the control points on the line is in a selected range
|
||||
// check if one of the control points on the line is in a selected range
|
||||
bool range_found = false;
|
||||
ControlPoint *cp;
|
||||
|
||||
|
|
@ -740,38 +715,92 @@ AutomationLine::line_drag (uint32_t i1, uint32_t i2, float fraction, bool with_p
|
|||
if (range_found) {
|
||||
for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
|
||||
if ((*i)->selected()) {
|
||||
modify_view_point (*(*i), trackview.editor().unit_to_frame ((*i)->get_x()), ((_height - (*i)->get_y()) /_height) + ydelta, with_push);
|
||||
_drag_points.push_back (*i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ControlPoint *cp;
|
||||
for (uint32_t i = i1 ; i <= i2; i++) {
|
||||
cp = nth (i);
|
||||
modify_view_point (*cp, trackview.editor().unit_to_frame (cp->get_x()), ((_height - cp->get_y()) /_height) + ydelta, with_push);
|
||||
_drag_points.push_back (nth (i));
|
||||
}
|
||||
}
|
||||
|
||||
start_drag_common (0, fraction);
|
||||
}
|
||||
|
||||
/** Start dragging multiple points (with no change in x)
|
||||
* @param cp Points to drag.
|
||||
* @param fraction Initial y position (as a fraction of the track height, where 0 is the bottom and 1 the top)
|
||||
*/
|
||||
void
|
||||
AutomationLine::start_drag_multiple (list<ControlPoint*> cp, float fraction, XMLNode* state)
|
||||
{
|
||||
trackview.editor().session()->begin_reversible_command (_("automation range move"));
|
||||
trackview.editor().session()->add_command (new MementoCommand<AutomationList>(*alist.get(), state, 0));
|
||||
|
||||
_drag_points = cp;
|
||||
start_drag_common (0, fraction);
|
||||
}
|
||||
|
||||
/** Common parts of starting a drag.
|
||||
* @param d Description of the drag.
|
||||
* @param x Starting x position in frames, or 0 if x is being ignored.
|
||||
* @param fraction Starting y position (as a fraction of the track height, where 0 is the bottom and 1 the top)
|
||||
*/
|
||||
void
|
||||
AutomationLine::start_drag_common (nframes_t x, float fraction)
|
||||
{
|
||||
drag_x = x;
|
||||
drag_distance = 0;
|
||||
_last_drag_fraction = fraction;
|
||||
_drag_had_movement = false;
|
||||
did_push = false;
|
||||
}
|
||||
|
||||
/** Should be called to indicate motion during a drag.
|
||||
* @param x New x position of the drag in frames, or 0 if x is being ignored.
|
||||
* @param fraction New y fraction.
|
||||
*/
|
||||
void
|
||||
AutomationLine::drag_motion (nframes_t x, float fraction, bool with_push)
|
||||
{
|
||||
int64_t const dx = x - drag_x;
|
||||
drag_distance += dx;
|
||||
drag_x = x;
|
||||
|
||||
double const dy = fraction - _last_drag_fraction;
|
||||
|
||||
_last_drag_fraction = fraction;
|
||||
|
||||
for (list<ControlPoint*>::iterator i = _drag_points.begin(); i != _drag_points.end(); ++i) {
|
||||
|
||||
modify_view_point (
|
||||
**i,
|
||||
trackview.editor().unit_to_frame ((*i)->get_x()) + dx,
|
||||
((_height - (*i)->get_y()) / _height) + dy,
|
||||
(x == 0),
|
||||
with_push
|
||||
);
|
||||
}
|
||||
|
||||
if (line_points.size() > 1) {
|
||||
line->property_points() = line_points;
|
||||
}
|
||||
|
||||
drags++;
|
||||
_drag_had_movement = true;
|
||||
did_push = with_push;
|
||||
}
|
||||
|
||||
/** Should be called to indicate the end of a drag */
|
||||
void
|
||||
AutomationLine::end_drag (ControlPoint* cp)
|
||||
AutomationLine::end_drag ()
|
||||
{
|
||||
if (!drags) {
|
||||
if (!_drag_had_movement) {
|
||||
return;
|
||||
}
|
||||
|
||||
alist->freeze ();
|
||||
|
||||
if (cp) {
|
||||
sync_model_with_view_point (*cp, did_push, drag_distance);
|
||||
} else {
|
||||
sync_model_with_view_line (line_drag_cp1, line_drag_cp2);
|
||||
}
|
||||
sync_model_with_view_points (_drag_points, did_push, drag_distance);
|
||||
|
||||
alist->thaw ();
|
||||
|
||||
|
|
@ -782,7 +811,6 @@ AutomationLine::end_drag (ControlPoint* cp)
|
|||
trackview.editor().session()->set_dirty ();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int64_t distance)
|
||||
{
|
||||
|
|
@ -849,7 +877,6 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int
|
|||
|
||||
alist->slide (mr.end, drag_distance);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -1316,3 +1343,18 @@ AutomationLine::add_visible_control_point (uint32_t view_index, uint32_t pi, dou
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutomationLine::add_always_in_view (double x)
|
||||
{
|
||||
_always_in_view.push_back (x);
|
||||
alist->apply_to_points (*this, &AutomationLine::reset_callback);
|
||||
}
|
||||
|
||||
void
|
||||
AutomationLine::clear_always_in_view ()
|
||||
{
|
||||
_always_in_view.clear ();
|
||||
alist->apply_to_points (*this, &AutomationLine::reset_callback);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,10 +74,11 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
|
|||
bool control_points_adjacent (double xval, uint32_t& before, uint32_t& after);
|
||||
|
||||
/* dragging API */
|
||||
virtual void start_drag (ControlPoint*, nframes_t x, float fraction);
|
||||
virtual void point_drag(ControlPoint&, nframes_t x, float, bool with_push);
|
||||
virtual void end_drag (ControlPoint*);
|
||||
virtual void line_drag(uint32_t i1, uint32_t i2, float, bool with_push);
|
||||
virtual void start_drag_single (ControlPoint*, nframes_t x, float);
|
||||
virtual void start_drag_line (uint32_t, uint32_t, float);
|
||||
virtual void start_drag_multiple (std::list<ControlPoint*>, float, XMLNode *);
|
||||
virtual void drag_motion (nframes_t, float, bool);
|
||||
virtual void end_drag ();
|
||||
|
||||
ControlPoint* nth (uint32_t);
|
||||
uint32_t npoints() const { return control_points.size(); }
|
||||
|
|
@ -130,6 +131,9 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
|
|||
|
||||
void modify_point_y (ControlPoint&, double);
|
||||
|
||||
void add_always_in_view (double);
|
||||
void clear_always_in_view ();
|
||||
|
||||
protected:
|
||||
|
||||
std::string _name;
|
||||
|
|
@ -164,8 +168,9 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
|
|||
static bool invalid_point (ALPoints&, uint32_t index);
|
||||
|
||||
void determine_visible_control_points (ALPoints&);
|
||||
void sync_model_with_view_point (ControlPoint&, bool did_push, int64_t distance);
|
||||
void sync_model_with_view_line (uint32_t, uint32_t);
|
||||
void sync_model_with_view_point (ControlPoint&, bool, int64_t);
|
||||
void sync_model_with_view_points (std::list<ControlPoint*>, bool, int64_t);
|
||||
void start_drag_common (nframes_t, float);
|
||||
|
||||
virtual void change_model (ARDOUR::AutomationList::iterator, double x, double y);
|
||||
|
||||
|
|
@ -177,18 +182,17 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
|
|||
virtual void add_model_point (ALPoints& tmp_points, double frame, double yfract);
|
||||
|
||||
private:
|
||||
uint32_t drags;
|
||||
double first_drag_fraction;
|
||||
double last_drag_fraction;
|
||||
uint32_t line_drag_cp1;
|
||||
uint32_t line_drag_cp2;
|
||||
int64_t drag_x;
|
||||
int64_t drag_distance;
|
||||
std::list<ControlPoint*> _drag_points; ///< points we are dragging
|
||||
bool _drag_had_movement; ///< true if the drag has seen movement, otherwise false
|
||||
nframes64_t drag_x; ///< last x position of the drag, in frames
|
||||
nframes64_t drag_distance; ///< total x movement of the drag, in frames
|
||||
double _last_drag_fraction; ///< last y position of the drag, as a fraction
|
||||
std::list<double> _always_in_view;
|
||||
|
||||
const Evoral::TimeConverter<double, ARDOUR::sframes_t>& _time_converter;
|
||||
ARDOUR::AutomationList::InterpolationStyle _interpolation;
|
||||
|
||||
void modify_view_point (ControlPoint&, double, double, bool with_push);
|
||||
void modify_view_point (ControlPoint&, double, double, bool, bool with_push);
|
||||
void reset_line_coords (ControlPoint&);
|
||||
void add_visible_control_point (uint32_t, uint32_t, double, double, ARDOUR::AutomationList::iterator, uint32_t);
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,10 @@ class AutomationTimeAxisView : public TimeAxisView {
|
|||
boost::shared_ptr<ARDOUR::AutomationControl> control() { return _control; }
|
||||
boost::shared_ptr<AutomationController> controller() { return _controller; }
|
||||
|
||||
ArdourCanvas::Item* base_item () const {
|
||||
return _base_rect;
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::shared_ptr<ARDOUR::Route> _route; ///< Parent route
|
||||
boost::shared_ptr<ARDOUR::AutomationControl> _control; ///< Control
|
||||
|
|
|
|||
|
|
@ -155,15 +155,6 @@ void
|
|||
ControlPoint::set_size (double sz)
|
||||
{
|
||||
_size = sz;
|
||||
|
||||
#if 0
|
||||
if (_size > 6.0) {
|
||||
item->property_fill() = (gboolean) TRUE;
|
||||
} else {
|
||||
item->property_fill() = (gboolean) FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
move_to (_x, _y, _shape);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -220,8 +220,10 @@ show_me_the_size (Requisition* r, const char* what)
|
|||
}
|
||||
|
||||
Editor::Editor ()
|
||||
: _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
|
||||
|
||||
/* time display buttons */
|
||||
: minsec_label (_("Mins:Secs"))
|
||||
, minsec_label (_("Mins:Secs"))
|
||||
, bbt_label (_("Bars:Beats"))
|
||||
, timecode_label (_("Timecode"))
|
||||
, frame_label (_("Samples"))
|
||||
|
|
@ -2314,6 +2316,10 @@ Editor::set_state (const XMLNode& node, int /*version*/)
|
|||
}
|
||||
}
|
||||
|
||||
if ((prop = node.property ("join-object-range"))) {
|
||||
join_object_range_button.set_active (string_is_affirmative (prop->value ()));
|
||||
}
|
||||
|
||||
if ((prop = node.property ("edit-point"))) {
|
||||
set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
|
||||
}
|
||||
|
|
@ -2461,6 +2467,7 @@ Editor::get_state ()
|
|||
node->add_property ("region-list-sort-type", enum2str (_regions->sort_type ()));
|
||||
node->add_property ("mouse-mode", enum2str(mouse_mode));
|
||||
node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
|
||||
node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
|
||||
|
||||
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
|
||||
if (act) {
|
||||
|
|
@ -2752,23 +2759,44 @@ Editor::setup_toolbar ()
|
|||
mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
|
||||
mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
|
||||
// internal_edit_button.set_relief(Gtk::RELIEF_NONE);
|
||||
join_object_range_button.set_relief(Gtk::RELIEF_NONE);
|
||||
|
||||
HBox* mode_box = manage(new HBox);
|
||||
mode_box->set_border_width (2);
|
||||
mode_box->set_spacing(4);
|
||||
mouse_mode_button_box.set_spacing(1);
|
||||
mouse_mode_button_box.pack_start(mouse_move_button, true, true);
|
||||
if (!Profile->get_sae()) {
|
||||
mouse_mode_button_box.pack_start(mouse_select_button, true, true);
|
||||
|
||||
/* table containing mode buttons */
|
||||
|
||||
Table* mouse_mode_button_table = manage (new Table (Profile->get_sae() ? 4 : 6, 2));
|
||||
|
||||
int c = 0;
|
||||
|
||||
if (Profile->get_sae()) {
|
||||
mouse_mode_button_table->attach (mouse_move_button, c, c + 1, 0, 1);
|
||||
++c;
|
||||
} else {
|
||||
mouse_mode_button_table->attach (mouse_move_button, c, c + 1, 0, 1);
|
||||
mouse_mode_button_table->attach (mouse_select_button, c + 1, c + 2, 0, 1);
|
||||
mouse_mode_button_table->attach (join_object_range_button, c, c + 2, 1, 2);
|
||||
c += 2;
|
||||
}
|
||||
mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
|
||||
|
||||
mouse_mode_button_table->attach (mouse_zoom_button, c, c + 1, 0, 1);
|
||||
++c;
|
||||
|
||||
if (!Profile->get_sae()) {
|
||||
mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
|
||||
mouse_mode_button_table->attach (mouse_gain_button, c, c + 1, 0, 1);
|
||||
++c;
|
||||
}
|
||||
mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
|
||||
mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
|
||||
mouse_mode_button_box.pack_start(internal_edit_button, true, true);
|
||||
mouse_mode_button_box.set_homogeneous(true);
|
||||
|
||||
mouse_mode_button_table->attach (mouse_timefx_button, c, c + 1, 0, 1);
|
||||
++c;
|
||||
|
||||
mouse_mode_button_table->attach (mouse_audition_button, c, c + 1, 0, 1);
|
||||
++c;
|
||||
|
||||
mouse_mode_button_table->attach (internal_edit_button, c, c + 1, 0, 1);
|
||||
++c;
|
||||
|
||||
vector<string> edit_mode_strings;
|
||||
edit_mode_strings.push_back (edit_mode_to_string (Slide));
|
||||
|
|
@ -2781,8 +2809,8 @@ Editor::setup_toolbar ()
|
|||
set_popdown_strings (edit_mode_selector, edit_mode_strings, true);
|
||||
edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
|
||||
|
||||
mode_box->pack_start(edit_mode_selector);
|
||||
mode_box->pack_start(mouse_mode_button_box);
|
||||
mode_box->pack_start (edit_mode_selector);
|
||||
mode_box->pack_start (*mouse_mode_button_table);
|
||||
|
||||
mouse_mode_tearoff = manage (new TearOff (*mode_box));
|
||||
mouse_mode_tearoff->set_name ("MouseModeBase");
|
||||
|
|
@ -2807,6 +2835,7 @@ Editor::setup_toolbar ()
|
|||
mouse_zoom_button.set_mode (false);
|
||||
mouse_timefx_button.set_mode (false);
|
||||
mouse_audition_button.set_mode (false);
|
||||
join_object_range_button.set_mode (false);
|
||||
|
||||
mouse_move_button.set_name ("MouseModeButton");
|
||||
mouse_select_button.set_name ("MouseModeButton");
|
||||
|
|
@ -2814,8 +2843,8 @@ Editor::setup_toolbar ()
|
|||
mouse_zoom_button.set_name ("MouseModeButton");
|
||||
mouse_timefx_button.set_name ("MouseModeButton");
|
||||
mouse_audition_button.set_name ("MouseModeButton");
|
||||
|
||||
internal_edit_button.set_name ("MouseModeButton");
|
||||
join_object_range_button.set_name ("MouseModeButton");
|
||||
|
||||
mouse_move_button.unset_flags (CAN_FOCUS);
|
||||
mouse_select_button.unset_flags (CAN_FOCUS);
|
||||
|
|
@ -2824,6 +2853,7 @@ Editor::setup_toolbar ()
|
|||
mouse_timefx_button.unset_flags (CAN_FOCUS);
|
||||
mouse_audition_button.unset_flags (CAN_FOCUS);
|
||||
internal_edit_button.unset_flags (CAN_FOCUS);
|
||||
join_object_range_button.unset_flags (CAN_FOCUS);
|
||||
|
||||
/* Zoom */
|
||||
|
||||
|
|
|
|||
|
|
@ -487,6 +487,19 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
|||
|
||||
Editing::MouseMode mouse_mode;
|
||||
bool _internal_editing;
|
||||
Editing::MouseMode effective_mouse_mode () const;
|
||||
|
||||
enum JoinObjectRangeState {
|
||||
JOIN_OBJECT_RANGE_NONE,
|
||||
/** `join object/range' mode is active and the mouse is over a place where object mode should happen */
|
||||
JOIN_OBJECT_RANGE_OBJECT,
|
||||
/** `join object/range' mode is active and the mouse is over a place where range mode should happen */
|
||||
JOIN_OBJECT_RANGE_RANGE
|
||||
};
|
||||
|
||||
JoinObjectRangeState _join_object_range_state;
|
||||
|
||||
void update_join_object_range_location (double, double);
|
||||
|
||||
int post_maximal_editor_width;
|
||||
int post_maximal_pane_position;
|
||||
|
|
@ -594,6 +607,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
|||
void collect_new_region_view (RegionView *);
|
||||
void collect_and_select_new_region_view (RegionView *);
|
||||
|
||||
void select_range_around_region (RegionView *);
|
||||
|
||||
Gtk::Menu track_context_menu;
|
||||
Gtk::Menu track_region_context_menu;
|
||||
Gtk::Menu track_selection_context_menu;
|
||||
|
|
@ -1492,7 +1507,6 @@ public:
|
|||
Gtk::Table toolbar_selection_clock_table;
|
||||
Gtk::Label toolbar_selection_cursor_label;
|
||||
|
||||
Gtk::HBox mouse_mode_button_box;
|
||||
Gtkmm2ext::TearOff* mouse_mode_tearoff;
|
||||
Gtk::ToggleButton mouse_select_button;
|
||||
Gtk::ToggleButton mouse_move_button;
|
||||
|
|
@ -1500,6 +1514,7 @@ public:
|
|||
Gtk::ToggleButton mouse_zoom_button;
|
||||
Gtk::ToggleButton mouse_timefx_button;
|
||||
Gtk::ToggleButton mouse_audition_button;
|
||||
Gtk::ToggleButton join_object_range_button;
|
||||
|
||||
void mouse_mode_toggled (Editing::MouseMode m);
|
||||
bool ignore_mouse_mode_toggle;
|
||||
|
|
|
|||
|
|
@ -683,7 +683,11 @@ Editor::register_actions ()
|
|||
mouse_select_button.set_name ("MouseModeButton");
|
||||
mouse_select_button.get_image ()->show ();
|
||||
|
||||
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-gain", _("Gain Tool"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
|
||||
join_object_range_button.set_image (*(manage (new Image (::get_icon ("join_tools")))));
|
||||
join_object_range_button.set_name ("MouseModeButton");
|
||||
join_object_range_button.get_image()->show ();
|
||||
|
||||
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-gain", _("Gain Tool"), sigc::bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
|
||||
act->connect_proxy (mouse_gain_button);
|
||||
mouse_gain_button.set_image (*(manage (new Image (::get_icon("tool_gain")))));
|
||||
mouse_gain_button.set_label ("");
|
||||
|
|
|
|||
|
|
@ -265,7 +265,6 @@ Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, Reg
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
switch (event->type) {
|
||||
case GDK_BUTTON_PRESS:
|
||||
case GDK_2BUTTON_PRESS:
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include "canvas-note.h"
|
||||
#include "selection.h"
|
||||
#include "midi_selection.h"
|
||||
#include "automation_time_axis.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
|
|
@ -2466,15 +2467,12 @@ ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
|
|||
// the point doesn't 'jump' to the mouse after the first drag
|
||||
_time_axis_view_grab_x = _point->get_x();
|
||||
_time_axis_view_grab_y = _point->get_y();
|
||||
nframes64_t grab_frame = _editor->pixel_to_frame (_time_axis_view_grab_x);
|
||||
|
||||
_point->line().parent_group().i2w (_time_axis_view_grab_x, _time_axis_view_grab_y);
|
||||
_editor->track_canvas->w2c (_time_axis_view_grab_x, _time_axis_view_grab_y, _time_axis_view_grab_x, _time_axis_view_grab_y);
|
||||
float const fraction = 1 - (_point->get_y() / _point->line().height());
|
||||
|
||||
_time_axis_view_grab_frame = _editor->pixel_to_frame (_time_axis_view_grab_x);
|
||||
_point->line().start_drag_single (_point, grab_frame, fraction);
|
||||
|
||||
_point->line().start_drag (_point, _time_axis_view_grab_frame, 0);
|
||||
|
||||
float fraction = 1.0 - (_point->get_y() / _point->line().height());
|
||||
_editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
|
||||
event->button.x + 10, event->button.y + 10);
|
||||
|
||||
|
|
@ -2492,18 +2490,16 @@ ControlPointDrag::motion (GdkEvent* event, bool)
|
|||
dy *= 0.1;
|
||||
}
|
||||
|
||||
/* coordinate in TimeAxisView's space */
|
||||
double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
|
||||
double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
|
||||
|
||||
// calculate zero crossing point. back off by .01 to stay on the
|
||||
// positive side of zero
|
||||
double _unused = 0;
|
||||
double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
|
||||
_point->line().parent_group().i2w(_unused, zero_gain_y);
|
||||
double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
|
||||
|
||||
// make sure we hit zero when passing through
|
||||
if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
|
||||
or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
|
||||
if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
|
||||
cy = zero_gain_y;
|
||||
}
|
||||
|
||||
|
|
@ -2517,13 +2513,10 @@ ControlPointDrag::motion (GdkEvent* event, bool)
|
|||
_cumulative_x_drag = cx - _time_axis_view_grab_x;
|
||||
_cumulative_y_drag = cy - _time_axis_view_grab_y;
|
||||
|
||||
_point->line().parent_group().w2i (cx, cy);
|
||||
|
||||
cx = max (0.0, cx);
|
||||
cy = max (0.0, cy);
|
||||
cy = min ((double) _point->line().height(), cy);
|
||||
|
||||
//translate cx to frames
|
||||
nframes64_t cx_frames = _editor->unit_to_frame (cx);
|
||||
|
||||
if (!_x_constrained) {
|
||||
|
|
@ -2534,7 +2527,7 @@ ControlPointDrag::motion (GdkEvent* event, bool)
|
|||
|
||||
bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
|
||||
|
||||
_point->line().point_drag (*_point, cx_frames, fraction, push);
|
||||
_point->line().drag_motion (cx_frames, fraction, push);
|
||||
|
||||
_editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
|
||||
}
|
||||
|
|
@ -2553,7 +2546,7 @@ ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
|
|||
} else {
|
||||
motion (event, false);
|
||||
}
|
||||
_point->line().end_drag (_point);
|
||||
_point->line().end_drag ();
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -2594,7 +2587,10 @@ LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
|
|||
|
||||
nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
|
||||
|
||||
if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
|
||||
uint32_t before;
|
||||
uint32_t after;
|
||||
|
||||
if (!_line->control_points_adjacent (frame_within_region, before, after)) {
|
||||
/* no adjacent points */
|
||||
return;
|
||||
}
|
||||
|
|
@ -2608,7 +2604,7 @@ LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
|
|||
|
||||
double fraction = 1.0 - (cy / _line->height());
|
||||
|
||||
_line->start_drag (0, grab_frame(), fraction);
|
||||
_line->start_drag_line (before, after, fraction);
|
||||
|
||||
_editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
|
||||
event->button.x + 10, event->button.y + 10);
|
||||
|
|
@ -2642,7 +2638,8 @@ LineDrag::motion (GdkEvent* event, bool)
|
|||
push = true;
|
||||
}
|
||||
|
||||
_line->line_drag (_before, _after, fraction, push);
|
||||
/* we are ignoring x position for this drag, so we can just pass in 0 */
|
||||
_line->drag_motion (0, fraction, push);
|
||||
|
||||
_editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
|
||||
}
|
||||
|
|
@ -2651,7 +2648,7 @@ void
|
|||
LineDrag::finished (GdkEvent* event, bool)
|
||||
{
|
||||
motion (event, false);
|
||||
_line->end_drag (0);
|
||||
_line->end_drag ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2850,6 +2847,8 @@ SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
|
|||
: Drag (e, i)
|
||||
, _operation (o)
|
||||
, _copy (false)
|
||||
, _original_pointer_time_axis (-1)
|
||||
, _last_pointer_time_axis (-1)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -2909,6 +2908,8 @@ SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
|
|||
} else {
|
||||
_editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
|
||||
}
|
||||
|
||||
_original_pointer_time_axis = _editor->trackview_by_y_position (current_pointer_y ()).first->order ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2918,13 +2919,16 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
|
|||
nframes64_t end = 0;
|
||||
nframes64_t length;
|
||||
|
||||
pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (current_pointer_y ());
|
||||
if (pending_time_axis.first == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
nframes64_t const pending_position = adjusted_current_frame (event);
|
||||
|
||||
/* only alter selection if the current frame is
|
||||
different from the last frame position (adjusted)
|
||||
*/
|
||||
/* only alter selection if things have changed */
|
||||
|
||||
if (pending_position == last_pointer_frame()) {
|
||||
if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2969,8 +2973,36 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
|
|||
_editor->clicked_selection = _editor->selection->set (start, end);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* select the track that we're in */
|
||||
if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
|
||||
_editor->selection->add (pending_time_axis.first);
|
||||
_added_time_axes.push_back (pending_time_axis.first);
|
||||
}
|
||||
|
||||
/* deselect any tracks that this drag no longer includes, being careful to only deselect
|
||||
tracks that we selected in the first place.
|
||||
*/
|
||||
|
||||
int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
|
||||
int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
|
||||
|
||||
list<TimeAxisView*>::iterator i = _added_time_axes.begin();
|
||||
while (i != _added_time_axes.end()) {
|
||||
|
||||
list<TimeAxisView*>::iterator tmp = i;
|
||||
++tmp;
|
||||
|
||||
if ((*i)->order() < min_order || (*i)->order() > max_order) {
|
||||
_editor->selection->remove (*i);
|
||||
_added_time_axes.remove (*i);
|
||||
}
|
||||
|
||||
i = tmp;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case SelectionStartTrim:
|
||||
|
||||
|
|
@ -3490,3 +3522,96 @@ NoteDrag::finished (GdkEvent* ev, bool moved)
|
|||
region->note_dropped (cnote, drag_delta_x, drag_delta_note);
|
||||
}
|
||||
}
|
||||
|
||||
AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
|
||||
: Drag (e, i)
|
||||
, _ranges (r)
|
||||
, _nothing_to_drag (false)
|
||||
{
|
||||
_atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
|
||||
assert (_atav);
|
||||
|
||||
_line = _atav->line ();
|
||||
}
|
||||
|
||||
void
|
||||
AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
|
||||
{
|
||||
Drag::start_grab (event, cursor);
|
||||
|
||||
list<ControlPoint*> points;
|
||||
|
||||
XMLNode* state = &_line->get_state ();
|
||||
|
||||
if (_ranges.empty()) {
|
||||
|
||||
uint32_t const N = _line->npoints ();
|
||||
for (uint32_t i = 0; i < N; ++i) {
|
||||
points.push_back (_line->nth (i));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
boost::shared_ptr<AutomationList> the_list = _line->the_list ();
|
||||
for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
|
||||
the_list->add (j->start, the_list->eval (j->start));
|
||||
_line->add_always_in_view (j->start);
|
||||
the_list->add (j->start + 1, the_list->eval (j->start + 1));
|
||||
_line->add_always_in_view (j->start + 1);
|
||||
the_list->add (j->end - 1, the_list->eval (j->end - 1));
|
||||
_line->add_always_in_view (j->end - 1);
|
||||
the_list->add (j->end, the_list->eval (j->end));
|
||||
_line->add_always_in_view (j->end);
|
||||
}
|
||||
|
||||
uint32_t const N = _line->npoints ();
|
||||
AutomationList::const_iterator j = the_list->begin ();
|
||||
for (uint32_t i = 0; i < N; ++i) {
|
||||
|
||||
ControlPoint* p = _line->nth (i);
|
||||
|
||||
list<AudioRange>::const_iterator k = _ranges.begin ();
|
||||
while (k != _ranges.end() && (k->start >= (*j)->when || k->end <= (*j)->when)) {
|
||||
++k;
|
||||
}
|
||||
|
||||
if (k != _ranges.end()) {
|
||||
points.push_back (p);
|
||||
}
|
||||
|
||||
++j;
|
||||
}
|
||||
}
|
||||
|
||||
if (points.empty()) {
|
||||
_nothing_to_drag = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_line->start_drag_multiple (points, 1 - (current_pointer_y() / _line->height ()), state);
|
||||
}
|
||||
|
||||
void
|
||||
AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
|
||||
{
|
||||
if (_nothing_to_drag) {
|
||||
return;
|
||||
}
|
||||
|
||||
float const f = 1 - (current_pointer_y() / _line->height());
|
||||
|
||||
/* we are ignoring x position for this drag, so we can just pass in 0 */
|
||||
_line->drag_motion (0, f, false);
|
||||
}
|
||||
|
||||
void
|
||||
AutomationRangeDrag::finished (GdkEvent* event, bool)
|
||||
{
|
||||
if (_nothing_to_drag) {
|
||||
return;
|
||||
}
|
||||
|
||||
motion (event, false);
|
||||
_line->end_drag ();
|
||||
_line->clear_always_in_view ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -474,7 +474,6 @@ private:
|
|||
ControlPoint* _point;
|
||||
double _time_axis_view_grab_x;
|
||||
double _time_axis_view_grab_y;
|
||||
nframes64_t _time_axis_view_grab_frame;
|
||||
double _cumulative_x_drag;
|
||||
double _cumulative_y_drag;
|
||||
static double const _zero_gain_fraction;
|
||||
|
|
@ -537,7 +536,7 @@ public:
|
|||
void finished (GdkEvent *, bool);
|
||||
};
|
||||
|
||||
/** Drag in range select(gc_owner.get()) moAutomatable */
|
||||
/** Drag in range select mode */
|
||||
class SelectionDrag : public Drag
|
||||
{
|
||||
public:
|
||||
|
|
@ -557,6 +556,9 @@ public:
|
|||
private:
|
||||
Operation _operation;
|
||||
bool _copy;
|
||||
int _original_pointer_time_axis;
|
||||
int _last_pointer_time_axis;
|
||||
std::list<TimeAxisView*> _added_time_axes;
|
||||
};
|
||||
|
||||
/** Range marker drag */
|
||||
|
|
@ -583,16 +585,33 @@ private:
|
|||
bool _copy;
|
||||
};
|
||||
|
||||
/* Drag of rectangle to set zoom */
|
||||
/** Drag of rectangle to set zoom */
|
||||
class MouseZoomDrag : public Drag
|
||||
{
|
||||
public:
|
||||
MouseZoomDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
|
||||
MouseZoomDrag (Editor* e, ArdourCanvas::Item *i) : Drag (e, i) {}
|
||||
|
||||
void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
|
||||
void motion (GdkEvent *, bool);
|
||||
void finished (GdkEvent *, bool);
|
||||
};
|
||||
|
||||
/** Drag of a range of automation data, changing value but not position */
|
||||
class AutomationRangeDrag : public Drag
|
||||
{
|
||||
public:
|
||||
AutomationRangeDrag (Editor *, ArdourCanvas::Item *, std::list<ARDOUR::AudioRange> const &);
|
||||
|
||||
void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
|
||||
void motion (GdkEvent *, bool);
|
||||
void finished (GdkEvent *, bool);
|
||||
|
||||
private:
|
||||
std::list<ARDOUR::AudioRange> _ranges;
|
||||
AutomationTimeAxisView* _atav;
|
||||
boost::shared_ptr<AutomationLine> _line;
|
||||
bool _nothing_to_drag;
|
||||
};
|
||||
|
||||
#endif /* __gtk2_ardour_editor_drag_h_ */
|
||||
|
||||
|
|
|
|||
|
|
@ -134,13 +134,11 @@ Editor::event_frame (GdkEvent const * event, double* pcx, double* pcy) const
|
|||
case GDK_BUTTON_PRESS:
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
|
||||
*pcx = event->button.x;
|
||||
*pcy = event->button.y;
|
||||
_trackview_group->w2i(*pcx, *pcy);
|
||||
break;
|
||||
case GDK_MOTION_NOTIFY:
|
||||
|
||||
*pcx = event->motion.x;
|
||||
*pcy = event->motion.y;
|
||||
_trackview_group->w2i(*pcx, *pcy);
|
||||
|
|
@ -254,6 +252,17 @@ Editor::set_canvas_cursor ()
|
|||
}
|
||||
}
|
||||
|
||||
switch (_join_object_range_state) {
|
||||
case JOIN_OBJECT_RANGE_NONE:
|
||||
break;
|
||||
case JOIN_OBJECT_RANGE_OBJECT:
|
||||
current_canvas_cursor = which_grabber_cursor ();
|
||||
break;
|
||||
case JOIN_OBJECT_RANGE_RANGE:
|
||||
current_canvas_cursor = selector_cursor;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_drawable()) {
|
||||
track_canvas->get_window()->set_cursor(*current_canvas_cursor);
|
||||
}
|
||||
|
|
@ -315,9 +324,9 @@ Editor::mouse_mode_toggled (MouseMode m)
|
|||
|
||||
instant_save ();
|
||||
|
||||
if (mouse_mode != MouseRange) {
|
||||
if (mouse_mode != MouseRange && _join_object_range_state == JOIN_OBJECT_RANGE_NONE) {
|
||||
|
||||
/* in all modes except range, hide the range selection,
|
||||
/* in all modes except range and joined object/range, hide the range selection,
|
||||
show the object (region) selection.
|
||||
*/
|
||||
|
||||
|
|
@ -331,7 +340,7 @@ Editor::mouse_mode_toggled (MouseMode m)
|
|||
} else {
|
||||
|
||||
/*
|
||||
in range mode, show the range selection.
|
||||
in range or object/range mode, show the range selection.
|
||||
*/
|
||||
|
||||
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
||||
|
|
@ -416,6 +425,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
|
|||
*/
|
||||
|
||||
if (((mouse_mode != MouseObject) &&
|
||||
(_join_object_range_state != JOIN_OBJECT_RANGE_OBJECT) &&
|
||||
(mouse_mode != MouseAudition || item_type != RegionItem) &&
|
||||
(mouse_mode != MouseTimeFX || item_type != RegionItem) &&
|
||||
(mouse_mode != MouseGain) &&
|
||||
|
|
@ -445,16 +455,21 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
|
|||
|
||||
switch (item_type) {
|
||||
case RegionItem:
|
||||
if (mouse_mode != MouseRange) {
|
||||
if (mouse_mode != MouseRange || _join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) {
|
||||
set_selected_regionview_from_click (press, op, true);
|
||||
} else if (event->type == GDK_BUTTON_PRESS) {
|
||||
set_selected_track_as_side_effect ();
|
||||
selection->clear_tracks ();
|
||||
set_selected_track_as_side_effect (true);
|
||||
}
|
||||
if (_join_object_range_state == JOIN_OBJECT_RANGE_OBJECT && !selection->regions.empty()) {
|
||||
select_range_around_region (selection->regions.front());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RegionViewNameHighlight:
|
||||
case RegionViewName:
|
||||
if (mouse_mode != MouseRange) {
|
||||
if (mouse_mode != MouseRange || _join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) {
|
||||
set_selected_regionview_from_click (press, op, true);
|
||||
} else if (event->type == GDK_BUTTON_PRESS) {
|
||||
set_selected_track_as_side_effect ();
|
||||
|
|
@ -466,7 +481,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
|
|||
case FadeInItem:
|
||||
case FadeOutHandleItem:
|
||||
case FadeOutItem:
|
||||
if (mouse_mode != MouseRange) {
|
||||
if (mouse_mode != MouseRange || _join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) {
|
||||
set_selected_regionview_from_click (press, op, true);
|
||||
} else if (event->type == GDK_BUTTON_PRESS) {
|
||||
set_selected_track_as_side_effect ();
|
||||
|
|
@ -475,7 +490,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
|
|||
|
||||
case ControlPointItem:
|
||||
set_selected_track_as_side_effect ();
|
||||
if (mouse_mode != MouseRange) {
|
||||
if (mouse_mode != MouseRange || _join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) {
|
||||
set_selected_control_point_from_click (op, false);
|
||||
}
|
||||
break;
|
||||
|
|
@ -597,7 +612,9 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
break;
|
||||
}
|
||||
|
||||
switch (mouse_mode) {
|
||||
Editing::MouseMode eff = effective_mouse_mode ();
|
||||
|
||||
switch (eff) {
|
||||
case MouseRange:
|
||||
switch (item_type) {
|
||||
case StartSelectionTrimItem:
|
||||
|
|
@ -623,11 +640,21 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
_drag = new SelectionDrag (this, item, SelectionDrag::SelectionMove);
|
||||
_drag->start_grab (event);
|
||||
} else {
|
||||
/* this was debated, but decided the more common action was to
|
||||
make a new selection */
|
||||
assert (_drag == 0);
|
||||
_drag = new SelectionDrag (this, item, SelectionDrag::CreateSelection);
|
||||
_drag->start_grab (event);
|
||||
double const y = event->button.y + vertical_adjustment.get_value() - canvas_timebars_vsize;
|
||||
pair<TimeAxisView*, int> tvp = trackview_by_y_position (y);
|
||||
if (tvp.first) {
|
||||
AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (tvp.first);
|
||||
assert (_drag == 0);
|
||||
if (join_object_range_button.get_active() && atv) {
|
||||
/* smart "join" mode: drag automation */
|
||||
_drag = new AutomationRangeDrag (this, atv->base_item(), selection->time);
|
||||
} else {
|
||||
/* this was debated, but decided the more common action was to
|
||||
make a new selection */
|
||||
_drag = new SelectionDrag (this, item, SelectionDrag::CreateSelection);
|
||||
}
|
||||
_drag->start_grab (event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -734,14 +761,46 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
_drag = new RegionCreateDrag (this, item, clicked_axisview);
|
||||
_drag->start_grab (event);
|
||||
return true;
|
||||
} else {
|
||||
assert (_drag == 0);
|
||||
_drag = new RubberbandSelectDrag (this, item);
|
||||
_drag->start_grab (event);
|
||||
}
|
||||
/* fallthru */
|
||||
break;
|
||||
|
||||
case AutomationTrackItem:
|
||||
assert (_drag == 0);
|
||||
_drag = new RubberbandSelectDrag (this, item);
|
||||
|
||||
if (join_object_range_button.get_active()) {
|
||||
/* smart "join" mode: drag automation */
|
||||
_drag = new AutomationRangeDrag (this, item, selection->time);
|
||||
} else {
|
||||
/* otherwise: rubberband drag to select automation points */
|
||||
_drag = new RubberbandSelectDrag (this, item);
|
||||
}
|
||||
|
||||
_drag->start_grab (event);
|
||||
break;
|
||||
|
||||
case SelectionItem:
|
||||
{
|
||||
if (join_object_range_button.get_active()) {
|
||||
/* we're in "smart" joined mode, and we've clicked on a Selection; if we're
|
||||
* over an automation track, start a drag of its data */
|
||||
double const y = event->button.y + vertical_adjustment.get_value() - canvas_timebars_vsize;
|
||||
pair<TimeAxisView*, int> tvp = trackview_by_y_position (y);
|
||||
if (tvp.first) {
|
||||
AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (tvp.first);
|
||||
if (atv) {
|
||||
assert (_drag == 0);
|
||||
_drag = new AutomationRangeDrag (this, atv->base_item(), selection->time);
|
||||
_drag->start_grab (event);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef WITH_CMT
|
||||
case ImageFrameHandleStartItem:
|
||||
imageframe_start_handle_op(item, event) ;
|
||||
|
|
@ -878,7 +937,8 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
bool
|
||||
Editor::button_press_handler_2 (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
|
||||
{
|
||||
switch (mouse_mode) {
|
||||
Editing::MouseMode const eff = effective_mouse_mode ();
|
||||
switch (eff) {
|
||||
case MouseObject:
|
||||
switch (item_type) {
|
||||
case RegionItem:
|
||||
|
|
@ -1152,6 +1212,8 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
|
||||
/* delete events get handled here */
|
||||
|
||||
Editing::MouseMode const eff = effective_mouse_mode ();
|
||||
|
||||
if (_drag == 0 && Keyboard::is_delete_event (&event->button)) {
|
||||
|
||||
switch (item_type) {
|
||||
|
|
@ -1168,13 +1230,13 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
break;
|
||||
|
||||
case RegionItem:
|
||||
if (mouse_mode == MouseObject) {
|
||||
if (eff == MouseObject) {
|
||||
remove_clicked_region ();
|
||||
}
|
||||
break;
|
||||
|
||||
case ControlPointItem:
|
||||
if (mouse_mode == MouseGain) {
|
||||
if (eff == MouseGain) {
|
||||
remove_gain_control_point (item, event);
|
||||
} else {
|
||||
remove_control_point (item, event);
|
||||
|
|
@ -1233,7 +1295,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
break;
|
||||
}
|
||||
|
||||
switch (mouse_mode) {
|
||||
switch (eff) {
|
||||
case MouseObject:
|
||||
switch (item_type) {
|
||||
case AutomationTrackItem:
|
||||
|
|
@ -1305,7 +1367,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
|
||||
|
||||
case 2:
|
||||
switch (mouse_mode) {
|
||||
switch (eff) {
|
||||
|
||||
case MouseObject:
|
||||
switch (item_type) {
|
||||
|
|
@ -1348,7 +1410,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
}
|
||||
|
||||
bool
|
||||
Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* /*event*/, ItemType item_type)
|
||||
Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
|
||||
{
|
||||
ControlPoint* cp;
|
||||
Marker * marker;
|
||||
|
|
@ -1544,7 +1606,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* /*event*/, ItemType i
|
|||
}
|
||||
|
||||
bool
|
||||
Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* /*event*/, ItemType item_type)
|
||||
Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
|
||||
{
|
||||
AutomationLine* al;
|
||||
ControlPoint* cp;
|
||||
|
|
@ -1661,6 +1723,10 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* /*event*/, ItemType i
|
|||
break;
|
||||
}
|
||||
|
||||
if (item_type == RegionItem) {
|
||||
update_join_object_range_location (event->crossing.x, event->crossing.y);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1782,6 +1848,12 @@ Editor::motion_handler (ArdourCanvas::Item* /*item*/, GdkEvent* event, bool from
|
|||
return true;
|
||||
}
|
||||
|
||||
JoinObjectRangeState const old = _join_object_range_state;
|
||||
update_join_object_range_location (event->motion.x, event->motion.y);
|
||||
if (_join_object_range_state != old) {
|
||||
set_canvas_cursor ();
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
if (_drag) {
|
||||
handled = _drag->motion_handler (event, from_autoscroll);
|
||||
|
|
@ -2598,3 +2670,52 @@ Editor::set_internal_edit (bool yn)
|
|||
|
||||
|
||||
}
|
||||
|
||||
/** Update _join_object_range_state which indicate whether we are over the top or bottom half of a region view,
|
||||
* used by the `join object/range' tool mode.
|
||||
*/
|
||||
void
|
||||
Editor::update_join_object_range_location (double x, double y)
|
||||
{
|
||||
if (join_object_range_button.get_active() == false || (mouse_mode != MouseRange && mouse_mode != MouseObject)) {
|
||||
_join_object_range_state = JOIN_OBJECT_RANGE_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (entered_regionview) {
|
||||
|
||||
double cx = x;
|
||||
double cy = y;
|
||||
entered_regionview->get_canvas_group()->w2i (cx, cy);
|
||||
|
||||
double x1;
|
||||
double y1;
|
||||
double x2;
|
||||
double y2;
|
||||
entered_regionview->get_canvas_group()->get_bounds (x1, y1, x2, y2);
|
||||
|
||||
bool const top_half = cy < (y2 - y1) / 2;
|
||||
|
||||
_join_object_range_state = top_half ? JOIN_OBJECT_RANGE_RANGE : JOIN_OBJECT_RANGE_OBJECT;
|
||||
|
||||
} else {
|
||||
|
||||
if (mouse_mode == MouseObject) {
|
||||
_join_object_range_state = JOIN_OBJECT_RANGE_OBJECT;
|
||||
} else if (mouse_mode == MouseRange) {
|
||||
_join_object_range_state = JOIN_OBJECT_RANGE_RANGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Editing::MouseMode
|
||||
Editor::effective_mouse_mode () const
|
||||
{
|
||||
if (_join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) {
|
||||
return MouseObject;
|
||||
} else if (_join_object_range_state == JOIN_OBJECT_RANGE_RANGE) {
|
||||
return MouseRange;
|
||||
}
|
||||
|
||||
return mouse_mode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,6 +171,9 @@ Editor::select_all_tracks ()
|
|||
selection->set (visible_views);
|
||||
}
|
||||
|
||||
/** Select clicked_routeview, unless there are no currently selected
|
||||
* tracks, in which case nothing will happen unless `force' is true.
|
||||
*/
|
||||
void
|
||||
Editor::set_selected_track_as_side_effect (bool force)
|
||||
{
|
||||
|
|
@ -1392,4 +1395,12 @@ Editor::deselect_all ()
|
|||
selection->clear ();
|
||||
}
|
||||
|
||||
void
|
||||
Editor::select_range_around_region (RegionView* rv)
|
||||
{
|
||||
selection->set (&rv->get_time_axis_view());
|
||||
|
||||
selection->time.clear ();
|
||||
boost::shared_ptr<Region> r = rv->region ();
|
||||
selection->set (r->position(), r->position() + r->length());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,9 +50,10 @@ AudioRegionGainLine::AudioRegionGainLine (const string & name, AudioRegionView&
|
|||
}
|
||||
|
||||
void
|
||||
AudioRegionGainLine::start_drag (ControlPoint* cp, nframes_t x, float fraction)
|
||||
AudioRegionGainLine::start_drag_single (ControlPoint* cp, nframes_t x, float fraction)
|
||||
{
|
||||
AutomationLine::start_drag (cp, x, fraction);
|
||||
AutomationLine::start_drag_single (cp, x, fraction);
|
||||
|
||||
if (!rv.audio_region()->envelope_active()) {
|
||||
trackview.session()->add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), &rv.audio_region()->get_state(), 0));
|
||||
rv.audio_region()->set_envelope_active(false);
|
||||
|
|
@ -85,13 +86,13 @@ AudioRegionGainLine::remove_point (ControlPoint& cp)
|
|||
}
|
||||
|
||||
void
|
||||
AudioRegionGainLine::end_drag (ControlPoint* cp)
|
||||
AudioRegionGainLine::end_drag ()
|
||||
{
|
||||
if (!rv.audio_region()->envelope_active()) {
|
||||
rv.audio_region()->set_envelope_active(true);
|
||||
trackview.session()->add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), 0, &rv.audio_region()->get_state()));
|
||||
}
|
||||
|
||||
AutomationLine::end_drag(cp);
|
||||
AutomationLine::end_drag ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ class AudioRegionGainLine : public AutomationLine
|
|||
public:
|
||||
AudioRegionGainLine (const std::string & name, AudioRegionView&, ArdourCanvas::Group& parent, boost::shared_ptr<ARDOUR::AutomationList>);
|
||||
|
||||
void start_drag (ControlPoint*, nframes_t x, float fraction);
|
||||
void end_drag (ControlPoint*);
|
||||
void start_drag_single (ControlPoint*, nframes_t x, float fraction);
|
||||
void end_drag ();
|
||||
|
||||
void remove_point (ControlPoint&);
|
||||
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ BasicUI::transport_play (bool from_last_start)
|
|||
}
|
||||
|
||||
if (session->get_play_range ()) {
|
||||
session->request_play_range (false);
|
||||
session->request_play_range (0);
|
||||
}
|
||||
|
||||
if (from_last_start && rolling) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue