merge fix
authorBen Loftis <ben@harrisonconsoles.com>
Thu, 16 Jul 2015 21:13:24 +0000 (16:13 -0500)
committerBen Loftis <ben@harrisonconsoles.com>
Thu, 16 Jul 2015 21:13:24 +0000 (16:13 -0500)
26 files changed:
gtk2_ardour/audio_region_view.cc
gtk2_ardour/audio_streamview.cc
gtk2_ardour/audio_streamview.h
gtk2_ardour/automation_controller.cc
gtk2_ardour/automation_line.cc
gtk2_ardour/automation_region_view.cc
gtk2_ardour/automation_time_axis.cc
gtk2_ardour/editor_canvas.cc
gtk2_ardour/editor_canvas_events.cc
gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_drag.h
gtk2_ardour/editor_mouse.cc
gtk2_ardour/editor_ops.cc
gtk2_ardour/editor_selection.cc
gtk2_ardour/editor_timefx.cc
gtk2_ardour/midi_time_axis.cc
gtk2_ardour/region_editor.cc
gtk2_ardour/route_time_axis.cc
libs/ardour/ardour/automation_control.h
libs/ardour/automation_control.cc
libs/ardour/automation_list.cc
libs/ardour/automation_watch.cc
libs/evoral/evoral/ControlList.hpp
libs/evoral/src/ControlList.cpp
libs/gtkmm2ext/gtkmm2ext/pixfader.h
libs/gtkmm2ext/pixfader.cc

index f9af7f98d29eb3aa5eacd10b6639afba239928ff..4f963a290df34a5867e66634e6dfb948aaf5e96d 100644 (file)
@@ -1261,7 +1261,7 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev, b
                trackview.session()->add_command (new MementoCommand<AudioRegion>(*(audio_region().get()), &region_before, &region_after));
        }
 
-       audio_region()->envelope()->add (fx, y, with_guard_points);
+       audio_region()->envelope()->editor_add (fx, y, with_guard_points);
 
        XMLNode &after = audio_region()->envelope()->get_state();
        trackview.session()->add_command (new MementoCommand<AutomationList>(*audio_region()->envelope().get(), &before, &after));
index 7951848c5959e226715f0e323b842a8bcca96c70..ed7bfc238d7da68e08db818dca00109840384204 100644 (file)
@@ -41,6 +41,7 @@
 #include "tape_region_view.h"
 #include "audio_time_axis.h"
 #include "region_selection.h"
+#include "region_gain_line.h"
 #include "selection.h"
 #include "public_editor.h"
 #include "ardour_ui.h"
@@ -471,3 +472,14 @@ AudioStreamView::color_handler ()
                }
        }
 }
+
+void
+AudioStreamView::set_selected_points (PointSelection& points)
+{
+       for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
+               AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
+               if (arv && arv->get_gain_line ()) {
+                       arv->get_gain_line ()->set_selected_points (points);
+               }
+       }
+}
index 8e9b095537d47e6f4e0d8725c9ec7b321f8be24c..443a39063b80d5a4dafce23efc81ec0a508e1ad1 100644 (file)
@@ -26,6 +26,7 @@
 #include <boost/weak_ptr.hpp>
 
 #include "ardour/location.h"
+#include "point_selection.h"
 #include "editing.h"
 #include "streamview.h"
 
@@ -61,6 +62,7 @@ class AudioStreamView : public StreamView
        std::pair<std::list<AudioRegionView*>, std::list<AudioRegionView*> > hide_xfades_with (boost::shared_ptr<ARDOUR::AudioRegion> ar);
 
        RegionView* create_region_view (boost::shared_ptr<ARDOUR::Region>, bool, bool);
+       void set_selected_points (PointSelection&);
 
   private:
        void setup_rec_box ();
index f57f2a737a81314f20ec9524f5f26d2875d86751..44c03159a4f2a84f0d4bb0bc5c02a55f4172b2bd 100644 (file)
@@ -204,7 +204,7 @@ AutomationController::toggled ()
                                _controllable->set_automation_state(Write);
                        }
                        if (_controllable->list()) {
-                               _controllable->list()->set_in_write_pass(true, false, _controllable->session().audible_frame());
+                               _controllable->list()->set_in_write_pass(true, true, _controllable->session().audible_frame());
                        }
                }
                const bool was_active = _controllable->get_value() >= 0.5;
index 069a82315508f8af9b5394d92ba1e54428b900b8..d0dc9337590f992ffbac163f0f51e6b6902f5dc0 100644 (file)
@@ -466,7 +466,6 @@ AutomationLine::string_to_fraction (string const & s) const
 void
 AutomationLine::start_drag_single (ControlPoint* cp, double x, float fraction)
 {
-       trackview.editor().begin_reversible_command (_("automation event move"));
        trackview.editor().session()->add_command (
                new MementoCommand<AutomationList> (memento_command_binder(), &get_state(), 0));
 
@@ -492,7 +491,6 @@ AutomationLine::start_drag_single (ControlPoint* cp, double x, float fraction)
 void
 AutomationLine::start_drag_line (uint32_t i1, uint32_t i2, float fraction)
 {
-       trackview.editor().begin_reversible_command (_("automation range move"));
        trackview.editor().session()->add_command (
                new MementoCommand<AutomationList> (memento_command_binder (), &get_state(), 0));
 
@@ -512,7 +510,6 @@ AutomationLine::start_drag_line (uint32_t i1, uint32_t i2, float fraction)
 void
 AutomationLine::start_drag_multiple (list<ControlPoint*> cp, float fraction, XMLNode* state)
 {
-       trackview.editor().begin_reversible_command (_("automation range move"));
        trackview.editor().session()->add_command (
                new MementoCommand<AutomationList> (memento_command_binder(), state, 0));
 
@@ -678,6 +675,7 @@ AutomationLine::drag_motion (double const x, float fraction, bool ignore_x, bool
                for (vector<CCP>::iterator ccp = contiguous_points.begin(); ccp != contiguous_points.end(); ++ccp) {
                        (*ccp)->compute_x_bounds (trackview.editor());
                }
+               _drag_had_movement = true;
        }       
 
        /* OK, now on to the stuff related to *this* motion event. First, for
@@ -738,7 +736,6 @@ AutomationLine::drag_motion (double const x, float fraction, bool ignore_x, bool
        _drag_distance += dx;
        _drag_x += dx;
        _last_drag_fraction = fraction;
-       _drag_had_movement = true;
        did_push = with_push;
 
        return pair<double, float> (_drag_x + dx, _last_drag_fraction + dy);
@@ -951,7 +948,8 @@ AutomationLine::set_selected_points (PointSelection const & points)
        set_colors ();
 }
 
-void AutomationLine::set_colors ()
+void
+AutomationLine::set_colors ()
 {
        set_line_color (ARDOUR_UI::config()->color ("automation line"));
        for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
index 7e330949de8b877d9b7a16867ad21f19b6a6fde8..b418d096f22e1e2c7726740b7af66b5efe54761b 100644 (file)
@@ -190,7 +190,7 @@ AutomationRegionView::add_automation_event (GdkEvent *, framepos_t when, double
        view->editor().begin_reversible_command (_("add automation event"));
        XMLNode& before = _line->the_list()->get_state();
 
-       _line->the_list()->add (when_d, y, with_guard_points, false);
+       _line->the_list()->editor_add (when_d, y, with_guard_points);
 
        XMLNode& after = _line->the_list()->get_state();
 
index 01f2ebb5140e13abd100a45a925219f87345ad8f..d5276e0cc511fd2acdd07a6d7f6e365dcef76bd7 100644 (file)
@@ -449,7 +449,7 @@ AutomationTimeAxisView::clear_clicked ()
        } else if (_view) {
                _view->clear ();
        }
-
+       set_automation_state ((AutoState) ARDOUR::Off);
        _editor.commit_reversible_command ();
        _session->set_dirty ();
 }
@@ -644,10 +644,10 @@ AutomationTimeAxisView::add_automation_event (GdkEvent* event, framepos_t when,
        _editor.begin_reversible_command (_("add automation event"));
        XMLNode& before = list->get_state();
 
-       list->add (when, y, with_guard_points);
+       list->editor_add (when, y, with_guard_points);
 
        XMLNode& after = list->get_state();
-       _session->add_command (new MementoCommand<ARDOUR::AutomationList> (*list, &before, &after));
+       _session->add_command (new MementoCommand<ARDOUR::AutomationList> (*list.get (), &before, &after));
        _editor.commit_reversible_command ();
        _session->set_dirty ();
 }
index 8e2f78fb93246fab8b7d80ae12b2a257d839159e..6413b6d6910de00031a27aecd6851676a0711b76 100644 (file)
@@ -1236,7 +1236,7 @@ Editor::which_canvas_cursor(ItemType type) const
                        cursor = _cursors->fader;
                        break;
                case GainLineItem:
-                       cursor = which_track_cursor ();
+                       cursor = _cursors->cross_hair;
                        break;
                case AutomationLineItem:
                        cursor = _cursors->cross_hair;
index 8af5389e7066e62e46fac758409f8304277ed1fd..92ebbd976d3c85c77f908a4c33e5003baf43af9f 100644 (file)
@@ -695,6 +695,11 @@ Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, Automation
                type = AutomationLineItem;
        }
 
+       clicked_control_point = 0;
+       clicked_axisview = &al->trackview;
+       clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
+       clicked_regionview = 0;
+
        return typed_event (item, event, type);
 }
 
index 99b8ff628385fc1a8566729ea84e2ab37075d992..0877a8b4bece9185ba597f640c58833e598969c0 100644 (file)
@@ -617,6 +617,11 @@ RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
                assert(_last_pointer_time_axis_view >= 0);
                _last_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
        }
+
+       if (_brushing) {
+               /* cross track dragging seems broken here. disabled for now. */
+               _y_constrained = true;
+       }
 }
 
 double
@@ -1221,13 +1226,13 @@ void
 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
 {
        if (_copy && first_move) {
-
-               if (_x_constrained) {
+               if (_x_constrained && !_brushing) {
                        _editor->begin_reversible_command (Operations::fixed_time_region_copy);
-               } else {
+               } else if (!_brushing) {
                        _editor->begin_reversible_command (Operations::region_copy);
+               } else if (_brushing) {
+                       _editor->begin_reversible_command (Operations::drag_region_brush);
                }
-
                /* duplicate the regionview(s) and region(s) */
 
                list<DraggingView> new_regionviews;
@@ -1285,14 +1290,14 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move)
                }
 
        } else if (!_copy && first_move) {
-
-               if (_x_constrained) {
+               if (_x_constrained && !_brushing) {
                        _editor->begin_reversible_command (_("fixed time region drag"));
-               } else {
+               } else if (!_brushing) {
                        _editor->begin_reversible_command (Operations::region_drag);
+               } else if (_brushing) {
+                       _editor->begin_reversible_command (Operations::drag_region_brush);
                }
        }
-
        RegionMotionDrag::motion (event, first_move);
 }
 
@@ -1500,12 +1505,6 @@ RegionMoveDrag::finished_no_copy (
        set<RouteTimeAxisView*> views_to_update;
        RouteTimeAxisView* new_time_axis_view = 0;
 
-       if (_brushing) {
-               /* all changes were made during motion event handlers */
-               _editor->commit_reversible_command ();
-               return;
-       }
-
        typedef map<boost::shared_ptr<Playlist>, RouteTimeAxisView*> PlaylistMapping;
        PlaylistMapping playlist_mapping;
 
@@ -1619,7 +1618,6 @@ RegionMoveDrag::finished_no_copy (
                        }
 
                        rv->region()->set_position (where);
-
                        _editor->session()->add_command (new StatefulDiffCommand (rv->region()));
                }
 
@@ -1668,7 +1666,7 @@ RegionMoveDrag::finished_no_copy (
 
        /* write commands for the accumulated diffs for all our modified playlists */
        add_stateful_diff_commands_for_playlists (modified_playlists);
-
+       /* applies to _brushing */
        _editor->commit_reversible_command ();
 
        /* We have futzed with the layering of canvas items on our streamviews.
@@ -2334,6 +2332,8 @@ RegionCreateDrag::aborted (bool)
 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
        : Drag (e, i)
        , region (0)
+       , relative (false)
+       , at_front (true)
        , _snap_delta (0)
 {
        DEBUG_TRACE (DEBUG::Drags, "New NoteResizeDrag\n");
@@ -2370,37 +2370,36 @@ NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*ignored*/)
        } else {
                relative = true;
        }
-
        MidiRegionSelection& ms (_editor->get_selection().midi_regions);
-
        if (ms.size() > 1) {
                /* has to be relative, may make no sense otherwise */
                relative = true;
        }
-
        /* select this note; if it is already selected, preserve the existing selection,
           otherwise make this note the only one selected.
        */
        region->note_selected (cnote, cnote->selected ());
-
-       _editor->begin_reversible_command (_("resize notes"));
-
-       for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
-               MidiRegionSelection::iterator next;
-               next = r;
-               ++next;
-               MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*r);
-               if (mrv) {
-                       mrv->begin_resizing (at_front);
-               }
-               r = next;
-       }
 }
 
 void
-NoteResizeDrag::motion (GdkEvent* event, bool /*first_move*/)
+NoteResizeDrag::motion (GdkEvent* event, bool first_move)
 {
        MidiRegionSelection& ms (_editor->get_selection().midi_regions);
+       if (first_move) {
+               _editor->begin_reversible_command (_("resize notes"));
+
+               for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
+                       MidiRegionSelection::iterator next;
+                       next = r;
+                       ++next;
+                       MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*r);
+                       if (mrv) {
+                               mrv->begin_resizing (at_front);
+                       }
+                       r = next;
+               }
+       }
+
        for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
                NoteBase* nb = reinterpret_cast<NoteBase*> (_item->get_data ("notebase"));
                assert (nb);
@@ -2434,8 +2433,12 @@ NoteResizeDrag::motion (GdkEvent* event, bool /*first_move*/)
 }
 
 void
-NoteResizeDrag::finished (GdkEvent* event, bool /*movement_occurred*/)
+NoteResizeDrag::finished (GdkEvent* event, bool movement_occurred)
 {
+       if (!movement_occurred) {
+               return;
+       }
+
        MidiRegionSelection& ms (_editor->get_selection().midi_regions);
        for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
                NoteBase* nb = reinterpret_cast<NoteBase*> (_item->get_data ("notebase"));
@@ -2458,9 +2461,11 @@ NoteResizeDrag::finished (GdkEvent* event, bool /*movement_occurred*/)
                                        }
                                }
                        }
+
                        if (apply_snap_delta) {
                                sd = _snap_delta;
                        }
+
                        mrv->commit_resizing (nb, at_front, _drags->current_pointer_x() - grab_x(), relative, sd, snap);
                }
        }
@@ -3479,7 +3484,7 @@ FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
                fade_length = pos - region->position();
        }
 
-       _editor->begin_reversible_command (_("change fade in length"));
+       bool in_command = false;
 
        for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
 
@@ -3495,11 +3500,17 @@ FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
                tmp->audio_region()->set_fade_in_length (fade_length);
                tmp->audio_region()->set_fade_in_active (true);
 
+               if (!in_command) {
+                       _editor->begin_reversible_command (_("change fade in length"));
+                       in_command = true;
+               }
                XMLNode &after = alist->get_state();
                _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
        }
 
-       _editor->commit_reversible_command ();
+       if (in_command) {
+               _editor->commit_reversible_command ();
+       }
 }
 
 void
@@ -3598,7 +3609,7 @@ FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
                fade_length = region->last_frame() - pos;
        }
 
-       _editor->begin_reversible_command (_("change fade out length"));
+       bool in_command = false;
 
        for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
 
@@ -3614,11 +3625,17 @@ FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
                tmp->audio_region()->set_fade_out_length (fade_length);
                tmp->audio_region()->set_fade_out_active (true);
 
+               if (!in_command) {
+                       _editor->begin_reversible_command (_("change fade out length"));
+                       in_command = false;
+               }
                XMLNode &after = alist->get_state();
                _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
        }
 
-       _editor->commit_reversible_command ();
+       if (in_command) {
+               _editor->commit_reversible_command ();
+       }
 }
 
 void
@@ -3952,8 +3969,8 @@ MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
 
        _editor->_dragging_edit_point = false;
 
-       _editor->begin_reversible_command ( _("move marker") );
        XMLNode &before = _editor->session()->locations()->get_state();
+       bool in_command = false;
 
        MarkerSelection::iterator i;
        CopiedLocationInfo::iterator x;
@@ -3968,9 +3985,12 @@ MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
                if (location) {
 
                        if (location->locked()) {
-                               return;
+                               continue;
+                       }
+                       if (!in_command) {
+                               _editor->begin_reversible_command ( _("move marker") );
+                               in_command = true;
                        }
-
                        if (location->is_mark()) {
                                location->set_start (((*x).location)->start());
                        } else {
@@ -3979,9 +3999,11 @@ MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
                }
        }
 
-       XMLNode &after = _editor->session()->locations()->get_state();
-       _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
-       _editor->commit_reversible_command ();
+       if (in_command) {
+               XMLNode &after = _editor->session()->locations()->get_state();
+               _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
+               _editor->commit_reversible_command ();
+       }
 }
 
 void
@@ -4044,9 +4066,6 @@ ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
        setup_snap_delta (pos);
 
        float const fraction = 1 - (_point->get_y() / _point->line().height());
-
-       _point->line().start_drag_single (_point, _fixed_grab_x, fraction);
-
        show_verbose_cursor_text (_point->line().get_verbose_cursor_string (fraction));
 
        _pushing = Keyboard::modifier_state_equals (event->button.state, ArdourKeyboard::push_points_modifier ());
@@ -4057,7 +4076,7 @@ ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
 }
 
 void
-ControlPointDrag::motion (GdkEvent* event, bool)
+ControlPointDrag::motion (GdkEvent* event, bool first_motion)
 {
        double dx = _drags->current_pointer_x() - last_pointer_x();
        double dy = current_pointer_y() - last_pointer_y();
@@ -4076,11 +4095,6 @@ ControlPointDrag::motion (GdkEvent* event, bool)
        // positive side of zero
        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 && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
-               cy = zero_gain_y;
-       }
-
        if (_x_constrained) {
                cx = _fixed_grab_x;
        }
@@ -4091,6 +4105,11 @@ ControlPointDrag::motion (GdkEvent* event, bool)
        _cumulative_x_drag = cx - _fixed_grab_x;
        _cumulative_y_drag = cy - _fixed_grab_y;
 
+       // make sure we hit zero when passing through
+       if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
+               cy = zero_gain_y;
+       }
+
        cx = max (0.0, cx);
        cy = max (0.0, cy);
        cy = min ((double) _point->line().height(), cy);
@@ -4106,6 +4125,11 @@ ControlPointDrag::motion (GdkEvent* event, bool)
 
        float const fraction = 1.0 - (cy / _point->line().height());
 
+       if (first_motion) {
+               _editor->begin_reversible_command (_("automation event move"));
+               _point->line().start_drag_single (_point, _fixed_grab_x, fraction);
+       }
+
        _point->line().drag_motion (_editor->sample_to_pixel_unrounded (cx_frames), fraction, false, _pushing, _final_index);
 
        show_verbose_cursor_text (_point->line().get_verbose_cursor_string (fraction));
@@ -4123,10 +4147,9 @@ ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
 
        } else {
                motion (event, false);
+               _point->line().end_drag (_pushing, _final_index);
+               _editor->commit_reversible_command ();
        }
-
-       _point->line().end_drag (_pushing, _final_index);
-       _editor->commit_reversible_command ();
 }
 
 void
@@ -4151,6 +4174,8 @@ LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
        : Drag (e, i)
        , _line (0)
        , _cumulative_y_drag (0)
+       , _before (0)
+       , _after (0)
 {
        DEBUG_TRACE (DEBUG::Drags, "New LineDrag\n");
 }
@@ -4174,10 +4199,7 @@ LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
 
        framecnt_t const frame_within_region = (framecnt_t) floor (cx * _editor->samples_per_pixel);
 
-       uint32_t before;
-       uint32_t after;
-
-       if (!_line->control_points_adjacent (frame_within_region, before, after)) {
+       if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
                /* no adjacent points */
                return;
        }
@@ -4191,13 +4213,11 @@ LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
 
        double fraction = 1.0 - (cy / _line->height());
 
-       _line->start_drag_line (before, after, fraction);
-
        show_verbose_cursor_text (_line->get_verbose_cursor_string (fraction));
 }
 
 void
-LineDrag::motion (GdkEvent* event, bool)
+LineDrag::motion (GdkEvent* event, bool first_move)
 {
        double dy = current_pointer_y() - last_pointer_y();
 
@@ -4215,6 +4235,11 @@ LineDrag::motion (GdkEvent* event, bool)
        double const fraction = 1.0 - (cy / _line->height());
        uint32_t ignored;
 
+       if (first_move) {
+               _editor->begin_reversible_command (_("automation range move"));
+               _line->start_drag_line (_before, _after, fraction);
+       }
+
        /* we are ignoring x position for this drag, so we can just pass in anything */
        _line->drag_motion (0, fraction, true, false, ignored);
 
@@ -4227,20 +4252,17 @@ LineDrag::finished (GdkEvent* event, bool movement_occured)
        if (movement_occured) {
                motion (event, false);
                _line->end_drag (false, 0);
+               _editor->commit_reversible_command ();
        } else {
                /* add a new control point on the line */
 
                AutomationTimeAxisView* atv;
 
-               _line->end_drag (false, 0);
-
                if ((atv = dynamic_cast<AutomationTimeAxisView*>(_editor->clicked_axisview)) != 0) {
                        framepos_t where = _editor->window_event_sample (event, 0, 0);
                        atv->add_automation_event (event, where, event->button.y, false);
                }
        }
-
-       _editor->commit_reversible_command ();
 }
 
 void
@@ -5525,8 +5547,8 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
                                double const p = j->line->time_converter().from (i->start - j->line->time_converter().origin_b ());
                                double const q = j->line->time_converter().from (a - j->line->time_converter().origin_b ());
 
-                               the_list->editor_add (p, value (the_list, p));
-                               the_list->editor_add (q, value (the_list, q));
+                               the_list->editor_add (p, value (the_list, p), false);
+                               the_list->editor_add (q, value (the_list, q), false);
                        }
 
                        /* same thing for the end */
@@ -5551,8 +5573,8 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
                                double const p = j->line->time_converter().from (b - j->line->time_converter().origin_b ());
                                double const q = j->line->time_converter().from (i->end - j->line->time_converter().origin_b ());
 
-                               the_list->editor_add (p, value (the_list, p));
-                               the_list->editor_add (q, value (the_list, q));
+                               the_list->editor_add (p, value (the_list, p), false);
+                               the_list->editor_add (q, value (the_list, q), false);
                        }
                }
 
@@ -5589,19 +5611,22 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
        if (_nothing_to_drag) {
                return;
        }
-
-       for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
-               i->line->start_drag_multiple (i->points, y_fraction (i->line, current_pointer_y()), i->state);
-       }
 }
 
 void
-AutomationRangeDrag::motion (GdkEvent*, bool /*first_move*/)
+AutomationRangeDrag::motion (GdkEvent*, bool first_move)
 {
        if (_nothing_to_drag) {
                return;
        }
 
+       if (first_move) {
+               _editor->begin_reversible_command (_("automation range move"));
+               for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
+                       i->line->start_drag_multiple (i->points, y_fraction (i->line, current_pointer_y()), i->state);
+               }
+       }
+
        for (list<Line>::iterator l = _lines.begin(); l != _lines.end(); ++l) {
                float const f = y_fraction (l->line, current_pointer_y());
                /* we are ignoring x position for this drag, so we can just pass in anything */
@@ -5612,9 +5637,9 @@ AutomationRangeDrag::motion (GdkEvent*, bool /*first_move*/)
 }
 
 void
-AutomationRangeDrag::finished (GdkEvent* event, bool)
+AutomationRangeDrag::finished (GdkEvent* event, bool motion_occurred)
 {
-       if (_nothing_to_drag) {
+       if (_nothing_to_drag || !motion_occurred) {
                return;
        }
 
index 1e0161fd71da42476aee009e25235bf8c4803677..e5acbaad448f3a9e6e22ebc27724c00be9cabe0c 100644 (file)
@@ -877,6 +877,8 @@ private:
        double _fixed_grab_x;
        double _fixed_grab_y;
        double _cumulative_y_drag;
+       uint32_t _before;
+       uint32_t _after;
 };
 
 /** Transient feature line drags*/
index 5c106785e28559efafe7ee60fcb8c79c22680abb..26e8dd2872436f9ef0efba630c5347c1d64423f3 100644 (file)
@@ -446,7 +446,8 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
        if (((mouse_mode != MouseObject) &&
             (mouse_mode != MouseAudition || item_type != RegionItem) &&
             (mouse_mode != MouseTimeFX || item_type != RegionItem) &&
-            (mouse_mode != MouseDraw)) ||
+            (mouse_mode != MouseDraw) &&
+            (mouse_mode != MouseContent || item_type == RegionItem)) ||
            ((event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE) || event->button.button > 3)) {
                return;
        }
@@ -512,7 +513,8 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
                break;
 
        case ControlPointItem:
-               set_selected_track_as_side_effect (op);
+               /* for object/track exclusivity, we don't call set_selected_track_as_side_effect (op); */
+
                if (eff_mouse_mode != MouseRange) {
                        _mouse_changed_selection |= set_selected_control_point_from_click (press, op);
                }
@@ -761,11 +763,21 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        }
                        return true;
 
+               case GainLineItem:
+                       _drags->set (new LineDrag (this, item), event);
+                       return true;
+                       break;
+
                case ControlPointItem:
                        _drags->set (new ControlPointDrag (this, item), event);
                        return true;
                        break;
 
+               case AutomationLineItem:
+                       _drags->set (new LineDrag (this, item), event);
+                       return true;
+                       break;
+
                case StreamItem:
                        //in the past, we created a new midi region here, but perhaps that is best left to the Draw mode
                        break;
@@ -2200,7 +2212,7 @@ Editor::mouse_brush_insert_region (RegionView* rv, framepos_t pos)
 
        // playlist is frozen, so we have to update manually XXX this is disgusting
 
-       playlist->RegionAdded (new_region); /* EMIT SIGNAL */
+       //playlist->RegionAdded (new_region); /* EMIT SIGNAL */
 }
 
 gint
@@ -2262,8 +2274,6 @@ Editor::add_region_brush_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView*
        }
 
        _drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), true, false));
-
-       begin_reversible_command (Operations::drag_region_brush);
 }
 
 /** Start a grab where a time range is selected, track(s) are selected, and the
@@ -2303,7 +2313,6 @@ Editor::start_selection_grab (ArdourCanvas::Item* /*item*/, GdkEvent* event)
        /* A selection grab currently creates two undo/redo operations, one for
           creating the new region and another for moving it.
        */
-
        begin_reversible_command (Operations::selection_grab);
 
        boost::shared_ptr<Playlist> playlist = clicked_axisview->playlist();
@@ -2316,6 +2325,7 @@ Editor::start_selection_grab (ArdourCanvas::Item* /*item*/, GdkEvent* event)
 
        if (latest_regionviews.empty()) {
                /* something went wrong */
+               abort_reversible_command ();
                return;
        }
 
index 2d26a90a86ce5362886b06cff6c1a450dc38860a..50b7c81b44128f4a9de9c4f0e18f08f6dbf8c8cf 100644 (file)
@@ -336,9 +336,9 @@ Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, boo
                return;
        }
 
-       begin_reversible_command (_("alter selection"));
+       begin_reversible_selection_op (_("alter selection"));
        selection->set_preserving_all_ranges (start, end);
-       commit_reversible_command ();
+       commit_reversible_selection_op ();
 }
 
 bool
@@ -400,8 +400,7 @@ Editor::nudge_forward (bool next, bool force_playhead)
        } else if (!force_playhead && !selection->markers.empty()) {
 
                bool is_start;
-
-               begin_reversible_command (_("nudge location forward"));
+               bool in_command = false;
 
                for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
 
@@ -432,13 +431,18 @@ Editor::nudge_forward (bool next, bool force_playhead)
                                                loc->set_end (max_framepos);
                                        }
                                }
+                               if (!in_command) {
+                                       begin_reversible_command (_("nudge location forward"));
+                                       in_command = true;
+                               }
                                XMLNode& after (loc->get_state());
                                _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
                        }
                }
 
-               commit_reversible_command ();
-
+               if (in_command) {
+                       commit_reversible_command ();
+               }
        } else {
                distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
                _session->request_locate (playhead_cursor->current_frame () + distance);
@@ -485,8 +489,7 @@ Editor::nudge_backward (bool next, bool force_playhead)
        } else if (!force_playhead && !selection->markers.empty()) {
 
                bool is_start;
-
-               begin_reversible_command (_("nudge location forward"));
+               bool in_command = false;
 
                for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
 
@@ -519,13 +522,17 @@ Editor::nudge_backward (bool next, bool force_playhead)
                                                loc->set_end (loc->length());
                                        }
                                }
-
+                               if (!in_command) {
+                                       begin_reversible_command (_("nudge location forward"));
+                                       in_command = true;
+                               }
                                XMLNode& after (loc->get_state());
                                _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
                        }
                }
-
-               commit_reversible_command ();
+               if (in_command) {
+                       commit_reversible_command ();
+               }
 
        } else {
 
@@ -615,7 +622,8 @@ Editor::sequence_regions ()
 
        if (!rs.empty()) {
 
-               begin_reversible_command (_("sequence regions"));
+               bool in_command = false;
+
                for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
                        boost::shared_ptr<Region> r ((*i)->region());
 
@@ -635,13 +643,20 @@ Editor::sequence_regions ()
                                r->set_position(r_end_prev);
                        }
 
+                       if (!in_command) {
+                               begin_reversible_command (_("sequence regions"));
+                               in_command = true;
+                       }
                        _session->add_command (new StatefulDiffCommand (r));
 
                        r_end=r->position() + r->length();
 
                        iCount++;
                }
-               commit_reversible_command ();
+
+               if (in_command) {
+                       commit_reversible_command ();
+               }
        } 
 } 
 
@@ -2172,10 +2187,7 @@ void
 Editor::remove_location_at_playhead_cursor ()
 {
        if (_session) {
-
                //set up for undo
-               begin_reversible_command (_("remove marker"));
-               
                XMLNode &before = _session->locations()->get_state();
                bool removed = false;
 
@@ -2191,9 +2203,9 @@ Editor::remove_location_at_playhead_cursor ()
                
                //store undo
                if (removed) {
+                       begin_reversible_command (_("remove marker"));
                        XMLNode &after = _session->locations()->get_state();
                        _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
-                       
                        commit_reversible_command ();
                }
        }
@@ -2208,8 +2220,7 @@ Editor::add_locations_from_region ()
        if (rs.empty()) {
                return;
        }
-
-       begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
+       bool commit = false;
        
        XMLNode &before = _session->locations()->get_state();
 
@@ -2220,12 +2231,15 @@ Editor::add_locations_from_region ()
                Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
 
                _session->locations()->add (location, true);
+               commit = true;
        }
 
-       XMLNode &after = _session->locations()->get_state();
-       _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
-       
-       commit_reversible_command ();
+       if (commit) {
+               begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
+               XMLNode &after = _session->locations()->get_state();
+               _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
+               commit_reversible_command ();
+       }
 }
 
 /** Add a single range marker around all selected regions */
@@ -2238,8 +2252,6 @@ Editor::add_location_from_region ()
                return;
        }
 
-       begin_reversible_command (_("add marker"));
-       
        XMLNode &before = _session->locations()->get_state();
 
        string markername;
@@ -2260,9 +2272,9 @@ Editor::add_location_from_region ()
        Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
        _session->locations()->add (location, true);
 
+       begin_reversible_command (_("add marker"));
        XMLNode &after = _session->locations()->get_state();
        _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
-       
        commit_reversible_command ();
 }
 
@@ -3264,8 +3276,7 @@ Editor::crop_region_to (framepos_t start, framepos_t end)
        framepos_t the_start;
        framepos_t the_end;
        framepos_t cnt;
-
-       begin_reversible_command (_("trim to selection"));
+       bool in_command = false;
 
        for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
 
@@ -3290,12 +3301,18 @@ Editor::crop_region_to (framepos_t start, framepos_t end)
                the_end = min (end, the_end);
                cnt = the_end - the_start + 1;
 
+               if(!in_command) {
+                       begin_reversible_command (_("trim to selection"));
+                       in_command = true;
+               }
                region->clear_changes ();
                region->trim_to (the_start, cnt);
                _session->add_command (new StatefulDiffCommand (region));
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -3308,8 +3325,8 @@ Editor::region_fill_track ()
        }
 
        framepos_t const end = _session->current_end_frame ();
-
-       begin_reversible_command (Operations::region_fill);
+       RegionSelection foo;
+       bool in_command = false;
 
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
 
@@ -3318,21 +3335,39 @@ Editor::region_fill_track ()
                boost::shared_ptr<Playlist> pl = region->playlist();
 
                if (end <= region->last_frame()) {
-                       return;
+                       continue;
                }
 
                double times = (double) (end - region->last_frame()) / (double) region->length();
 
                if (times == 0) {
-                       return;
+                       continue;
+               }
+
+               if (!in_command) {
+                       begin_reversible_command (Operations::region_fill);
+                       in_command = true;
                }
+               TimeAxisView& tv = (*i)->get_time_axis_view();
+               RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
+               latest_regionviews.clear ();
+               sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
 
                pl->clear_changes ();
                pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
                _session->add_command (new StatefulDiffCommand (pl));
+
+               c.disconnect ();
+
+               foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               if (!foo.empty()) {
+                       selection->set (foo);
+               }
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -3362,10 +3397,10 @@ Editor::region_fill_selection ()
 
        framepos_t selection_length = end - start;
        float times = (float)selection_length / region->length();
-
-       begin_reversible_command (Operations::fill_selection);
+       bool in_command = false;
 
        TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
+       RegionSelection foo;
 
        for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
 
@@ -3373,12 +3408,27 @@ Editor::region_fill_selection ()
                        continue;
                }
 
+               if (!in_command) {
+                       begin_reversible_command (Operations::fill_selection);
+                       in_command = true;
+               }
+               RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
+               latest_regionviews.clear ();
+               sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
+
                playlist->clear_changes ();
                playlist->add_region (RegionFactory::create (region, true), start, times);
                _session->add_command (new StatefulDiffCommand (playlist));
+               c.disconnect ();
+               foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               if (!foo.empty()) {
+                       selection->set (foo);
+               }
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -3676,8 +3726,7 @@ void
 Editor::trim_region_to_location (const Location& loc, const char* str)
 {
        RegionSelection rs = get_regions_from_selection_and_entered ();
-
-       begin_reversible_command (str);
+       bool in_command = false;
 
        for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
                RegionView* rv = (*x);
@@ -3708,10 +3757,17 @@ Editor::trim_region_to_location (const Location& loc, const char* str)
 
                rv->region()->clear_changes ();
                rv->region()->trim_to (start, (end - start));
+
+               if (!in_command) {
+                       begin_reversible_command (str);
+                       in_command = true;
+               }
                _session->add_command(new StatefulDiffCommand (rv->region()));
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -3730,8 +3786,7 @@ void
 Editor::trim_to_region(bool forward)
 {
        RegionSelection rs = get_regions_from_selection_and_entered ();
-
-       begin_reversible_command (_("trim to region"));
+       bool in_command = false;
 
        boost::shared_ptr<Region> next_region;
 
@@ -3746,7 +3801,7 @@ Editor::trim_to_region(bool forward)
                AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
 
                if (!atav) {
-                       return;
+                       continue;
                }
 
                float speed = 1.0;
@@ -3785,10 +3840,16 @@ Editor::trim_to_region(bool forward)
                    arv->region_changed (ARDOUR::bounds_change);
                }
 
+               if (!in_command) {
+                       begin_reversible_command (_("trim to region"));
+                       in_command = true;
+               }
                _session->add_command(new StatefulDiffCommand (region));
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -3913,8 +3974,7 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
        framepos_t start = selection->time[clicked_selection].start;
        framepos_t end = selection->time[clicked_selection].end;
        framepos_t cnt = end - start + 1;
-
-       begin_reversible_command (_("bounce range"));
+       bool in_command = false;
 
        for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
 
@@ -3927,7 +3987,7 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
                boost::shared_ptr<Playlist> playlist;
 
                if ((playlist = rtv->playlist()) == 0) {
-                       return;
+                       continue;
                }
 
                InterThreadInfo itt;
@@ -3954,6 +4014,10 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
                        playlist->add_region (r, start);
                }
 
+               if (!in_command) {
+                       begin_reversible_command (_("bounce range"));
+                       in_command = true;
+               }
                vector<Command*> cmds;
                playlist->rdiff (cmds);
                _session->add_commands (cmds);
@@ -3961,7 +4025,9 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
                _session->add_command (new StatefulDiffCommand (playlist));
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 /** Delete selected regions, automation points or a time range */
@@ -4315,8 +4381,6 @@ Editor::remove_selected_regions ()
                return;
        }
 
-       begin_reversible_command (_("remove region"));
-
        list<boost::shared_ptr<Region> > regions_to_remove;
 
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
@@ -4360,6 +4424,7 @@ Editor::remove_selected_regions ()
        }
 
        vector<boost::shared_ptr<Playlist> >::iterator pl;
+       bool in_command = false;
 
        for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
                (*pl)->thaw ();
@@ -4367,6 +4432,11 @@ Editor::remove_selected_regions ()
                /* We might have removed regions, which alters other regions' layering_index,
                   so we need to do a recursive diff here.
                */
+
+               if (!in_command) {
+                       begin_reversible_command (_("remove region"));
+                       in_command = true;
+               }
                vector<Command*> cmds;
                (*pl)->rdiff (cmds);
                _session->add_commands (cmds);
@@ -4374,7 +4444,9 @@ Editor::remove_selected_regions ()
                _session->add_command(new StatefulDiffCommand (*pl));
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 /** Cut, copy or clear selected regions.
@@ -4710,6 +4782,10 @@ Editor::paste_internal (framepos_t position, float times)
 void
 Editor::duplicate_some_regions (RegionSelection& regions, float times)
 {
+       if (regions.empty ()) {
+               return;
+       }
+
        boost::shared_ptr<Playlist> playlist;
        RegionSelection sel = regions; // clear (below) may  clear the argument list if its the current region selection
        RegionSelection foo;
@@ -4764,11 +4840,10 @@ Editor::duplicate_selection (float times)
                return;
        }
 
-       begin_reversible_command (_("duplicate selection"));
-
        ri = new_regions.begin();
 
        TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
+       bool in_command = false;
 
        for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
                if ((playlist = (*i)->playlist()) == 0) {
@@ -4782,6 +4857,11 @@ Editor::duplicate_selection (float times)
                        end = selection->time.end_frame();
                }
                playlist->duplicate (*ri, end, times);
+
+               if (!in_command) {
+                       begin_reversible_command (_("duplicate selection"));
+                       in_command = true;
+               }
                _session->add_command (new StatefulDiffCommand (playlist));
 
                ++ri;
@@ -4790,7 +4870,9 @@ Editor::duplicate_selection (float times)
                }
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 /** Reset all selected points to the relevant default value */
@@ -4848,9 +4930,8 @@ Editor::nudge_track (bool use_edit, bool forwards)
                return;
        }
 
-       begin_reversible_command (_("nudge track"));
-
        TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
+       bool in_command = false;
 
        for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
 
@@ -4863,6 +4944,10 @@ Editor::nudge_track (bool use_edit, bool forwards)
 
                playlist->nudge_after (start, distance, forwards);
 
+               if (!in_command) {
+                       begin_reversible_command (_("nudge track"));
+                       in_command = true;
+               }
                vector<Command*> cmds;
 
                playlist->rdiff (cmds);
@@ -4871,7 +4956,9 @@ Editor::nudge_track (bool use_edit, bool forwards)
                _session->add_command (new StatefulDiffCommand (playlist));
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -4951,9 +5038,8 @@ Editor::normalize_region ()
                }
        }
 
-       begin_reversible_command (_("normalize"));
-
        list<double>::const_iterator a = max_amps.begin ();
+       bool in_command = false;
 
        for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
@@ -4966,12 +5052,19 @@ Editor::normalize_region ()
                double const amp = dialog.normalize_individually() ? *a : max_amp;
 
                arv->audio_region()->normalize (amp, dialog.target ());
+
+               if (!in_command) {
+                       begin_reversible_command (_("normalize"));
+                       in_command = true;
+               }
                _session->add_command (new StatefulDiffCommand (arv->region()));
 
                ++a;
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 
@@ -4988,7 +5081,7 @@ Editor::reset_region_scale_amplitude ()
                return;
        }
 
-       begin_reversible_command ("reset gain");
+       bool in_command = false;
 
        for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
@@ -4996,10 +5089,17 @@ Editor::reset_region_scale_amplitude ()
                        continue;
                arv->region()->clear_changes ();
                arv->audio_region()->set_scale_amplitude (1.0f);
+
+               if(!in_command) {
+                               begin_reversible_command ("reset gain");
+                               in_command = true;
+               }
                _session->add_command (new StatefulDiffCommand (arv->region()));
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -5011,7 +5111,7 @@ Editor::adjust_region_gain (bool up)
                return;
        }
 
-       begin_reversible_command ("adjust region gain");
+       bool in_command = false;
 
        for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
@@ -5030,10 +5130,17 @@ Editor::adjust_region_gain (bool up)
                }
 
                arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
+
+               if (!in_command) {
+                               begin_reversible_command ("adjust region gain");
+                               in_command = true;
+               }
                _session->add_command (new StatefulDiffCommand (arv->region()));
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 
@@ -5105,7 +5212,7 @@ Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
                return;
        }
 
-       begin_reversible_command (op.name ());
+       bool in_command = false;
 
        for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
                RegionSelection::const_iterator tmp = r;
@@ -5116,6 +5223,10 @@ Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
                if (mrv) {
                        Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
                        if (cmd) {
+                               if (!in_command) {
+                                       begin_reversible_command (op.name ());
+                                       in_command = true;
+                               }
                                (*cmd)();
                                _session->add_command (cmd);
                        }
@@ -5124,7 +5235,9 @@ Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
                r = tmp;
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -5136,9 +5249,9 @@ Editor::fork_region ()
                return;
        }
 
-       begin_reversible_command (_("Fork Region(s)"));
-
        CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
+       bool in_command = false;
+
        gdk_flush ();
 
        for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
@@ -5152,7 +5265,11 @@ Editor::fork_region ()
                                boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
                                boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
                                boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
-                               
+
+                               if (!in_command) {
+                                       begin_reversible_command (_("Fork Region(s)"));
+                                       in_command = true;
+                               }
                                playlist->clear_changes ();
                                playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
                                _session->add_command(new StatefulDiffCommand (playlist));
@@ -5164,7 +5281,9 @@ Editor::fork_region ()
                r = tmp;
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -5292,9 +5411,9 @@ Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress
                return;
        }
 
-       begin_reversible_command (command);
-
        CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
+       bool in_command = false;
+
        gdk_flush ();
 
        int n = 0;
@@ -5337,17 +5456,22 @@ Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress
                                        }
 
                                }
-
                                /* We might have removed regions, which alters other regions' layering_index,
                                   so we need to do a recursive diff here.
                                */
+
+                               if (!in_command) {
+                                       begin_reversible_command (command);
+                                       in_command = true;
+                               }
                                vector<Command*> cmds;
                                playlist->rdiff (cmds);
                                _session->add_commands (cmds);
                                
                                _session->add_command(new StatefulDiffCommand (playlist));
+
                        } else {
-                               return;
+                               continue;
                        }
 
                        if (progress) {
@@ -5359,7 +5483,9 @@ Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress
                ++n;
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -5377,7 +5503,7 @@ Editor::reset_region_gain_envelopes ()
                return;
        }
 
-       begin_reversible_command (_("reset region gain"));
+       bool in_command = false;
        
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
@@ -5386,11 +5512,18 @@ Editor::reset_region_gain_envelopes ()
                        XMLNode& before (alist->get_state());
 
                        arv->audio_region()->set_default_envelope ();
+
+                       if (!in_command) {
+                               begin_reversible_command (_("reset region gain"));
+                               in_command = true;
+                       }
                        _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
                }
        }
-       
-       commit_reversible_command ();
+
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -5430,18 +5563,25 @@ Editor::toggle_gain_envelope_active ()
                return;
        }
 
-       begin_reversible_command (_("region gain envelope active"));
-       
+       bool in_command = false;
+
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
                if (arv) {
                        arv->region()->clear_changes ();
                        arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
+
+                       if (!in_command) {
+                               begin_reversible_command (_("region gain envelope active"));
+                               in_command = true;
+                       }
                        _session->add_command (new StatefulDiffCommand (arv->region()));
                }
        }
-       
-       commit_reversible_command ();
+
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -5671,13 +5811,13 @@ Editor::set_fade_length (bool in)
                cmd = _("set fade out length");
        }
 
-       begin_reversible_command (cmd);
+       bool in_command = false;
 
        for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
                AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
 
                if (!tmp) {
-                       return;
+                       continue;
                }
 
                boost::shared_ptr<AutomationList> alist;
@@ -5697,11 +5837,17 @@ Editor::set_fade_length (bool in)
                        tmp->audio_region()->set_fade_out_active (true);
                }
 
+               if (!in_command) {
+                       begin_reversible_command (cmd);
+                       in_command = true;
+               }
                XMLNode &after = alist->get_state();
                _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -5712,14 +5858,13 @@ Editor::set_fade_in_shape (FadeShape shape)
        if (rs.empty()) {
                return;
        }
-
-       begin_reversible_command (_("set fade in shape"));
+       bool in_command = false;
 
        for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
                AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
 
                if (!tmp) {
-                       return;
+                       continue;
                }
 
                boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
@@ -5727,12 +5872,17 @@ Editor::set_fade_in_shape (FadeShape shape)
 
                tmp->audio_region()->set_fade_in_shape (shape);
 
+               if (!in_command) {
+                       begin_reversible_command (_("set fade in shape"));
+                       in_command = true;
+               }
                XMLNode &after = alist->get_state();
                _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
        }
 
-       commit_reversible_command ();
-
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -5743,14 +5893,13 @@ Editor::set_fade_out_shape (FadeShape shape)
        if (rs.empty()) {
                return;
        }
-
-       begin_reversible_command (_("set fade out shape"));
+       bool in_command = false;
 
        for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
                AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
 
                if (!tmp) {
-                       return;
+                       continue;
                }
 
                boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
@@ -5758,11 +5907,17 @@ Editor::set_fade_out_shape (FadeShape shape)
 
                tmp->audio_region()->set_fade_out_shape (shape);
 
+               if(!in_command) {
+                       begin_reversible_command (_("set fade out shape"));
+                       in_command = true;
+               }
                XMLNode &after = alist->get_state();
                _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -5773,14 +5928,13 @@ Editor::set_fade_in_active (bool yn)
        if (rs.empty()) {
                return;
        }
-
-       begin_reversible_command (_("set fade in active"));
+       bool in_command = false;
 
        for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
                AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
 
                if (!tmp) {
-                       return;
+                       continue;
                }
 
 
@@ -5788,10 +5942,17 @@ Editor::set_fade_in_active (bool yn)
 
                ar->clear_changes ();
                ar->set_fade_in_active (yn);
+
+               if (!in_command) {
+                       begin_reversible_command (_("set fade in active"));
+                       in_command = true;
+               }
                _session->add_command (new StatefulDiffCommand (ar));
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -5802,24 +5963,30 @@ Editor::set_fade_out_active (bool yn)
        if (rs.empty()) {
                return;
        }
-
-       begin_reversible_command (_("set fade out active"));
+       bool in_command = false;
 
        for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
                AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
 
                if (!tmp) {
-                       return;
+                       continue;
                }
 
                boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
 
                ar->clear_changes ();
                ar->set_fade_out_active (yn);
+
+               if (!in_command) {
+                       begin_reversible_command (_("set fade out active"));
+                       in_command = true;
+               }
                _session->add_command(new StatefulDiffCommand (ar));
        }
 
-       commit_reversible_command ();
+       if (in_command) {
+               commit_reversible_command ();
+       }
 }
 
 void
@@ -5855,11 +6022,14 @@ Editor::toggle_region_fades (int dir)
        }
 
        /* XXX should this undo-able? */
+       bool in_command = false;
 
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
                if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
                        continue;
                }
+               ar->clear_changes ();
+
                if (dir == 1 || dir == 0) {
                        ar->set_fade_in_active (!yn);
                }
@@ -5867,6 +6037,15 @@ Editor::toggle_region_fades (int dir)
                if (dir == -1 || dir == 0) {
                        ar->set_fade_out_active (!yn);
                }
+               if (!in_command) {
+                       begin_reversible_command (_("toggle fade active"));
+                       in_command = true;
+               }
+               _session->add_command(new StatefulDiffCommand (ar));
+       }
+
+       if (in_command) {
+               commit_reversible_command ();
        }
 }
 
@@ -6964,13 +7143,11 @@ Editor::insert_time (
        bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
        )
 {
-       bool commit = false;
 
        if (Config->get_edit_mode() == Lock) {
                return;
        }
-
-       begin_reversible_command (_("insert time"));
+       bool in_command = false;
 
        TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
 
@@ -7010,19 +7187,25 @@ Editor::insert_time (
 
                        (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
 
+                       if (!in_command) {
+                               begin_reversible_command (_("insert time"));
+                               in_command = true;
+                       }
                        vector<Command*> cmds;
                        (*i)->rdiff (cmds);
                        _session->add_commands (cmds);
 
                        _session->add_command (new StatefulDiffCommand (*i));
-                       commit = true;
                }
 
                /* automation */
                RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
                if (rtav) {
+                       if (!in_command) {
+                               begin_reversible_command (_("insert time"));
+                               in_command = true;
+                       }
                        rtav->route ()->shift (pos, frames);
-                       commit = true;
                }
        }
 
@@ -7058,16 +7241,27 @@ Editor::insert_time (
                }
 
                if (moved) {
+                       if (!in_command) {
+                               begin_reversible_command (_("insert time"));
+                               in_command = true;
+                       }
                        XMLNode& after (_session->locations()->get_state());
                        _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
                }
        }
 
        if (tempo_too) {
+               if (!in_command) {
+                       begin_reversible_command (_("insert time"));
+                       in_command = true;
+               }
+               XMLNode& before (_session->tempo_map().get_state());
                _session->tempo_map().insert_time (pos, frames);
+               XMLNode& after (_session->tempo_map().get_state());
+               _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
        }
 
-       if (commit) {
+       if (in_command) {
                commit_reversible_command ();
        }
 }
@@ -7110,14 +7304,11 @@ void
 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt, 
                     bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
 {
-       bool commit = false;
-       
        if (Config->get_edit_mode() == Lock) {
                error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
                return;
        }
-
-       begin_reversible_command (_("cut time"));
+       bool in_command = false;
 
        for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
                /* regions */
@@ -7133,17 +7324,23 @@ Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
                        pl->cut (rl);
                        pl->shift (pos, -frames, true, ignore_music_glue);
                        
+                       if (!in_command) {
+                               begin_reversible_command (_("cut time"));
+                               in_command = true;
+                       }
                        XMLNode &after = pl->get_state();
                        
                        _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
-                       commit = true;
                }
                        
                /* automation */
                RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
                if (rtav) {
+                       if (!in_command) {
+                               begin_reversible_command (_("cut time"));
+                               in_command = true;
+                       }
                        rtav->route ()->shift (pos, -frames);
-                       commit = true;
                }
        }
 
@@ -7212,23 +7409,29 @@ Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
                }
        
                if (moved) {
+                       if (!in_command) {
+                               begin_reversible_command (_("cut time"));
+                               in_command = true;
+                       }
                        XMLNode& after (_session->locations()->get_state());
                        _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
-                       commit = true;
                }
        }
        
        if (tempo_too) {
                XMLNode& before (_session->tempo_map().get_state());
 
-               if (_session->tempo_map().remove_time (pos, frames) ) {
+               if (_session->tempo_map().cut_time (pos, frames) ) {
+                       if (!in_command) {
+                               begin_reversible_command (_("cut time"));
+                               in_command = true;
+                       }
                        XMLNode& after (_session->tempo_map().get_state());
                        _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
-                       commit = true;
                }
        }
        
-       if (commit) {
+       if (in_command) {
                commit_reversible_command ();
        }
 }
index 5bb777d7391ab2aed4a4f33dfd35c11b02a849ff..44794313a0d6a862fce6a967b5eb4d804180be1a 100644 (file)
@@ -326,19 +326,23 @@ Editor::set_selected_control_point_from_click (bool press, Selection::Operation
        if (!clicked_control_point) {
                return false;
        }
+       bool ret = false;
 
        switch (op) {
        case Selection::Set:
                if (press) {
                        selection->set (clicked_control_point);
+                       ret = true;
                }
                break;
        case Selection::Add:
                if (press) {
                        selection->add (clicked_control_point);
+                       ret = true;
                }
                break;
        case Selection::Toggle:
+
                /* This is a bit of a hack; if we Primary-Click-Drag a control
                   point (for push drag) we want the point we clicked on to be
                   selected, otherwise we end up confusingly dragging an
@@ -353,9 +357,11 @@ Editor::set_selected_control_point_from_click (bool press, Selection::Operation
                        */
                        selection->toggle (clicked_control_point);
                        _control_point_toggled_on_press = true;
+                       ret = true;
                } else if (!press && !_control_point_toggled_on_press) {
                        /* This is the release, and the point wasn't toggled on the press, so do it now */
                        selection->toggle (clicked_control_point);
+                       ret = true;
                } else {
                        /* Reset our flag */
                        _control_point_toggled_on_press = false;
@@ -366,7 +372,7 @@ Editor::set_selected_control_point_from_click (bool press, Selection::Operation
                break;
        }
 
-       return true;
+       return ret;
 }
 
 void
index 2025ec70c3e2a8767435441107e5db9a53d5d538..5908e502493323005ae668d447eab5e2e4fa6ca9 100644 (file)
@@ -133,6 +133,8 @@ Editor::pitch_shift (RegionSelection& regions, float fraction)
 
        if (ret == 0) {
                commit_reversible_command ();
+       } else {
+               abort_reversible_command ();
        }
 
        return ret;
index be475216c17e0e9c57f94dd8f16257f690f28988..e412b82c32d10f5ef569b0d0c78b9e7ebba4eb32 100644 (file)
@@ -1509,8 +1509,9 @@ boost::shared_ptr<MidiRegion>
 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
 {
        Editor* real_editor = dynamic_cast<Editor*> (&_editor);
-
-       real_editor->begin_reversible_command (Operations::create_region);
+       if (commit) {
+               real_editor->begin_reversible_command (Operations::create_region);
+       }
        playlist()->clear_changes ();
 
        real_editor->snap_to (pos, RoundNearest);
index 16888fb6880d2d7160d60eeda70aeb240abc58a6..e41e012ce6a760cd70e6f00991bfacfa24218dc1 100644 (file)
@@ -270,33 +270,41 @@ RegionEditor::connect_editor_events ()
 void
 RegionEditor::position_clock_changed ()
 {
-       PublicEditor::instance().begin_reversible_command (_("change region start position"));
-
+       bool in_command = false;
        boost::shared_ptr<Playlist> pl = _region->playlist();
 
        if (pl) {
+               PublicEditor::instance().begin_reversible_command (_("change region start position"));
+               in_command = true;
+
                _region->clear_changes ();
                _region->set_position (position_clock.current_time());
                _session->add_command(new StatefulDiffCommand (_region));
        }
 
-       PublicEditor::instance().commit_reversible_command ();
+       if (in_command) {
+               PublicEditor::instance().commit_reversible_command ();
+       }
 }
 
 void
 RegionEditor::end_clock_changed ()
 {
-       PublicEditor::instance().begin_reversible_command (_("change region end position"));
-
+       bool in_command = false;
        boost::shared_ptr<Playlist> pl = _region->playlist();
 
        if (pl) {
+               PublicEditor::instance().begin_reversible_command (_("change region end position"));
+               in_command = true;
+
                 _region->clear_changes ();
                _region->trim_end (end_clock.current_time());
                _session->add_command(new StatefulDiffCommand (_region));
        }
 
-       PublicEditor::instance().commit_reversible_command ();
+       if (in_command) {
+               PublicEditor::instance().commit_reversible_command ();
+       }
 
        end_clock.set (_region->position() + _region->length() - 1, true);
 }
@@ -305,18 +313,21 @@ void
 RegionEditor::length_clock_changed ()
 {
        framecnt_t frames = length_clock.current_time();
-
-       PublicEditor::instance().begin_reversible_command (_("change region length"));
-
+       bool in_command = false;
        boost::shared_ptr<Playlist> pl = _region->playlist();
 
        if (pl) {
-                _region->clear_changes ();
+               PublicEditor::instance().begin_reversible_command (_("change region length"));
+               in_command = true;
+
+               _region->clear_changes ();
                _region->trim_end (_region->position() + frames - 1);
                _session->add_command(new StatefulDiffCommand (_region));
        }
 
-       PublicEditor::instance().commit_reversible_command ();
+       if (in_command) {
+               PublicEditor::instance().commit_reversible_command ();
+       }
 
        length_clock.set (_region->length());
 }
index 7f112b9546a145d3978b18447cf4488e1ec9c9d9..94ed2a86f044abc8909cf70b6496e1293a8bc77f 100644 (file)
@@ -59,6 +59,7 @@
 
 #include "ardour_ui.h"
 #include "ardour_button.h"
+#include "audio_streamview.h"
 #include "debug.h"
 #include "global_signals.h"
 #include "route_time_axis.h"
@@ -1342,6 +1343,10 @@ RouteTimeAxisView::set_selected_points (PointSelection& points)
        for (Children::iterator i = children.begin(); i != children.end(); ++i) {
                (*i)->set_selected_points (points);
        }
+       AudioStreamView* asv = dynamic_cast<AudioStreamView*>(_view);
+       if (asv) {
+               asv->set_selected_points (points);
+       }
 }
 
 void
index 24a9e0de3ee84fd497afad4abbf006d52c65f904..5d73e4aef959107d80613b5c96ac804a63eacdc1 100644 (file)
@@ -101,6 +101,7 @@ protected:
        ARDOUR::Session& _session;
 
        const ParameterDescriptor _desc;
+       XMLNode* _before; //used for undo of touch start/stop pairs.
 };
 
 
index 21952038cfc180a467b1c56141afbd675e9d6ee2..bfb1046849887b83fa57a67d391efe99b4404896 100644 (file)
 */
 
 #include <iostream>
-
 #include "ardour/automation_control.h"
 #include "ardour/automation_watch.h"
 #include "ardour/event_type_map.h"
 #include "ardour/session.h"
 
+#include "pbd/memento_command.h"
+
+#include "i18n.h"
+
 using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
@@ -85,6 +88,8 @@ AutomationControl::set_automation_state (AutoState as)
                }
 
                if (as == Write) {
+                       /* get state for undo */
+                       _before = &alist ()->get_state ();
                        AutomationWatch::instance().add_automation_watch (shared_from_this());
                } else if (as == Touch) {
                        if (!touching()) {
@@ -113,9 +118,16 @@ AutomationControl::set_automation_style (AutoStyle as)
 void
 AutomationControl::start_touch(double when)
 {
-       if (!_list) return;
+       if (!_list) {
+               return;
+       }
+
        if (!touching()) {
+
                if (alist()->automation_state() == Touch) {
+                       /* subtle. aligns the user value with the playback */
+                       set_value (get_value ());
+                       _before = &alist ()->get_state ();
                        alist()->start_touch (when);
                        if (!_desc.toggled) {
                                AutomationWatch::instance().add_automation_watch (shared_from_this());
@@ -131,11 +143,22 @@ AutomationControl::stop_touch(bool mark, double when)
        if (!_list) return;
        if (touching()) {
                set_touching (false);
+
+               if (alist()->automation_state() == Write) {
+                       _session.begin_reversible_command (string_compose (_("write %1 automation"), name ()));
+                       _session.add_command (new MementoCommand<AutomationList> (*alist ().get (), _before, &alist ()->get_state ()));
+                       _session.commit_reversible_command ();
+               }
+
                if (alist()->automation_state() == Touch) {
                        alist()->stop_touch (mark, when);
                        if (!_desc.toggled) {
                                AutomationWatch::instance().remove_automation_watch (shared_from_this());
                        }
+
+                       _session.begin_reversible_command (string_compose (_("touch %1 automation"), name ()));
+                       _session.add_command (new MementoCommand<AutomationList> (*alist ().get (), _before, &alist ()->get_state ()));
+                       _session.commit_reversible_command ();
                }
        }
 }
index 7f7599f8ca4abc8025ec62c78f337c735386ffd6..706a3330a74d360f91e98efed3cebb5717d0f381 100644 (file)
@@ -276,7 +276,11 @@ AutomationList::state (bool full)
                 if (_state != Write) {
                         root->add_property ("state", auto_state_to_string (_state));
                 } else {
-                        root->add_property ("state", auto_state_to_string (Off));
+                       if (_events.empty ()) {
+                               root->add_property ("state", auto_state_to_string (Off));
+                       } else {
+                               root->add_property ("state", auto_state_to_string (Touch));
+                       }
                 }
        } else {
                /* never save anything but Off for automation state to a template */
index 4e833fceb5cd2cae57e87cee5dbd31142f9432e4..3714f1750214b8caf338a67e170416ec55781d13 100644 (file)
@@ -128,7 +128,7 @@ AutomationWatch::timer ()
                                        (*aw)->list()->add (time, (*aw)->user_double(), true);
                                }
                        }
-               } else {  //transport stopped or reversed.  stop the automation pass and start a new one (for bonus points, someday store the previous pass in an undo record)
+               } else if (time != _last_time) {  //transport stopped or reversed.  stop the automation pass and start a new one (for bonus points, someday store the previous pass in an undo record)
                        for (AutomationWatches::iterator aw = automation_watches.begin(); aw != automation_watches.end(); ++aw) {
                                DEBUG_TRACE (DEBUG::Automation, string_compose ("%1: transport in rewind, speed %2, in write pass ? %3 writing ? %4\n", 
                                                                                (*aw)->name(), _session->transport_speed(), _session->transport_rolling(),
index 7a828264bdfbbc83bb5384f567dac49f4938c930..82868cd24c40b52294cd1c222a1ce2823adb753f 100644 (file)
@@ -124,8 +124,8 @@ public:
        void slide (iterator before, double distance);
        void shift (double before, double distance);
 
-       virtual void add (double when, double value, bool with_guards=true, bool with_default=true);
-       virtual void editor_add (double when, double value);
+       virtual void add (double when, double value, bool with_guards=true, bool with_initial=true);
+       virtual void editor_add (double when, double value, bool with_guard);
        
        void fast_simple_add (double when, double value);
 
index a2f3aa4f334f017b653d87acf7280e33a1ee08a4..5118744c05240f491b95d53097daa83f51da6184 100644 (file)
@@ -399,7 +399,7 @@ ControlList::add_guard_point (double when)
        most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
 
        double eval_value = unlocked_eval (insert_position);
-       
+
        if (most_recent_insert_iterator == _events.end()) {
                
                DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert iterator at end, adding eval-value there %2\n", this, eval_value));
@@ -407,7 +407,7 @@ ControlList::add_guard_point (double when)
                /* leave insert iterator at the end */
                
        } else if ((*most_recent_insert_iterator)->when == when) {
-               
+
                DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert iterator at existing point, setting eval-value there %2\n", this, eval_value));
                
                /* most_recent_insert_iterator points to a control event
@@ -415,15 +415,15 @@ ControlList::add_guard_point (double when)
                   nothing to do.
                   
                   ... except ... 
-                  
+
                   advance most_recent_insert_iterator so that the "real"
                   insert occurs in the right place, since it 
                   points to the control event just inserted.
                */
-               
+
                ++most_recent_insert_iterator;
        } else {
-               
+
                /* insert a new control event at the right spot
                 */
                
@@ -431,7 +431,7 @@ ControlList::add_guard_point (double when)
                                                                 this, eval_value, (*most_recent_insert_iterator)->when));
                
                most_recent_insert_iterator = _events.insert (most_recent_insert_iterator, new ControlEvent (when, eval_value));
-               
+
                /* advance most_recent_insert_iterator so that the "real"
                 * insert occurs in the right place, since it 
                 * points to the control event just inserted.
@@ -452,7 +452,7 @@ ControlList::in_write_pass () const
 }
 
 void
-ControlList::editor_add (double when, double value)
+ControlList::editor_add (double when, double value, bool with_guard)
 {
        /* this is for making changes from a graphical line editor
        */
@@ -464,11 +464,19 @@ ControlList::editor_add (double when, double value)
                 */
 
                if (when >= 1) {
-                       _events.insert (_events.end(), new ControlEvent (0, _default_value));
-                       DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
+                       _events.insert (_events.end(), new ControlEvent (0, value));
+                       DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added value %2 at zero\n", this, value));
                }
        }
 
+       insert_position = when;
+       if (with_guard) {
+               if (when > 64) {
+                       add_guard_point (when - 64);
+               }
+               maybe_add_insert_guard (when);
+       }
+
        ControlEvent cp (when, 0.0f);
        iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
        DEBUG_TRACE (DEBUG::ControlList, string_compose ("editor_add: actually add when= %1 value= %2\n", when, value));
@@ -491,9 +499,9 @@ ControlList::maybe_add_insert_guard (double when)
                           new control point so that our insert will happen correctly. */
                        most_recent_insert_iterator = _events.insert (
                                most_recent_insert_iterator,
-                               new ControlEvent (when + 1, (*most_recent_insert_iterator)->value));
+                               new ControlEvent (when + 64, (*most_recent_insert_iterator)->value));
                        DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added insert guard point @ %2 = %3\n",
-                                                                        this, when+1,
+                                                                        this, when + 64,
                                                                         (*most_recent_insert_iterator)->value));
                }
        }
@@ -546,7 +554,7 @@ ControlList::erase_from_iterator_to (iterator iter, double when)
 }
 
 void
-ControlList::add (double when, double value, bool with_guards, bool with_default)
+ControlList::add (double when, double value, bool with_guards, bool with_initial)
 {
        /* this is for making changes from some kind of user interface or
           control surface (GUI, MIDI, OSC etc)
@@ -561,12 +569,12 @@ ControlList::add (double when, double value, bool with_guards, bool with_default
                ControlEvent cp (when, 0.0f);
                iterator insertion_point;
 
-               if (_events.empty() && with_default) {
+               if (_events.empty() && with_initial) {
                        
                        /* empty: add an "anchor" point if the point we're adding past time 0 */
 
                        if (when >= 1) {
-                               _events.insert (_events.end(), new ControlEvent (0, _default_value));
+                               _events.insert (_events.end(), new ControlEvent (0, value));
                                DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
                        }
                }
@@ -628,10 +636,10 @@ ControlList::add (double when, double value, bool with_guards, bool with_default
                        if ((*most_recent_insert_iterator)->value != value) {
                                DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 reset existing point to new value %2\n", this, value));
 
-                               /* only one point allowed per time point, so just
-                                * reset the value here.
+                               /* only one point allowed per time point, so add a guard point
+                                * before it if needed then reset the value of the point.
                                 */
-                               
+
                                (*most_recent_insert_iterator)->value = value;
 
                                /* if we modified the final value, then its as
@@ -649,10 +657,35 @@ ControlList::add (double when, double value, bool with_guards, bool with_default
 
                } else {
                        DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert new point at %2 at iterator at %3\n", this, when, (*most_recent_insert_iterator)->when));
-                       
-                       const bool done = maybe_insert_straight_line (when, value);
+                       bool done = false;
+                       /* check for possible straight line here until maybe_insert_straight_line () handles the insert iterator properly*/
+                       if (most_recent_insert_iterator != _events.begin ()) {
+                               bool have_point2 = false;
+                               --most_recent_insert_iterator;
+                               const bool have_point1 = (*most_recent_insert_iterator)->value == value;
+
+                               if (most_recent_insert_iterator != _events.begin ()) {
+                                       --most_recent_insert_iterator;
+                                       have_point2 = (*most_recent_insert_iterator)->value == value;
+                                       ++most_recent_insert_iterator;
+                               }
+
+                               if (have_point1 && have_point2) {
+                                       (*most_recent_insert_iterator)->when = when;
+                                       done = true;
+                               } else {
+                                       ++most_recent_insert_iterator;
+                               }
+                       }
+                       //done = maybe_insert_straight_line (when, value) || done;
+                       /* if the transport is stopped, add guard points (?) */
+                       if (!done && !_in_write_pass && when > 64) {
+                               add_guard_point (when - 64);
+                               maybe_add_insert_guard (when);
+                       }
+
                        if (with_guards) {
-                               maybe_add_insert_guard(when);
+                               maybe_add_insert_guard (when);
                        }
 
                        if (!done) {
index f137a4ed65ebbbc10270815d1fbef6b1a98c6662..0a316340b49f035b9e774c6f13c5edf5a2eefe27 100644 (file)
@@ -58,6 +58,7 @@ class LIBGTKMM2EXT_API PixFader : public CairoWidget
        void on_size_allocate (Gtk::Allocation& alloc);
 
        void render (cairo_t *, cairo_rectangle_t*);
+       bool on_grab_broken_event (GdkEventGrabBroken*);
        bool on_button_press_event (GdkEventButton*);
        bool on_button_release_event (GdkEventButton*);
        bool on_motion_notify_event (GdkEventMotion*);
index b140d7b56bc697d52fdb163925a20fe83131020d..1e814fd147517b6aa6b0b2ae77f7a06e28cc0004 100644 (file)
@@ -71,7 +71,7 @@ PixFader::PixFader (Gtk::Adjustment& adj, int orientation, int fader_length, int
 
        _adjustment.signal_value_changed().connect (mem_fun (*this, &PixFader::adjustment_changed));
        _adjustment.signal_changed().connect (mem_fun (*this, &PixFader::adjustment_changed));
-
+       signal_grab_broken_event ().connect (mem_fun (*this, &PixFader::on_grab_broken_event));
        if (_orien == VERT) {
                CairoWidget::set_size_request(_girth, _span);
        } else {
@@ -365,6 +365,18 @@ PixFader::on_size_allocate (Gtk::Allocation& alloc)
        update_unity_position ();
 }
 
+bool
+PixFader::on_grab_broken_event (GdkEventGrabBroken* ev)
+{
+       if (_dragging) {
+               remove_modal_grab();
+               _dragging = false;
+               gdk_pointer_ungrab (GDK_CURRENT_TIME);
+               StopGesture ();
+       }
+       return (_tweaks & NoButtonForward) ? true : false;
+}
+
 bool
 PixFader::on_button_press_event (GdkEventButton* ev)
 {