From 9af9e17adc96f7c27ce0e1651d6949393e787636 Mon Sep 17 00:00:00 2001 From: nick_m Date: Mon, 15 Dec 2014 00:13:38 +1100 Subject: Add editor selection state to session history via a SelectionMemento, which combines selection related editor properties with the current editor selection. The related editor properties are: mouse mode, zoom setting, left frame of the canvas, y origin of the canvas. Selection state now includes region views (storing the underlying region id) and time. This patch also fixes a region mute undo bug. --- gtk2_ardour/audio_region_view.cc | 4 +- gtk2_ardour/automation_line.cc | 14 ++-- gtk2_ardour/automation_region_view.cc | 6 +- gtk2_ardour/automation_time_axis.cc | 9 +- gtk2_ardour/crossfade_edit.cc | 4 +- gtk2_ardour/editor.cc | 62 +++++++++++++- gtk2_ardour/editor.h | 9 +- gtk2_ardour/editor_drag.cc | 36 ++++---- gtk2_ardour/editor_locations.cc | 2 +- gtk2_ardour/editor_markers.cc | 10 ++- gtk2_ardour/editor_mouse.cc | 5 +- gtk2_ardour/editor_ops.cc | 149 +++++++++++++++++++--------------- gtk2_ardour/location_ui.cc | 13 +-- gtk2_ardour/midi_region_view.cc | 4 +- gtk2_ardour/public_editor.h | 8 ++ gtk2_ardour/region_editor.cc | 21 ++--- gtk2_ardour/region_gain_line.cc | 4 +- gtk2_ardour/region_selection.cc | 1 + gtk2_ardour/region_selection.h | 1 + gtk2_ardour/rhythm_ferret.cc | 4 +- gtk2_ardour/selection.cc | 52 +++++++++++- gtk2_ardour/selection_memento.cc | 95 ++++++++++++++++++++++ gtk2_ardour/selection_memento.h | 34 ++++++++ gtk2_ardour/wscript | 1 + 24 files changed, 414 insertions(+), 134 deletions(-) create mode 100644 gtk2_ardour/selection_memento.cc create mode 100644 gtk2_ardour/selection_memento.h diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc index 2adb9e9500..d5882514c7 100644 --- a/gtk2_ardour/audio_region_view.cc +++ b/gtk2_ardour/audio_region_view.cc @@ -1237,7 +1237,7 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev, b can represent automation data with it. */ - trackview.session()->begin_reversible_command (_("add gain control point")); + trackview.editor().begin_reversible_command (_("add gain control point")); XMLNode &before = audio_region()->envelope()->get_state(); if (!audio_region()->envelope_active()) { @@ -1251,7 +1251,7 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev, b XMLNode &after = audio_region()->envelope()->get_state(); trackview.session()->add_command (new MementoCommand(*audio_region()->envelope().get(), &before, &after)); - trackview.session()->commit_reversible_command (); + trackview.editor().commit_reversible_command (); } void diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc index 62c9118ef4..c0ed14f7f9 100644 --- a/gtk2_ardour/automation_line.cc +++ b/gtk2_ardour/automation_line.cc @@ -283,7 +283,7 @@ AutomationLine::modify_point_y (ControlPoint& cp, double y) double const x = trackview.editor().sample_to_pixel_unrounded (_time_converter->to((*cp.model())->when) - _offset); - trackview.editor().session()->begin_reversible_command (_("automation event move")); + trackview.editor().begin_reversible_command (_("automation event move")); trackview.editor().session()->add_command ( new MementoCommand (memento_command_binder(), &get_state(), 0)); @@ -304,7 +304,7 @@ AutomationLine::modify_point_y (ControlPoint& cp, double y) trackview.editor().session()->add_command ( new MementoCommand (memento_command_binder(), 0, &alist->get_state())); - trackview.editor().session()->commit_reversible_command (); + trackview.editor().commit_reversible_command (); trackview.editor().session()->set_dirty (); } @@ -456,7 +456,7 @@ AutomationLine::string_to_fraction (string const & s) const void AutomationLine::start_drag_single (ControlPoint* cp, double x, float fraction) { - trackview.editor().session()->begin_reversible_command (_("automation event move")); + trackview.editor().begin_reversible_command (_("automation event move")); trackview.editor().session()->add_command ( new MementoCommand (memento_command_binder(), &get_state(), 0)); @@ -482,7 +482,7 @@ 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().session()->begin_reversible_command (_("automation range move")); + trackview.editor().begin_reversible_command (_("automation range move")); trackview.editor().session()->add_command ( new MementoCommand (memento_command_binder (), &get_state(), 0)); @@ -502,7 +502,7 @@ AutomationLine::start_drag_line (uint32_t i1, uint32_t i2, float fraction) void AutomationLine::start_drag_multiple (list cp, float fraction, XMLNode* state) { - trackview.editor().session()->begin_reversible_command (_("automation range move")); + trackview.editor().begin_reversible_command (_("automation range move")); trackview.editor().session()->add_command ( new MementoCommand (memento_command_binder(), state, 0)); @@ -857,7 +857,7 @@ AutomationLine::is_first_point (ControlPoint& cp) void AutomationLine::remove_point (ControlPoint& cp) { - trackview.editor().session()->begin_reversible_command (_("remove control point")); + trackview.editor().begin_reversible_command (_("remove control point")); XMLNode &before = alist->get_state(); alist->erase (cp.model()); @@ -865,7 +865,7 @@ AutomationLine::remove_point (ControlPoint& cp) trackview.editor().session()->add_command( new MementoCommand (memento_command_binder (), &before, &alist->get_state())); - trackview.editor().session()->commit_reversible_command (); + trackview.editor().commit_reversible_command (); trackview.editor().session()->set_dirty (); } diff --git a/gtk2_ardour/automation_region_view.cc b/gtk2_ardour/automation_region_view.cc index ac9083e6ed..c5afcadfe0 100644 --- a/gtk2_ardour/automation_region_view.cc +++ b/gtk2_ardour/automation_region_view.cc @@ -182,15 +182,15 @@ AutomationRegionView::add_automation_event (GdkEvent *, framepos_t when, double double when_d = when; _line->view_to_model_coord (when_d, y); - view->session()->begin_reversible_command (_("add automation event")); + 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); XMLNode& after = _line->the_list()->get_state(); - view->session()->commit_reversible_command ( - new MementoCommand (_line->memento_command_binder(), &before, &after)); + view->session()->add_command (new MementoCommand (_line->memento_command_binder(), &before, &after)); + view->editor().commit_reversible_command (); view->session()->set_dirty (); } diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc index 3452da3847..ff50c7bece 100644 --- a/gtk2_ardour/automation_time_axis.cc +++ b/gtk2_ardour/automation_time_axis.cc @@ -434,7 +434,7 @@ AutomationTimeAxisView::clear_clicked () { assert (_line || _view); - _session->begin_reversible_command (_("clear automation")); + _editor.begin_reversible_command (_("clear automation")); if (_line) { _line->clear (); @@ -442,7 +442,7 @@ AutomationTimeAxisView::clear_clicked () _view->clear (); } - _session->commit_reversible_command (); + _editor.commit_reversible_command (); _session->set_dirty (); } @@ -627,13 +627,14 @@ AutomationTimeAxisView::add_automation_event (GdkEvent* event, framepos_t when, _editor.snap_to_with_modifier (when, event); - _session->begin_reversible_command (_("add automation event")); + _editor.begin_reversible_command (_("add automation event")); XMLNode& before = list->get_state(); list->add (when, y, with_guard_points); XMLNode& after = list->get_state(); - _session->commit_reversible_command (new MementoCommand (*list, &before, &after)); + _session->add_command (new MementoCommand (*list, &before, &after)); + _editor.commit_reversible_command (); _session->set_dirty (); } diff --git a/gtk2_ardour/crossfade_edit.cc b/gtk2_ardour/crossfade_edit.cc index 9654a9afd9..976ca8ff9e 100644 --- a/gtk2_ardour/crossfade_edit.cc +++ b/gtk2_ardour/crossfade_edit.cc @@ -780,7 +780,7 @@ CrossfadeEditor::apply_preset (Preset *preset) void CrossfadeEditor::apply () { - _session->begin_reversible_command (_("Edit crossfade")); + the_editor().begin_reversible_command (_("Edit crossfade")); XMLNode& before = xfade->get_state (); @@ -793,7 +793,7 @@ CrossfadeEditor::apply () ) ); - _session->commit_reversible_command (); + the_editor().commit_reversible_command (); } void diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index f7e641fbb2..e3c03db510 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -305,6 +305,8 @@ Editor::Editor () selection = new Selection (this); cut_buffer = new Selection (this); + _selection_memento = new SelectionMemento (); + before.clear(); clicked_regionview = 0; clicked_axisview = 0; @@ -1392,6 +1394,7 @@ Editor::set_session (Session *t) /* register for undo history */ _session->register_with_memento_command_factory(id(), this); + _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento); ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated)); @@ -3317,6 +3320,7 @@ void Editor::begin_reversible_command (string name) { if (_session) { + before.push_back (&_selection_memento->get_state ()); _session->begin_reversible_command (name); } } @@ -3325,6 +3329,7 @@ void Editor::begin_reversible_command (GQuark q) { if (_session) { + before.push_back (&_selection_memento->get_state ()); _session->begin_reversible_command (q); } } @@ -3333,6 +3338,14 @@ void Editor::commit_reversible_command () { if (_session) { + if (before.size() == 1) { + _session->add_command (new MementoCommand(*(_selection_memento), before.front(), &_selection_memento->get_state ())); + } + + if (!before.empty()) { + before.pop_back(); + } + _session->commit_reversible_command (); } } @@ -4182,7 +4195,7 @@ Editor::copy_playlists (TimeAxisView* v) void Editor::clear_playlists (TimeAxisView* v) { - begin_reversible_command (_("clear playlists")); + begin_reversible_command (_("clear playlists")); vector > playlists; _session->playlists->get (playlists); mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id); @@ -4220,6 +4233,12 @@ Editor::on_key_release_event (GdkEventKey* ev) // return key_press_focus_accelerator_handler (*this, ev); } +double +Editor::get_y_origin () const +{ + return vertical_adjustment.get_value (); +} + /** Queue up a change to the viewport x origin. * @param frame New x origin. */ @@ -4629,8 +4648,7 @@ Editor::set_punch_range (framepos_t start, framepos_t end, string cmd) _session->set_auto_punch_location (loc); XMLNode &after = _session->locations()->get_state(); _session->add_command (new MementoCommand(*(_session->locations()), &before, &after)); - } - else { + } else { XMLNode &before = tpl->get_state(); tpl->set_hidden (false, this); tpl->set (start, end); @@ -4807,6 +4825,35 @@ Editor::get_regions_from_selection_and_entered () return regions; } +void +Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const +{ + for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) { + RouteTimeAxisView* tatv; + + if ((tatv = dynamic_cast (*i)) != 0) { + boost::shared_ptr pl; + std::vector > results; + boost::shared_ptr tr; + + if ((tr = tatv->track()) == 0) { + /* bus */ + continue; + } + + if ((pl = (tr->playlist())) != 0) { + boost::shared_ptr r = pl->region_by_id (id); + if (r) { + RegionView* marv = tatv->view()->find_view (r); + if (marv) { + regions.push_back (marv); + } + } + } + } + } +} + void Editor::get_regions_corresponding_to (boost::shared_ptr region, vector& regions, bool src_comparison) { @@ -4966,8 +5013,15 @@ Editor::located () } void -Editor::region_view_added (RegionView *) +Editor::region_view_added (RegionView * rv) { + for (list::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) { + if (rv->region ()->id () == (*pr)) { + selection->add (rv); + selection->regions.pending.erase (pr); + break; + } + } _summary->set_background_dirty (); } diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index ab781d3cd4..fa86833dc6 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -58,6 +58,7 @@ #include "enums.h" #include "editor_items.h" #include "region_selection.h" +#include "selection_memento.h" namespace Gtkmm2ext { class TearOff; @@ -149,7 +150,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD double visible_canvas_height () const { return _visible_canvas_height; } - double trackviews_height() const; + double trackviews_height () const; void cycle_snap_mode (); void next_snap_choice (); @@ -372,6 +373,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void update_tearoff_visibility(); void reattach_all_tearoffs (); + double get_y_origin () const; void reset_x_origin (framepos_t); void reset_x_origin_to_follow_playhead (); void reset_y_origin (double); @@ -405,6 +407,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void get_regions_corresponding_to (boost::shared_ptr region, std::vector& regions, bool src_comparison); + void get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const; + void center_screen (framepos_t); TrackViewList axis_views_from_routes (boost::shared_ptr) const; @@ -1716,6 +1720,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD Selection* selection; Selection* cut_buffer; + SelectionMemento* _selection_memento; void time_selection_changed (); void update_time_selection_display (); @@ -1875,7 +1880,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void write_selection (); - XMLNode *before; /* used in *_reversible_command */ + std::list before; /* used in *_reversible_command */ void update_title (); void update_title_s (const std::string & snapshot_name); diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 370a6936b1..73a6e4dad6 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -840,6 +840,12 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move) { if (_copy && first_move) { + if (_x_constrained) { + _editor->begin_reversible_command (Operations::fixed_time_region_copy); + } else { + _editor->begin_reversible_command (Operations::region_copy); + } + /* duplicate the regionview(s) and region(s) */ list new_regionviews; @@ -890,6 +896,14 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move) swap_grab (new_regionviews.front().view->get_canvas_group (), 0, event ? event->motion.time : 0); } + + } else if (!_copy && first_move) { + + if (_x_constrained) { + _editor->begin_reversible_command (_("fixed time region drag")); + } else { + _editor->begin_reversible_command (Operations::region_drag); + } } RegionMotionDrag::motion (event, first_move); @@ -1020,12 +1034,6 @@ RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed return; } - if (_x_constrained) { - _editor->begin_reversible_command (Operations::fixed_time_region_copy); - } else { - _editor->begin_reversible_command (Operations::region_copy); - } - /* insert the regions into their new playlists */ for (list::const_iterator i = _views.begin(); i != _views.end();) { @@ -1102,12 +1110,6 @@ RegionMoveDrag::finished_no_copy ( return; } - if (_x_constrained) { - _editor->begin_reversible_command (_("fixed time region drag")); - } else { - _editor->begin_reversible_command (Operations::region_drag); - } - for (list::const_iterator i = _views.begin(); i != _views.end(); ) { RegionView* rv = i->view; @@ -3632,7 +3634,7 @@ ControlPointDrag::finished (GdkEvent* event, bool movement_occurred) } _point->line().end_drag (_pushing, _final_index); - _editor->session()->commit_reversible_command (); + _editor->commit_reversible_command (); } void @@ -3746,7 +3748,7 @@ LineDrag::finished (GdkEvent* event, bool movement_occured) } } - _editor->session()->commit_reversible_command (); + _editor->commit_reversible_command (); } void @@ -5043,7 +5045,7 @@ AutomationRangeDrag::finished (GdkEvent* event, bool) i->line->end_drag (false, 0); } - _editor->session()->commit_reversible_command (); + _editor->commit_reversible_command (); } void @@ -5189,9 +5191,11 @@ EditorRubberbandSelectDrag::select_things (int button_state, framepos_t x1, fram } Selection::Operation op = ArdourKeyboard::selection_type (button_state); - + _editor->begin_reversible_command (_("rubberband selection")); + _editor->select_all_within (x1, x2 - 1, y1, y2, _editor->track_views, op, false); + _editor->commit_reversible_command (); } diff --git a/gtk2_ardour/editor_locations.cc b/gtk2_ardour/editor_locations.cc index bbaf0daf75..03509ac023 100644 --- a/gtk2_ardour/editor_locations.cc +++ b/gtk2_ardour/editor_locations.cc @@ -28,7 +28,7 @@ using namespace Gtk; EditorLocations::EditorLocations (Editor* e) : EditorComponent (e) { - _locations = new LocationUI; + _locations = new LocationUI (); _scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_NEVER); _scroller.add (*_locations); } diff --git a/gtk2_ardour/editor_markers.cc b/gtk2_ardour/editor_markers.cc index 6d07ecc357..d982de3a32 100644 --- a/gtk2_ardour/editor_markers.cc +++ b/gtk2_ardour/editor_markers.cc @@ -654,12 +654,12 @@ Editor::mouse_add_new_marker (framepos_t where, bool is_cd, bool is_xrun) return; } Location *location = new Location (*_session, where, where, markername, (Location::Flags) flags); - _session->begin_reversible_command (_("add marker")); + begin_reversible_command (_("add marker")); + XMLNode &before = _session->locations()->get_state(); _session->locations()->add (location, true); XMLNode &after = _session->locations()->get_state(); _session->add_command (new MementoCommand(*(_session->locations()), &before, &after)); - _session->commit_reversible_command (); /* find the marker we just added */ @@ -668,6 +668,8 @@ Editor::mouse_add_new_marker (framepos_t where, bool is_cd, bool is_xrun) /* make it the selected marker */ selection->set (lam->start); } + + commit_reversible_command (); } } @@ -721,12 +723,12 @@ Editor::remove_marker (ArdourCanvas::Item& item, GdkEvent*) gint Editor::really_remove_marker (Location* loc) { - _session->begin_reversible_command (_("remove marker")); + begin_reversible_command (_("remove marker")); XMLNode &before = _session->locations()->get_state(); _session->locations()->remove (loc); XMLNode &after = _session->locations()->get_state(); _session->add_command (new MementoCommand(*(_session->locations()), &before, &after)); - _session->commit_reversible_command (); + commit_reversible_command (); return FALSE; } diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 84b632202f..19351d49e4 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -2344,8 +2344,6 @@ Editor::start_selection_grab (ArdourCanvas::Item* /*item*/, GdkEvent* event) clicked_routeview->playlist()->add_region (region, selection->time[clicked_selection].start); _session->add_command(new StatefulDiffCommand (playlist)); - commit_reversible_command (); - c.disconnect (); if (latest_regionviews.empty()) { @@ -2356,8 +2354,11 @@ Editor::start_selection_grab (ArdourCanvas::Item* /*item*/, GdkEvent* event) /* we need to deselect all other regionviews, and select this one i'm ignoring undo stuff, because the region creation will take care of it */ + selection->set (latest_regionviews); + commit_reversible_command (); + _drags->set (new RegionMoveDrag (this, latest_regionviews.front()->get_canvas_group(), latest_regionviews.front(), latest_regionviews, false, false), event); } diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index aa0f316467..9f2f4acccf 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -219,14 +219,14 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions) a = tmp; } + latest_regionviews.clear (); + vector region_added_connections; for (list::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) { region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view))); } - latest_regionviews.clear (); - while (used_playlists.size() > 0) { list >::iterator i = used_playlists.begin(); (*i)->thaw(); @@ -236,8 +236,6 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions) for (vector::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) { (*c).disconnect (); } - - commit_reversible_command (); if (frozen){ EditorThaw(); /* Emit Signal */ @@ -251,7 +249,15 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions) selection->add (latest_regionviews); //these are the new regions created after the split } _ignore_follow_edits = false; + } else { + _ignore_follow_edits = true; + if( working_on_selection ) { + selection->add (latest_regionviews); //these are the new regions created after the split + } + _ignore_follow_edits = false; } + + commit_reversible_command (); } /** Move one extreme of the current range selection. If more than one range is selected, @@ -1928,12 +1934,14 @@ Editor::add_location_from_selection () _session->locations()->next_available_name(rangename,"selection"); Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker); - _session->begin_reversible_command (_("add marker")); + begin_reversible_command (_("add marker")); + XMLNode &before = _session->locations()->get_state(); _session->locations()->add (location, true); XMLNode &after = _session->locations()->get_state(); _session->add_command(new MementoCommand(*(_session->locations()), &before, &after)); - _session->commit_reversible_command (); + + commit_reversible_command (); } void @@ -1948,12 +1956,14 @@ Editor::add_location_mark (framepos_t where) return; } Location *location = new Location (*_session, where, where, markername, Location::IsMark); - _session->begin_reversible_command (_("add marker")); + begin_reversible_command (_("add marker")); + XMLNode &before = _session->locations()->get_state(); _session->locations()->add (location, true); XMLNode &after = _session->locations()->get_state(); _session->add_command(new MementoCommand(*(_session->locations()), &before, &after)); - _session->commit_reversible_command (); + + commit_reversible_command (); } void @@ -1968,7 +1978,8 @@ Editor::remove_location_at_playhead_cursor () if (_session) { //set up for undo - _session->begin_reversible_command (_("remove marker")); + begin_reversible_command (_("remove marker")); + XMLNode &before = _session->locations()->get_state(); bool removed = false; @@ -1986,7 +1997,8 @@ Editor::remove_location_at_playhead_cursor () if (removed) { XMLNode &after = _session->locations()->get_state(); _session->add_command(new MementoCommand(*(_session->locations()), &before, &after)); - _session->commit_reversible_command (); + + commit_reversible_command (); } } } @@ -2001,7 +2013,8 @@ Editor::add_locations_from_region () return; } - _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker")); + begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker")); + XMLNode &before = _session->locations()->get_state(); for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) { @@ -2015,7 +2028,8 @@ Editor::add_locations_from_region () XMLNode &after = _session->locations()->get_state(); _session->add_command (new MementoCommand(*(_session->locations()), &before, &after)); - _session->commit_reversible_command (); + + commit_reversible_command (); } /** Add a single range marker around all selected regions */ @@ -2028,7 +2042,8 @@ Editor::add_location_from_region () return; } - _session->begin_reversible_command (_("add marker")); + begin_reversible_command (_("add marker")); + XMLNode &before = _session->locations()->get_state(); string markername; @@ -2051,7 +2066,8 @@ Editor::add_location_from_region () XMLNode &after = _session->locations()->get_state(); _session->add_command (new MementoCommand(*(_session->locations()), &before, &after)); - _session->commit_reversible_command (); + + commit_reversible_command (); } /* MARKS */ @@ -2107,12 +2123,14 @@ void Editor::clear_markers () { if (_session) { - _session->begin_reversible_command (_("clear markers")); + begin_reversible_command (_("clear markers")); + XMLNode &before = _session->locations()->get_state(); _session->locations()->clear_markers (); XMLNode &after = _session->locations()->get_state(); _session->add_command(new MementoCommand(*(_session->locations()), &before, &after)); - _session->commit_reversible_command (); + + commit_reversible_command (); } } @@ -2120,27 +2138,30 @@ void Editor::clear_ranges () { if (_session) { - _session->begin_reversible_command (_("clear ranges")); + begin_reversible_command (_("clear ranges")); + XMLNode &before = _session->locations()->get_state(); _session->locations()->clear_ranges (); XMLNode &after = _session->locations()->get_state(); _session->add_command(new MementoCommand(*(_session->locations()), &before, &after)); - _session->commit_reversible_command (); + + commit_reversible_command (); } } void Editor::clear_locations () { - _session->begin_reversible_command (_("clear locations")); + begin_reversible_command (_("clear locations")); + XMLNode &before = _session->locations()->get_state(); _session->locations()->clear (); XMLNode &after = _session->locations()->get_state(); _session->add_command(new MementoCommand(*(_session->locations()), &before, &after)); - _session->commit_reversible_command (); - _session->locations()->clear (); + + commit_reversible_command (); } void @@ -4537,11 +4558,11 @@ Editor::duplicate_some_regions (RegionSelection& regions, float times) foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end()); } - commit_reversible_command (); - if (!foo.empty()) { selection->set (foo); } + + commit_reversible_command (); } void @@ -5168,8 +5189,8 @@ Editor::reset_region_gain_envelopes () return; } - _session->begin_reversible_command (_("reset region gain")); - + begin_reversible_command (_("reset region gain")); + for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { AudioRegionView* const arv = dynamic_cast(*i); if (arv) { @@ -5180,8 +5201,8 @@ Editor::reset_region_gain_envelopes () _session->add_command (new MementoCommand(*arv->audio_region()->envelope().get(), &before, &alist->get_state())); } } - - _session->commit_reversible_command (); + + commit_reversible_command (); } void @@ -5221,8 +5242,8 @@ Editor::toggle_gain_envelope_active () return; } - _session->begin_reversible_command (_("region gain envelope active")); - + begin_reversible_command (_("region gain envelope active")); + for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { AudioRegionView* const arv = dynamic_cast(*i); if (arv) { @@ -5231,8 +5252,8 @@ Editor::toggle_gain_envelope_active () _session->add_command (new StatefulDiffCommand (arv->region())); } } - - _session->commit_reversible_command (); + + commit_reversible_command (); } void @@ -5248,15 +5269,15 @@ Editor::toggle_region_lock () return; } - _session->begin_reversible_command (_("toggle region lock")); - + begin_reversible_command (_("toggle region lock")); + for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { (*i)->region()->clear_changes (); (*i)->region()->set_locked (!(*i)->region()->locked()); _session->add_command (new StatefulDiffCommand ((*i)->region())); } - - _session->commit_reversible_command (); + + commit_reversible_command (); } void @@ -5272,15 +5293,15 @@ Editor::toggle_region_video_lock () return; } - _session->begin_reversible_command (_("Toggle Video Lock")); - + begin_reversible_command (_("Toggle Video Lock")); + for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { (*i)->region()->clear_changes (); (*i)->region()->set_video_locked (!(*i)->region()->video_locked()); _session->add_command (new StatefulDiffCommand ((*i)->region())); } - - _session->commit_reversible_command (); + + commit_reversible_command (); } void @@ -5296,16 +5317,16 @@ Editor::toggle_region_lock_style () return; } - _session->begin_reversible_command (_("region lock style")); - + begin_reversible_command (_("region lock style")); + for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { (*i)->region()->clear_changes (); PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime; (*i)->region()->set_position_lock_style (ns); _session->add_command (new StatefulDiffCommand ((*i)->region())); } - - _session->commit_reversible_command (); + + commit_reversible_command (); } void @@ -5321,15 +5342,15 @@ Editor::toggle_opaque_region () return; } - _session->begin_reversible_command (_("change region opacity")); - + begin_reversible_command (_("change region opacity")); + for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { (*i)->region()->clear_changes (); (*i)->region()->set_opaque (!(*i)->region()->opaque()); _session->add_command (new StatefulDiffCommand ((*i)->region())); } - - _session->commit_reversible_command (); + + commit_reversible_command (); } void @@ -6137,8 +6158,8 @@ Editor::split_region_at_transients () return; } - _session->begin_reversible_command (_("split regions")); - + begin_reversible_command (_("split regions")); + for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) { RegionSelection::iterator tmp; @@ -6155,8 +6176,8 @@ Editor::split_region_at_transients () i = tmp; } - - _session->commit_reversible_command (); + + commit_reversible_command (); } @@ -6344,14 +6365,14 @@ Editor::place_transient() framepos_t where = get_preferred_edit_position(); - _session->begin_reversible_command (_("place transient")); - + begin_reversible_command (_("place transient")); + for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) { framepos_t position = (*r)->region()->position(); (*r)->region()->add_transient(where - position); } - - _session->commit_reversible_command (); + + commit_reversible_command (); } void @@ -6379,8 +6400,8 @@ Editor::snap_regions_to_grid () return; } - _session->begin_reversible_command (_("snap regions to grid")); - + begin_reversible_command (_("snap regions to grid")); + for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) { boost::shared_ptr pl = (*r)->region()->playlist(); @@ -6403,8 +6424,8 @@ Editor::snap_regions_to_grid () (*i)->thaw(); used_playlists.pop_front(); } - - _session->commit_reversible_command (); + + commit_reversible_command (); } void @@ -6462,8 +6483,8 @@ Editor::close_region_gaps () /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */ - _session->begin_reversible_command (_("close region gaps")); - + begin_reversible_command (_("close region gaps")); + int idx = 0; boost::shared_ptr last_region; @@ -6502,8 +6523,8 @@ Editor::close_region_gaps () (*i)->thaw(); used_playlists.pop_front(); } - - _session->commit_reversible_command (); + + commit_reversible_command (); } void @@ -7111,7 +7132,7 @@ Editor::toggle_region_mute () (*i)->region()->playlist()->clear_changes (); (*i)->region()->set_muted (!(*i)->region()->muted ()); - _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist())); + _session->add_command (new StatefulDiffCommand ((*i)->region())); } diff --git a/gtk2_ardour/location_ui.cc b/gtk2_ardour/location_ui.cc index 689706ba01..3c4a28097e 100644 --- a/gtk2_ardour/location_ui.cc +++ b/gtk2_ardour/location_ui.cc @@ -33,6 +33,7 @@ #include "location_ui.h" #include "prompter.h" #include "utils.h" +#include "public_editor.h" #include "i18n.h" @@ -853,12 +854,12 @@ LocationUI::do_location_remove (ARDOUR::Location *loc) return FALSE; } - _session->begin_reversible_command (_("remove marker")); + PublicEditor::instance().begin_reversible_command (_("remove marker")); XMLNode &before = _session->locations()->get_state(); _session->locations()->remove (loc); XMLNode &after = _session->locations()->get_state(); _session->add_command(new MementoCommand(*(_session->locations()), &before, &after)); - _session->commit_reversible_command (); + PublicEditor::instance().commit_reversible_command (); return FALSE; } @@ -1017,12 +1018,12 @@ LocationUI::add_new_location() if (Config->get_name_new_markers()) { newest_location = location; } - _session->begin_reversible_command (_("add marker")); + PublicEditor::instance().begin_reversible_command (_("add marker")); XMLNode &before = _session->locations()->get_state(); _session->locations()->add (location, true); XMLNode &after = _session->locations()->get_state(); _session->add_command (new MementoCommand(*(_session->locations()), &before, &after)); - _session->commit_reversible_command (); + PublicEditor::instance().commit_reversible_command (); } } @@ -1036,12 +1037,12 @@ LocationUI::add_new_range() framepos_t where = _session->audible_frame(); _session->locations()->next_available_name(rangename,"unnamed"); Location *location = new Location (*_session, where, where, rangename, Location::IsRangeMarker); - _session->begin_reversible_command (_("add range marker")); + PublicEditor::instance().begin_reversible_command (_("add range marker")); XMLNode &before = _session->locations()->get_state(); _session->locations()->add (location, true); XMLNode &after = _session->locations()->get_state(); _session->add_command (new MementoCommand(*(_session->locations()), &before, &after)); - _session->commit_reversible_command (); + PublicEditor::instance().commit_reversible_command (); } } diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 6b6d40f93c..85ea05fe3f 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -3350,7 +3350,7 @@ MidiRegionView::selection_as_cut_buffer () const bool MidiRegionView::paste (framepos_t pos, const ::Selection& selection, PasteContext& ctx) { - trackview.session()->begin_reversible_command (Operations::paste); + trackview.editor().begin_reversible_command (Operations::paste); // Paste notes, if available MidiNoteSelection::const_iterator m = selection.midi_notes.get_nth(ctx.counts.n_notes()); @@ -3366,7 +3366,7 @@ MidiRegionView::paste (framepos_t pos, const ::Selection& selection, PasteContex a->second->paste(pos, selection, ctx); } - trackview.session()->commit_reversible_command (); + trackview.editor().commit_reversible_command (); return true; } diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index 9969d9d49e..c2972116a1 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -245,6 +245,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi virtual void set_zoom_focus (Editing::ZoomFocus) = 0; virtual Editing::ZoomFocus get_zoom_focus () const = 0; virtual framecnt_t get_current_zoom () const = 0; + virtual void reset_zoom (framecnt_t) = 0; virtual PlaylistSelector& playlist_selector() const = 0; virtual void clear_playlist (boost::shared_ptr) = 0; virtual void new_playlists (TimeAxisView*) = 0; @@ -288,6 +289,8 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi virtual void prepare_for_cleanup () = 0; virtual void finish_cleanup () = 0; virtual void reset_x_origin (framepos_t frame) = 0; + virtual double get_y_origin () const = 0; + virtual void reset_y_origin (double pos) = 0; virtual void remove_last_capture () = 0; virtual void maximise_editing_space () = 0; virtual void restore_editing_space () = 0; @@ -403,6 +406,10 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi virtual void stop_canvas_autoscroll () = 0; virtual bool autoscroll_active() const = 0; + virtual void begin_reversible_command (std::string cmd_name) = 0; + virtual void begin_reversible_command (GQuark) = 0; + virtual void commit_reversible_command () = 0; + virtual MouseCursors const * cursors () const = 0; virtual VerboseCursor * verbose_cursor () const = 0; @@ -420,6 +427,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi virtual void get_regions_at (RegionSelection &, framepos_t where, TrackViewList const &) const = 0; virtual RegionSelection get_regions_from_selection_and_mouse (framepos_t) = 0; + virtual void get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const = 0; /// Singleton instance, set up by Editor::Editor() diff --git a/gtk2_ardour/region_editor.cc b/gtk2_ardour/region_editor.cc index 511314dfc5..16888fb688 100644 --- a/gtk2_ardour/region_editor.cc +++ b/gtk2_ardour/region_editor.cc @@ -33,6 +33,7 @@ #include "main_clock.h" #include "gui_thread.h" #include "region_editor.h" +#include "public_editor.h" #include "i18n.h" @@ -269,7 +270,7 @@ RegionEditor::connect_editor_events () void RegionEditor::position_clock_changed () { - _session->begin_reversible_command (_("change region start position")); + PublicEditor::instance().begin_reversible_command (_("change region start position")); boost::shared_ptr pl = _region->playlist(); @@ -279,13 +280,13 @@ RegionEditor::position_clock_changed () _session->add_command(new StatefulDiffCommand (_region)); } - _session->commit_reversible_command (); + PublicEditor::instance().commit_reversible_command (); } void RegionEditor::end_clock_changed () { - _session->begin_reversible_command (_("change region end position")); + PublicEditor::instance().begin_reversible_command (_("change region end position")); boost::shared_ptr pl = _region->playlist(); @@ -295,7 +296,7 @@ RegionEditor::end_clock_changed () _session->add_command(new StatefulDiffCommand (_region)); } - _session->commit_reversible_command (); + PublicEditor::instance().commit_reversible_command (); end_clock.set (_region->position() + _region->length() - 1, true); } @@ -305,7 +306,7 @@ RegionEditor::length_clock_changed () { framecnt_t frames = length_clock.current_time(); - _session->begin_reversible_command (_("change region length")); + PublicEditor::instance().begin_reversible_command (_("change region length")); boost::shared_ptr pl = _region->playlist(); @@ -315,7 +316,7 @@ RegionEditor::length_clock_changed () _session->add_command(new StatefulDiffCommand (_region)); } - _session->commit_reversible_command (); + PublicEditor::instance().commit_reversible_command (); length_clock.set (_region->length()); } @@ -399,25 +400,25 @@ RegionEditor::audition_state_changed (bool yn) void RegionEditor::sync_offset_absolute_clock_changed () { - _session->begin_reversible_command (_("change region sync point")); + PublicEditor::instance().begin_reversible_command (_("change region sync point")); _region->clear_changes (); _region->set_sync_position (sync_offset_absolute_clock.current_time()); _session->add_command (new StatefulDiffCommand (_region)); - _session->commit_reversible_command (); + PublicEditor::instance().commit_reversible_command (); } void RegionEditor::sync_offset_relative_clock_changed () { - _session->begin_reversible_command (_("change region sync point")); + PublicEditor::instance().begin_reversible_command (_("change region sync point")); _region->clear_changes (); _region->set_sync_position (sync_offset_relative_clock.current_time() + _region->position ()); _session->add_command (new StatefulDiffCommand (_region)); - _session->commit_reversible_command (); + PublicEditor::instance().commit_reversible_command (); } bool diff --git a/gtk2_ardour/region_gain_line.cc b/gtk2_ardour/region_gain_line.cc index b010efc04c..cbeb1224af 100644 --- a/gtk2_ardour/region_gain_line.cc +++ b/gtk2_ardour/region_gain_line.cc @@ -69,7 +69,7 @@ AudioRegionGainLine::start_drag_single (ControlPoint* cp, double x, float fracti void AudioRegionGainLine::remove_point (ControlPoint& cp) { - trackview.editor().session()->begin_reversible_command (_("remove control point")); + trackview.editor().begin_reversible_command (_("remove control point")); XMLNode &before = alist->get_state(); if (!rv.audio_region()->envelope_active()) { @@ -81,7 +81,7 @@ AudioRegionGainLine::remove_point (ControlPoint& cp) alist->erase (cp.model()); trackview.editor().session()->add_command (new MementoCommand(*alist.get(), &before, &alist->get_state())); - trackview.editor().session()->commit_reversible_command (); + trackview.editor().commit_reversible_command (); trackview.editor().session()->set_dirty (); } diff --git a/gtk2_ardour/region_selection.cc b/gtk2_ardour/region_selection.cc index 57ab59fd68..54e5aa3acc 100644 --- a/gtk2_ardour/region_selection.cc +++ b/gtk2_ardour/region_selection.cc @@ -73,6 +73,7 @@ void RegionSelection::clear_all() { clear(); + pending.clear (); _bylayer.clear(); } diff --git a/gtk2_ardour/region_selection.h b/gtk2_ardour/region_selection.h index 36e40061c1..0cd603e5f4 100644 --- a/gtk2_ardour/region_selection.h +++ b/gtk2_ardour/region_selection.h @@ -62,6 +62,7 @@ class RegionSelection : public std::list void by_track (std::list&) const; std::set > playlists () const; + std::list pending; private: void remove_it (RegionView*); diff --git a/gtk2_ardour/rhythm_ferret.cc b/gtk2_ardour/rhythm_ferret.cc index f159331018..e257f56b52 100644 --- a/gtk2_ardour/rhythm_ferret.cc +++ b/gtk2_ardour/rhythm_ferret.cc @@ -352,7 +352,7 @@ RhythmFerret::do_split_action () editor.EditorFreeze(); /* Emit signal */ - _session->begin_reversible_command (_("split regions (rhythm ferret)")); + editor.begin_reversible_command (_("split regions (rhythm ferret)")); /* Merge the transient positions for regions in consideration */ AnalysisFeatureList merged_features; @@ -381,7 +381,7 @@ RhythmFerret::do_split_action () i = tmp; } - _session->commit_reversible_command (); + editor.commit_reversible_command (); editor.EditorThaw(); /* Emit signal */ } diff --git a/gtk2_ardour/selection.cc b/gtk2_ardour/selection.cc index 7e2ee1338b..b29f5c3241 100644 --- a/gtk2_ardour/selection.cc +++ b/gtk2_ardour/selection.cc @@ -1206,6 +1206,7 @@ Selection::get_state () const so that re-opening plugin windows for editor mixer strips works */ + char buf[32]; XMLNode* node = new XMLNode (X_("Selection")); for (TrackSelection::const_iterator i = tracks.begin(); i != tracks.end(); ++i) { @@ -1221,9 +1222,23 @@ Selection::get_state () const } } + for (RegionSelection::const_iterator i = regions.begin(); i != regions.end(); ++i) { + XMLNode* r = node->add_child (X_("Region")); + r->add_property (X_("id"), atoi ((*i)->region ()->id ().to_s ().c_str())); + + } + + for (TimeSelection::const_iterator i = time.begin(); i != time.end(); ++i) { + XMLNode* t = node->add_child (X_("AudioRange")); + snprintf(buf, sizeof(buf), "%ld", (*i).start); + t->add_property (X_("start"), string(buf)); + snprintf(buf, sizeof(buf), "%ld", (*i).end); + t->add_property (X_("end"), string(buf)); + } + for (MarkerSelection::const_iterator i = markers.begin(); i != markers.end(); ++i) { XMLNode* t = node->add_child (X_("Marker")); - + bool is_start; Location* loc = editor->find_location_from_marker (*i, is_start); @@ -1241,6 +1256,11 @@ Selection::set_state (XMLNode const & node, int) return -1; } + clear_regions (); + clear_time (); + clear_tracks (); + clear_markers (); + XMLNodeList children = node.children (); for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) { if ((*i)->name() == X_("RouteView")) { @@ -1253,6 +1273,36 @@ Selection::set_state (XMLNode const & node, int) add (rtv); } + } else if ((*i)->name() == X_("Region")) { + XMLProperty* prop_id = (*i)->property (X_("id")); + assert (prop_id); + PBD::ID id (prop_id->value ()); + + RegionSelection rs; + editor->get_regionviews_by_id (id, rs); + + if (!rs.empty ()) { + add (rs); + } else { + /* + regionviews are being constructed - stash the region IDs + so we can identify them in Editor::region_view_added () + */ + regions.pending.push_back (id); + } + + } else if ((*i)->name() == X_("AudioRange")) { + XMLProperty* prop_start = (*i)->property (X_("start")); + XMLProperty* prop_end = (*i)->property (X_("end")); + + assert (prop_start); + assert (prop_end); + + framepos_t s (atol (prop_start->value ().c_str())); + framepos_t e (atol (prop_end->value ().c_str())); + + set_preserving_all_ranges (s, e); + } else if ((*i)->name() == X_("AutomationView")) { XMLProperty* prop_id = (*i)->property (X_("id")); diff --git a/gtk2_ardour/selection_memento.cc b/gtk2_ardour/selection_memento.cc new file mode 100644 index 0000000000..67e527b07f --- /dev/null +++ b/gtk2_ardour/selection_memento.cc @@ -0,0 +1,95 @@ +/* + Copyright (C) 2014 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "selection_memento.h" +#include "editing.h" +#include "public_editor.h" + +#include "i18n.h" + +SelectionMemento::SelectionMemento () +{ +} + +SelectionMemento::~SelectionMemento () +{ +} + +XMLNode& +SelectionMemento::get_state () { + + XMLNode* node = new XMLNode ("SelectionMemento"); + char buf[32]; + PublicEditor& editor = PublicEditor::instance(); + + node->add_property ("mouse-mode", enum2str(editor.current_mouse_mode())); + snprintf (buf, sizeof(buf), "%" PRId64, editor.get_current_zoom()); + node->add_property ("zoom", buf); + snprintf (buf, sizeof (buf), "%" PRIi64, editor.leftmost_sample()); + node->add_property ("left-frame", buf); + snprintf (buf, sizeof (buf), "%f", editor.get_y_origin()); + node->add_property ("y-origin", buf); + + node->add_child_nocopy (editor.get_selection().get_state()); + return *node; +} + +int +SelectionMemento::set_state (const XMLNode& node, int /*version*/) { + + const XMLProperty* prop; + PublicEditor& editor = PublicEditor::instance(); + if (node.name() != X_("SelectionMemento")) { + return -1; + } + + if ((prop = node.property ("mouse-mode"))) { + Editing::MouseMode m = Editing::str2mousemode(prop->value()); + editor.set_mouse_mode (m, true); + } else { + editor.set_mouse_mode (Editing::MouseObject, true); + } + + if ((prop = node.property ("zoom"))) { + /* older versions of ardour used floating point samples_per_pixel */ + double f = PBD::atof (prop->value()); + editor.reset_zoom (llrintf (f)); + } + + if ((prop = node.property ("left-frame")) != 0) { + framepos_t pos; + if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) { + if (pos < 0) { + pos = 0; + } + editor.reset_x_origin (pos); + } + } + + if ((prop = node.property ("y-origin")) != 0) { + editor.reset_y_origin (atof (prop->value ().c_str())); + } + + XMLNodeList children = node.children (); + for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) { + editor.get_selection().set_state (**i, Stateful::current_state_version); + } + + return 0; +} diff --git a/gtk2_ardour/selection_memento.h b/gtk2_ardour/selection_memento.h new file mode 100644 index 0000000000..571f9c75b4 --- /dev/null +++ b/gtk2_ardour/selection_memento.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2014 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __ardour_gtk_selection_memento_h__ +#define __ardour_gtk_selection_memento_h__ + +#include "pbd/statefuldestructible.h" + +class SelectionMemento : public PBD::StatefulDestructible +{ +public: + SelectionMemento (); + ~SelectionMemento (); + + XMLNode& get_state (); + int set_state (const XMLNode&, int version); +}; +#endif /* __ardour_gtk_selection_memento_h__ */ diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index c38c8509ab..165cd2f82b 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -201,6 +201,7 @@ gtk2_ardour_sources = [ 'ruler_dialog.cc', 'search_path_option.cc', 'selection.cc', + 'selection_memento.cc', 'send_ui.cc', 'session_dialog.cc', 'session_import_dialog.cc', -- cgit v1.2.3