diff options
author | Hans Fugal <hans@fugal.net> | 2006-08-04 03:46:07 +0000 |
---|---|---|
committer | Hans Fugal <hans@fugal.net> | 2006-08-04 03:46:07 +0000 |
commit | dca612e82af4f89dad4f15454cbbb15694fa077c (patch) | |
tree | 5ab9e96d4e4314554a818b541bbc8e0e5f0c3e70 | |
parent | aacae5f32b63f2847730eebc3b556f061ac5f6f1 (diff) | |
parent | 5756373841675a879833f98bb4008dd0c40714d3 (diff) |
Merging undo branch into trunk. It compiles and works for limited tests. Keep
your eye on it. Actual serialization is still not there, but the next step.
git-svn-id: svn://localhost/ardour2/trunk@758 d708f5d6-7413-0410-9779-e7cbd77b26cf
37 files changed, 751 insertions, 293 deletions
diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc index feb8f4fd0b..bdea3d39a2 100644 --- a/gtk2_ardour/audio_region_view.cc +++ b/gtk2_ardour/audio_region_view.cc @@ -30,6 +30,7 @@ #include <ardour/audioregion.h> #include <ardour/audiosource.h> #include <ardour/audio_diskstream.h> +#include <pbd/memento_command.h> #include "streamview.h" #include "audio_region_view.h" @@ -898,18 +899,20 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev) gain_line->view_to_model_y (y); trackview.session().begin_reversible_command (_("add gain control point")); - trackview.session().add_undo (audio_region().envelope().get_memento()); + XMLNode &before = audio_region().envelope().get_state(); if (!audio_region().envelope_active()) { - trackview.session().add_undo( bind( mem_fun(audio_region(), &AudioRegion::set_envelope_active), false) ); + XMLNode &before = audio_region().get_state(); audio_region().set_envelope_active(true); - trackview.session().add_redo( bind( mem_fun(audio_region(), &AudioRegion::set_envelope_active), true) ); + XMLNode &after = audio_region().get_state(); + trackview.session().add_command (new MementoCommand<AudioRegion>(audio_region(), before, after)); } audio_region().envelope().add (fx, y); - trackview.session().add_redo_no_execute (audio_region().envelope().get_memento()); + XMLNode &after = audio_region().envelope().get_state(); + trackview.session().add_command (new MementoCommand<Curve>(audio_region().envelope(), before, after)); trackview.session().commit_reversible_command (); } diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc index 376e05aa4c..9ae94d1fe0 100644 --- a/gtk2_ardour/audio_time_axis.cc +++ b/gtk2_ardour/audio_time_axis.cc @@ -31,6 +31,7 @@ #include <pbd/error.h> #include <pbd/stl_delete.h> #include <pbd/whitespace.h> +#include <pbd/memento_command.h> #include <gtkmm2ext/gtk_ui.h> #include <gtkmm2ext/selector.h> diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc index b87a71ca87..4cf6779c98 100644 --- a/gtk2_ardour/automation_line.cc +++ b/gtk2_ardour/automation_line.cc @@ -23,6 +23,7 @@ #include <vector> #include <pbd/stl_delete.h> +#include <pbd/memento_command.h> #include <ardour/automation_event.h> #include <ardour/curve.h> @@ -887,7 +888,7 @@ AutomationLine::start_drag (ControlPoint* cp, float fraction) } trackview.editor.current_session()->begin_reversible_command (str); - trackview.editor.current_session()->add_undo (get_memento()); + trackview.editor.current_session()->add_command (new MementoUndoCommand<AutomationLine>(*this, get_state())); first_drag_fraction = fraction; last_drag_fraction = fraction; @@ -936,7 +937,7 @@ AutomationLine::end_drag (ControlPoint* cp) update_pending = false; - trackview.editor.current_session()->add_redo_no_execute (get_memento()); + trackview.editor.current_session()->add_command (new MementoRedoCommand<AutomationLine>(*this, get_state())); trackview.editor.current_session()->commit_reversible_command (); trackview.editor.current_session()->set_dirty (); } @@ -1013,11 +1014,11 @@ AutomationLine::remove_point (ControlPoint& cp) model_representation (cp, mr); trackview.editor.current_session()->begin_reversible_command (_("remove control point")); - trackview.editor.current_session()->add_undo (get_memento()); + XMLNode &before = get_state(); alist.erase (mr.start, mr.end); - trackview.editor.current_session()->add_redo_no_execute (get_memento()); + trackview.editor.current_session()->add_command(new MementoCommand<AutomationLine>(*this, before, get_state())); trackview.editor.current_session()->commit_reversible_command (); trackview.editor.current_session()->set_dirty (); } @@ -1225,9 +1226,9 @@ void AutomationLine::clear () { /* parent must create command */ - trackview.editor.current_session()->add_undo (get_memento()); + XMLNode &before = get_state(); alist.clear(); - trackview.editor.current_session()->add_redo_no_execute (get_memento()); + trackview.editor.current_session()->add_command (new MementoCommand<AutomationLine>(*this, before, get_state())); trackview.editor.current_session()->commit_reversible_command (); trackview.editor.current_session()->set_dirty (); } @@ -1266,3 +1267,15 @@ AutomationLine::hide_all_but_selected_control_points () } } } + +XMLNode &AutomationLine::get_state(void) +{ + // TODO + return alist.get_state(); +} + +int AutomationLine::set_state(const XMLNode &node) +{ + // TODO + alist.set_state(node); +} diff --git a/gtk2_ardour/automation_line.h b/gtk2_ardour/automation_line.h index e922de6c80..9c6b932dfd 100644 --- a/gtk2_ardour/automation_line.h +++ b/gtk2_ardour/automation_line.h @@ -94,7 +94,7 @@ class ControlPoint ShapeType _shape; }; -class AutomationLine : public sigc::trackable +class AutomationLine : public sigc::trackable, public Stateful { public: AutomationLine (const string & name, TimeAxisView&, ArdourCanvas::Group&, ARDOUR::AutomationList&); @@ -158,6 +158,9 @@ class AutomationLine : public sigc::trackable bool is_last_point (ControlPoint &); bool is_first_point (ControlPoint &); + XMLNode& get_state (void); + int set_state (const XMLNode&); + protected: string _name; guint32 _height; diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc index cdeed5cc4d..6e2a93889f 100644 --- a/gtk2_ardour/automation_time_axis.cc +++ b/gtk2_ardour/automation_time_axis.cc @@ -1,4 +1,5 @@ #include <ardour/route.h> +#include <pbd/memento_command.h> #include "ardour_ui.h" #include "automation_time_axis.h" @@ -476,13 +477,13 @@ AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& sel AutomationList& alist (line.the_list()); bool ret = false; - _session.add_undo (alist.get_memento()); + XMLNode &before = alist.get_state(); switch (op) { case Cut: if ((what_we_got = alist.cut (selection.time.front().start, selection.time.front().end)) != 0) { editor.get_cut_buffer().add (what_we_got); - _session.add_redo_no_execute (alist.get_memento()); + _session.add_command(new MementoCommand<AutomationList>(alist, before, alist.get_state())); ret = true; } break; @@ -494,7 +495,7 @@ AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& sel case Clear: if ((what_we_got = alist.cut (selection.time.front().start, selection.time.front().end)) != 0) { - _session.add_redo_no_execute (alist.get_memento()); + _session.add_command(new MementoCommand<AutomationList>(alist, before, alist.get_state())); delete what_we_got; what_we_got = 0; ret = true; @@ -526,7 +527,7 @@ AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& { AutomationList& alist (line.the_list()); - _session.add_undo (alist.get_memento()); + _session.add_command (new MementoUndoCommand<AutomationList>(alist, alist.get_state())); for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) { @@ -557,7 +558,7 @@ AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointS AutomationList& alist (line.the_list()); bool ret = false; - _session.add_undo (alist.get_memento()); + XMLNode &before = alist.get_state(); for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) { @@ -569,7 +570,7 @@ AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointS case Cut: if ((what_we_got = alist.cut ((*i).start, (*i).end)) != 0) { editor.get_cut_buffer().add (what_we_got); - _session.add_redo_no_execute (alist.get_memento()); + _session.add_command (new MementoCommand<AutomationList>(alist, before, alist.get_state())); ret = true; } break; @@ -581,7 +582,7 @@ AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointS case Clear: if ((what_we_got = alist.cut ((*i).start, (*i).end)) != 0) { - _session.add_redo_no_execute (alist.get_memento()); + _session.add_command (new MementoCommand<AutomationList>(alist, before, alist.get_state())); delete what_we_got; what_we_got = 0; ret = true; @@ -638,9 +639,9 @@ AutomationTimeAxisView::paste_one (AutomationLine& line, jack_nframes_t pos, flo (*x)->value = foo; } - _session.add_undo (alist.get_memento()); + XMLNode &before = alist.get_state(); alist.paste (copy, pos, times); - _session.add_redo_no_execute (alist.get_memento()); + _session.add_command (new MementoCommand<AutomationList>(alist, before, alist.get_state())); return true; } diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 518ef7217a..513251085c 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -28,6 +28,7 @@ #include <pbd/convert.h> #include <pbd/error.h> +#include <pbd/memento_command.h> #include <gtkmm/image.h> #include <gdkmm/color.h> @@ -2878,8 +2879,8 @@ void Editor::begin_reversible_command (string name) { if (session) { - UndoAction ua = get_memento(); - session->begin_reversible_command (name, &ua); + before = &get_state(); + session->begin_reversible_command (name); } } @@ -2887,8 +2888,7 @@ void Editor::commit_reversible_command () { if (session) { - UndoAction ua = get_memento(); - session->commit_reversible_command (&ua); + session->commit_reversible_command (new MementoCommand<Editor>(*this, *before, get_state())); } } diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index a1e69e2ad1..c31dfd5ede 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1596,13 +1596,14 @@ class Editor : public PublicEditor UndoAction get_memento() const; + XMLNode *before; /* used in *_reversible_command */ void begin_reversible_command (string cmd_name); void commit_reversible_command (); /* visual history */ UndoHistory visual_history; - UndoCommand current_visual_command; + UndoTransaction current_visual_command; void begin_reversible_visual_command (const string & cmd_name); void commit_reversible_visual_command (); diff --git a/gtk2_ardour/editor_audio_import.cc b/gtk2_ardour/editor_audio_import.cc index f8c632f08a..7524f9605c 100644 --- a/gtk2_ardour/editor_audio_import.cc +++ b/gtk2_ardour/editor_audio_import.cc @@ -31,6 +31,7 @@ #include <ardour/audio_track.h> #include <ardour/audioplaylist.h> #include <ardour/audiofilesource.h> +#include <pbd/memento_command.h> #include "ardour_ui.h" #include "editor.h" @@ -320,9 +321,9 @@ Editor::finish_bringing_in_audio (AudioRegion& region, uint32_t in_chans, uint32 AudioRegion* copy = new AudioRegion (region); begin_reversible_command (_("insert sndfile")); - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->add_region (*copy, pos); - session->add_redo_no_execute (playlist->get_memento()); + session->add_command (new MementoCommand<Playlist>(*playlist, before, playlist->get_state())); commit_reversible_command (); pos += region.length(); diff --git a/gtk2_ardour/editor_keyboard.cc b/gtk2_ardour/editor_keyboard.cc index d2b7c1160e..f48d860d15 100644 --- a/gtk2_ardour/editor_keyboard.cc +++ b/gtk2_ardour/editor_keyboard.cc @@ -20,6 +20,7 @@ #include <ardour/audioregion.h> #include <ardour/playlist.h> +#include <pbd/memento_command.h> #include "editor.h" #include "region_view.h" @@ -102,11 +103,12 @@ Editor::kbd_mute_unmute_region () { if (entered_regionview) { begin_reversible_command (_("mute region")); - session->add_undo (entered_regionview->region().playlist()->get_memento()); + XMLNode &before = entered_regionview->region().playlist()->get_state(); entered_regionview->region().set_muted (!entered_regionview->region().muted()); - session->add_redo_no_execute (entered_regionview->region().playlist()->get_memento()); + XMLNode &after = entered_regionview->region().playlist()->get_state(); + session->add_command (new MementoCommand<ARDOUR::Playlist>(*(entered_regionview->region().playlist()), before, after)); commit_reversible_command(); } } diff --git a/gtk2_ardour/editor_markers.cc b/gtk2_ardour/editor_markers.cc index f34b8590a4..ccc1415888 100644 --- a/gtk2_ardour/editor_markers.cc +++ b/gtk2_ardour/editor_markers.cc @@ -26,6 +26,7 @@ #include <gtkmm2ext/gtk_ui.h> #include <ardour/location.h> +#include <pbd/memento_command.h> #include "editor.h" #include "marker.h" @@ -290,9 +291,10 @@ Editor::mouse_add_new_marker (jack_nframes_t where) if (session) { Location *location = new Location (where, where, "mark", Location::IsMark); session->begin_reversible_command (_("add marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (location, true); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand<Locations>(*(session->locations()), before, after)); session->commit_reversible_command (); } } @@ -329,9 +331,10 @@ gint Editor::really_remove_marker (Location* loc) { session->begin_reversible_command (_("remove marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->remove (loc); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand<Locations>(*(session->locations()), before, after)); session->commit_reversible_command (); return FALSE; } @@ -838,12 +841,13 @@ Editor::marker_menu_rename () } begin_reversible_command ( _("rename marker") ); - session->add_undo( session->locations()->get_memento() ); + XMLNode &before = session->locations()->get_state(); dialog.get_result(txt); loc->set_name (txt); - session->add_redo_no_execute( session->locations()->get_memento() ); + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand<Locations>(*(session->locations()), before, after)); commit_reversible_command (); } @@ -868,16 +872,18 @@ Editor::new_transport_marker_menu_set_loop () if ((tll = transport_loop_location()) == 0) { Location* loc = new Location (temp_location->start(), temp_location->end(), _("Loop"), Location::IsAutoLoop); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (loc, true); session->set_auto_loop_location (loc); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand<Locations>(*(session->locations()), before, after)); } else { - session->add_undo (retype_return<void>(bind (mem_fun (*tll, &Location::set), tll->start(), tll->end()))); - session->add_redo (retype_return<void>(bind (mem_fun (*tll, &Location::set), temp_location->start(), temp_location->end()))); + XMLNode &before = tll->get_state(); tll->set_hidden (false, this); tll->set (temp_location->start(), temp_location->end()); + XMLNode &after = tll->get_state(); + session->add_command (new MementoCommand<Location>(*tll, before, after)); } commit_reversible_command (); @@ -894,15 +900,17 @@ Editor::new_transport_marker_menu_set_punch () if ((tpl = transport_punch_location()) == 0) { tpl = new Location (temp_location->start(), temp_location->end(), _("Punch"), Location::IsAutoPunch); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (tpl, true); session->set_auto_punch_location (tpl); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand<Locations>(*(session->locations()), before, after)); } else { - session->add_undo (retype_return<void>(bind (mem_fun (*tpl, &Location::set), tpl->start(), tpl->end()))); - session->add_redo (retype_return<void>(bind (mem_fun (*tpl, &Location::set), temp_location->start(), temp_location->end()))); + XMLNode &before = tpl->get_state(); tpl->set_hidden(false, this); tpl->set(temp_location->start(), temp_location->end()); + XMLNode &after = tpl->get_state(); + session->add_command (new MementoCommand<Location>(*tpl, before, after)); } commit_reversible_command (); diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 7e9af2dcb0..18c7f0727d 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -28,6 +28,7 @@ #include <pbd/error.h> #include <gtkmm2ext/utils.h> +#include <pbd/memento_command.h> #include "ardour_ui.h" #include "editor.h" @@ -1817,9 +1818,14 @@ Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* even } begin_reversible_command (_("change fade in length")); - session->add_undo (arv->region().get_memento()); + XMLNode &before = arv->audio_region().get_state(); + arv->audio_region().set_fade_in_length (fade_length); - session->add_redo_no_execute (arv->region().get_memento()); + + XMLNode &after = arv->audio_region().get_state(); + session->add_command(new MementoCommand<ARDOUR::AudioRegion>(arv->audio_region(), + before, + after)); commit_reversible_command (); fade_in_drag_motion_callback (item, event); } @@ -1909,9 +1915,12 @@ Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* eve } begin_reversible_command (_("change fade out length")); - session->add_undo (arv->region().get_memento()); + XMLNode &before = arv->region().get_state(); + arv->audio_region().set_fade_out_length (fade_length); - session->add_redo_no_execute (arv->region().get_memento()); + + XMLNode &after = arv->region().get_state(); + session->add_command(new MementoCommand<ARDOUR::Region>(arv->region(), before, after)); commit_reversible_command (); fade_out_drag_motion_callback (item, event); @@ -2153,7 +2162,7 @@ Editor::marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event begin_reversible_command ( _("move marker") ); - session->add_undo( session->locations()->get_memento() ); + XMLNode &before = session->locations()->get_state(); Location * location = find_location_from_marker (marker, is_start); @@ -2165,7 +2174,8 @@ Editor::marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event } } - session->add_redo_no_execute( session->locations()->get_memento() ); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after)); commit_reversible_command (); marker_drag_line->hide(); @@ -2279,9 +2289,10 @@ Editor::meter_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* if (drag_info.copy == true) { begin_reversible_command (_("copy meter mark")); - session->add_undo (map.get_memento()); + XMLNode &before = map.get_state(); map.add_meter (marker->meter(), when); - session->add_redo_no_execute (map.get_memento()); + XMLNode &after = map.get_state(); + session->add_command(new MementoCommand<TempoMap>(map, before, after)); commit_reversible_command (); // delete the dummy marker we used for visual representation of copying. @@ -2289,9 +2300,10 @@ Editor::meter_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* delete marker; } else { begin_reversible_command (_("move meter mark")); - session->add_undo (map.get_memento()); + XMLNode &before = map.get_state(); map.move_meter (marker->meter(), when); - session->add_redo_no_execute (map.get_memento()); + XMLNode &after = map.get_state(); + session->add_command(new MementoCommand<TempoMap>(map, before, after)); commit_reversible_command (); } } @@ -2406,12 +2418,13 @@ Editor::tempo_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* TempoMap& map (session->tempo_map()); map.bbt_time (drag_info.last_pointer_frame, when); - + if (drag_info.copy == true) { begin_reversible_command (_("copy tempo mark")); - session->add_undo (map.get_memento()); + XMLNode &before = map.get_state(); map.add_tempo (marker->tempo(), when); - session->add_redo_no_execute (map.get_memento()); + XMLNode &after = map.get_state(); + session->add_command (new MementoCommand<TempoMap>(map, before, after)); commit_reversible_command (); // delete the dummy marker we used for visual representation of copying. @@ -2419,9 +2432,10 @@ Editor::tempo_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* delete marker; } else { begin_reversible_command (_("move tempo mark")); - session->add_undo (map.get_memento()); + XMLNode &before = map.get_state(); map.move_tempo (marker->tempo(), when); - session->add_redo_no_execute (map.get_memento()); + XMLNode &after = map.get_state(); + session->add_command (new MementoCommand<TempoMap>(map, before, after)); commit_reversible_command (); } } @@ -2785,7 +2799,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) insert_result = affected_playlists.insert (to_playlist); if (insert_result.second) { - session->add_undo (to_playlist->get_memento ()); + session->add_command (new MementoUndoCommand<Playlist>(*to_playlist, to_playlist->get_state())); } latest_regionview = 0; @@ -3221,7 +3235,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) insert_result = motion_frozen_playlists.insert (pl); if (insert_result.second) { pl->freeze(); - session->add_undo(pl->get_memento()); + session->add_command(new MementoUndoCommand<Playlist>(*pl, pl->get_state())); } } } @@ -3349,7 +3363,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event insert_result = motion_frozen_playlists.insert(to_playlist); if (insert_result.second) { to_playlist->freeze(); - session->add_undo(to_playlist->get_memento()); + session->add_command(new MementoUndoCommand<Playlist>(*to_playlist, to_playlist->get_state())); } } @@ -3431,7 +3445,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event out: for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) { (*p)->thaw (); - session->add_redo_no_execute ((*p)->get_memento()); + session->add_command (new MementoRedoCommand<Playlist>(*(*p), (*p)->get_state())); } motion_frozen_playlists.clear (); @@ -3626,9 +3640,10 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event) Playlist* playlist = clicked_trackview->playlist(); - session->add_undo (playlist->get_memento ()); + before = &(playlist->get_state()); clicked_trackview->playlist()->add_region (*region, selection->time[clicked_selection].start); - session->add_redo_no_execute (playlist->get_memento ()); + XMLNode &after = playlist->get_state(); + session->add_command(new MementoCommand<Playlist>(*playlist, *before, after)); commit_reversible_command (); @@ -3995,7 +4010,7 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) Playlist * pl = (*i)->region().playlist(); insert_result = motion_frozen_playlists.insert (pl); if (insert_result.second) { - session->add_undo (pl->get_memento()); + session->add_command(new MementoUndoCommand<Playlist>(*pl, pl->get_state())); } } } @@ -4185,8 +4200,8 @@ Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) { //(*p)->thaw (); - session->add_redo_no_execute ((*p)->get_memento()); - } + session->add_command (new MementoRedoCommand<Playlist>(*(*p), (*p)->get_state())); + } motion_frozen_playlists.clear (); @@ -4219,18 +4234,22 @@ Editor::point_trim (GdkEvent* event) i != selection->regions.by_layer().end(); ++i) { if (!(*i)->region().locked()) { - session->add_undo ((*i)->region().playlist()->get_memento()); + Playlist *pl = (*i)->region().playlist(); + XMLNode &before = pl->get_state(); (*i)->region().trim_front (new_bound, this); - session->add_redo_no_execute ((*i)->region().playlist()->get_memento()); + XMLNode &after = pl->get_state(); + session->add_command(new MementoCommand<Playlist>(*pl, before, after)); } } } else { if (!rv->region().locked()) { - session->add_undo (rv->region().playlist()->get_memento()); + Playlist *pl = rv->region().playlist(); + XMLNode &before = pl->get_state(); rv->region().trim_front (new_bound, this); - session->add_redo_no_execute (rv->region().playlist()->get_memento()); + XMLNode &after = pl->get_state(); + session->add_command(new MementoCommand<Playlist>(*pl, before, after)); } } @@ -4246,18 +4265,22 @@ Editor::point_trim (GdkEvent* event) for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { if (!(*i)->region().locked()) { - session->add_undo ((*i)->region().playlist()->get_memento()); + Playlist *pl = (*i)->region().playlist(); + XMLNode &before = pl->get_state(); (*i)->region().trim_end (new_bound, this); - session->add_redo_no_execute ((*i)->region().playlist()->get_memento()); + XMLNode &after = pl->get_state(); + session->add_command(new MementoCommand<Playlist>(*pl, before, after)); } } } else { if (!rv->region().locked()) { - session->add_undo (rv->region().playlist()->get_memento()); + Playlist *pl = rv->region().playlist(); + XMLNode &before = pl->get_state(); rv->region().trim_end (new_bound, this); - session->add_redo_no_execute (rv->region().playlist()->get_memento()); + XMLNode &after = pl->get_state(); + session->add_command (new MementoCommand<Playlist>(*pl, before, after)); } } @@ -4279,7 +4302,8 @@ Editor::thaw_region_after_trim (RegionView& rv) } region.thaw (_("trimmed region")); - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command (new MementoRedoCommand<Playlist>(*(region.playlist()), after)); AudioRegionView* arv = dynamic_cast<AudioRegionView*>(&rv); if (arv) @@ -4418,16 +4442,19 @@ Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event) switch (range_marker_op) { case CreateRangeMarker: + { begin_reversible_command (_("new range marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); newloc = new Location(temp_location->start(), temp_location->end(), "unnamed", Location::IsRangeMarker); session->locations()->add (newloc, true); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after)); commit_reversible_command (); range_bar_drag_rect->hide(); range_marker_drag_rect->hide(); break; + } case CreateTransportMarker: // popup menu to pick loop or punch @@ -4801,9 +4828,10 @@ Editor::mouse_brush_insert_region (RegionView* rv, jack_nframes_t pos) Playlist* playlist = atv->playlist(); double speed = atv->get_diskstream()->speed(); - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->add_region (*(new AudioRegion (arv->audio_region())), (jack_nframes_t) (pos * speed)); - session->add_redo_no_execute (playlist->get_memento()); + XMLNode &after = playlist->get_state(); + session->add_command(new MementoCommand<Playlist>(*playlist, before, after)); // playlist is frozen, so we have to update manually diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index bdaeb5aa97..1e5f336e52 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -28,6 +28,7 @@ #include <pbd/error.h> #include <pbd/basename.h> #include <pbd/pthread_utils.h> +#include <pbd/memento_command.h> #include <gtkmm2ext/utils.h> #include <gtkmm2ext/choice.h> @@ -209,9 +210,10 @@ Editor::split_regions_at (jack_nframes_t where, RegionSelection& regions) _new_regionviews_show_envelope = arv->envelope_visible(); if (pl) { - session->add_undo (pl->get_memento()); + XMLNode &before = pl->get_state(); pl->split_region ((*a)->region(), where); - session->add_redo_no_execute (pl->get_memento()); + XMLNode &after = pl->get_state(); + session->add_command(new MementoCommand<Playlist>(*pl, before, after)); } a = tmp; @@ -231,9 +233,10 @@ Editor::remove_clicked_region () Playlist* playlist = clicked_audio_trackview->playlist(); begin_reversible_command (_("remove region")); - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->remove_region (&clicked_regionview->region()); - session->add_redo_no_execute (playlist->get_memento()); + XMLNode &after = playlist->get_state(); + session->add_command(new MementoCommand<Playlist>(*playlist, before, after)); commit_reversible_command (); } @@ -406,9 +409,10 @@ Editor::nudge_forward (bool next) distance = next_distance; } - session->add_undo (r.playlist()->get_memento()); + XMLNode &before = r.playlist()->get_state(); r.set_position (r.position() + distance, this); - session->add_redo_no_execute (r.playlist()->get_memento()); + XMLNode &after = r.playlist()->get_state(); + session->add_command (new MementoCommand<Playlist>(*(r.playlist()), before, after)); } commit_reversible_command (); @@ -440,14 +444,15 @@ Editor::nudge_backward (bool next) distance = next_distance; } - session->add_undo (r.playlist()->get_memento()); + XMLNode &before = r.playlist()->get_state(); if (r.position() > distance) { r.set_position (r.position() - distance, this); } else { r.set_position (0, this); } - session->add_redo_no_execute (r.playlist()->get_memento()); + XMLNode &after = r.playlist()->get_state(); + session->add_command(new MementoCommand<Playlist>(*(r.playlist()), before, after)); } commit_reversible_command (); @@ -480,9 +485,10 @@ Editor::nudge_forward_capture_offset () for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { Region& r ((*i)->region()); - session->add_undo (r.playlist()->get_memento()); + XMLNode &before = r.playlist()->get_state(); r.set_position (r.position() + distance, this); - session->add_redo_no_execute (r.playlist()->get_memento()); + XMLNode &after = r.playlist()->get_state(); + session->add_command(new MementoCommand<Playlist>(*(r.playlist()), before, after)); } commit_reversible_command (); @@ -506,14 +512,15 @@ Editor::nudge_backward_capture_offset () for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { Region& r ((*i)->region()); - session->add_undo (r.playlist()->get_memento()); + XMLNode &before = r.playlist()->get_state(); if (r.position() > distance) { r.set_position (r.position() - distance, this); } else { r.set_position (0, this); } - session->add_redo_no_execute (r.playlist()->get_memento()); + XMLNode &after = r.playlist()->get_state(); + session->add_command(new MementoCommand<Playlist>(*(r.playlist()), before, after)); } commit_reversible_command (); @@ -1290,9 +1297,10 @@ Editor::add_location_from_selection () Location *location = new Location (start, end, "selection"); session->begin_reversible_command (_("add marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (location, true); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after)); session->commit_reversible_command (); } @@ -1303,9 +1311,10 @@ Editor::add_location_from_playhead_cursor () Location *location = new Location (where, where, "mark", Location::IsMark); session->begin_reversible_command (_("add marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (location, true); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after)); session->commit_reversible_command (); } @@ -1321,9 +1330,10 @@ Editor::add_location_from_audio_region () Location *location = new Location (region.position(), region.last_frame(), region.name()); session->begin_reversible_command (_("add marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (location, true); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after)); session->commit_reversible_command (); } @@ -1739,9 +1749,10 @@ Editor::clear_markers () { if (session) { session->begin_reversible_command (_("clear markers")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->clear_markers (); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after)); session->commit_reversible_command (); } } @@ -1751,7 +1762,7 @@ Editor::clear_ranges () { if (session) { session->begin_reversible_command (_("clear ranges")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); Location * looploc = session->locations()->auto_loop_location(); Location * punchloc = session->locations()->auto_punch_location(); @@ -1761,7 +1772,8 @@ Editor::clear_ranges () if (looploc) session->locations()->add (looploc); if (punchloc) session->locations()->add (punchloc); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after)); session->commit_reversible_command (); } } @@ -1770,9 +1782,10 @@ void Editor::clear_locations () { session->begin_reversible_command (_("clear locations")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->clear (); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after)); session->commit_reversible_command (); session->locations()->clear (); } @@ -1820,9 +1833,9 @@ Editor::insert_region_list_drag (AudioRegion& region, int x, int y) snap_to (where); begin_reversible_command (_("insert dragged region")); - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->add_region (*(new AudioRegion (region)), where, 1.0); - session->add_redo_no_execute (playlist->get_memento()); + session->add_command(new MementoCommand<Playlist>(*playlist, before, playlist->get_state())); commit_reversible_command (); } @@ -1856,9 +1869,9 @@ Editor::insert_region_list_selection (float times) Region* region = (*i)[region_list_columns.region]; begin_reversible_command (_("insert region")); - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->add_region (*(createRegion (*region)), edit_cursor->current_frame, times); - session->add_redo_no_execute (playlist->get_memento()); + session->add_command(new MementoCommand<Playlist>(*playlist, before, playlist->get_state())); commit_reversible_command (); } @@ -2282,7 +2295,9 @@ Editor::separate_region_from_selection () begin_reversible_command (_("separate")); doing_undo = true; } - if (doing_undo) session->add_undo ((playlist)->get_memento()); + XMLNode *before; + if (doing_undo) + before = &(playlist->get_state()); /* XXX need to consider musical time selections here at some point */ @@ -2292,7 +2307,8 @@ Editor::separate_region_from_selection () playlist->partition ((jack_nframes_t)((*t).start * speed), (jack_nframes_t)((*t).end * speed), true); } - if (doing_undo) session->add_redo_no_execute (playlist->get_memento()); + if (doing_undo) + session->add_command(new MementoCommand<Playlist>(*playlist, *before, playlist->get_state())); } } } @@ -2327,11 +2343,14 @@ Editor::separate_regions_using_location (Location& loc) if (atv->is_audio_track()) { if ((playlist = atv->playlist()) != 0) { + XMLNode *before; if (!doing_undo) { begin_reversible_command (_("separate")); doing_undo = true; } - if (doing_undo) session->add_undo ((playlist)->get_memento()); + if (doing_undo) + before = &(playlist->get_state()); + /* XXX need to consider musical time selections here at some point */ @@ -2339,7 +2358,8 @@ Editor::separate_regions_using_location (Location& loc) playlist->partition ((jack_nframes_t)(loc.start() * speed), (jack_nframes_t)(loc.end() * speed), true); - if (doing_undo) session->add_redo_no_execute (playlist->get_memento()); + if (doing_undo) + session->add_command(new MementoCommand<Playlist>(*playlist, *before, playlist->get_state())); } } } @@ -2410,9 +2430,10 @@ Editor::crop_region_to_selection () end = min (selection->time.end_frame(), start + region->length() - 1); cnt = end - start + 1; - session->add_undo ((*i)->get_memento()); + XMLNode &before = (*i)->get_state(); region->trim_to (start, cnt, this); - session->add_redo_no_execute ((*i)->get_memento()); + XMLNode &after = (*i)->get_state(); + session->add_command (new MementoCommand<Playlist>(*(*i), before, after)); } commit_reversible_command (); @@ -2453,9 +2474,9 @@ Editor::region_fill_track () return; } - session->add_undo (pl->get_memento()); + XMLNode &before = pl->get_state(); pl->add_region (*(new AudioRegion (*ar)), ar->last_frame(), times); - session->add_redo_no_execute (pl->get_memento()); + session->add_command (new MementoCommand<Playlist>(*pl, before, pl->get_state())); } commit_reversible_command (); @@ -2503,9 +2524,9 @@ Editor::region_fill_selection () continue; } - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->add_region (*(createRegion (*region)), start, times); - session->add_redo_no_execute (playlist->get_memento()); + session->add_command (new MementoCommand<Playlist>(*playlist, before, playlist->get_state())); } commit_reversible_command (); @@ -2520,9 +2541,10 @@ Editor::set_a_regions_sync_position (Region& region, jack_nframes_t position) return; } begin_reversible_command (_("set region sync position")); - session->add_undo (region.playlist()->get_memento()); + XMLNode &before = region.playlist()->get_state(); region.set_sync_position (position); - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command(new MementoCommand<Playlist>(*(region.playlist()), before, after)); commit_reversible_command (); } @@ -2540,9 +2562,10 @@ Editor::set_region_sync_from_edit_cursor () Region& region (clicked_regionview->region()); begin_reversible_command (_("set sync from edit cursor")); - session->add_undo (region.playlist()->get_memento()); + XMLNode &before = region.playlist()->get_state(); region.set_sync_position (edit_cursor->current_frame); - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command(new MementoCommand<Playlist>(*(region.playlist()), before, after)); commit_reversible_command (); } @@ -2552,9 +2575,10 @@ Editor::remove_region_sync () if (clicked_regionview) { Region& region (clicked_regionview->region()); begin_reversible_command (_("remove sync")); - session->add_undo (region.playlist()->get_memento()); + XMLNode &before = region.playlist()->get_state(); region.clear_sync_position (); - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command(new MementoCommand<Playlist>(*(region.playlist()), before, after)); commit_reversible_command (); } } @@ -2567,9 +2591,10 @@ Editor::naturalize () } begin_reversible_command (_("naturalize")); for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { - session->add_undo ((*i)->region().get_memento()); + XMLNode &before = (*i)->region().get_state(); (*i)->region().move_to_natural_position (this); - session->add_redo_no_execute ((*i)->region().get_memento()); + XMLNode &after = (*i)->region().get_state(); + session->add_command (new MementoCommand<Region>((*i)->region(), before, after)); } commit_reversible_command (); } @@ -2635,7 +2660,7 @@ Editor::align_selection_relative (RegionPoint point, jack_nframes_t position) Region& region ((*i)->region()); - session->add_undo (region.playlist()->get_memento()); + XMLNode &before = region.playlist()->get_state(); if (dir > 0) { region.set_position (region.position() + distance, this); @@ -2643,7 +2668,8 @@ Editor::align_selection_relative (RegionPoint point, jack_nframes_t position) region.set_position (region.position() - distance, this); } - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command(new MementoCommand<Playlist>(*(region.playlist()), before, after)); } @@ -2677,7 +2703,7 @@ Editor::align_region (Region& region, RegionPoint point, jack_nframes_t position void Editor::align_region_internal (Region& region, RegionPoint point, jack_nframes_t position) { - session->add_undo (region.playlist()->get_memento()); + XMLNode &before = region.playlist()->get_state(); switch (point) { case SyncPoint: @@ -2695,7 +2721,8 @@ Editor::align_region_internal (Region& region, RegionPoint point, jack_nframes_t break; } - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command(new MementoCommand<Playlist>(*(region.playlist()), before, after)); } void @@ -2717,9 +2744,10 @@ Editor::trim_region_to_edit_cursor () } begin_reversible_command (_("trim to edit")); - session->add_undo (region.playlist()->get_memento()); + XMLNode &before = region.playlist()->get_state(); region.trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this); - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command(new MementoCommand<Playlist>(*(region.playlist()), before, after)); commit_reversible_command (); } @@ -2742,9 +2770,10 @@ Editor::trim_region_from_edit_cursor () } begin_reversible_command (_("trim to edit")); - session->add_undo (region.playlist()->get_memento()); + XMLNode &before = region.playlist()->get_state(); region.trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this); - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command(new MementoCommand<Playlist>(*(region.playlist()), before, after)); commit_reversible_command (); } @@ -2856,9 +2885,10 @@ Editor::bounce_range_selection () itt.cancel = false; itt.progress = false; - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); atv->audio_track()->bounce_range (start, cnt, itt); - session->add_redo_no_execute (playlist->get_memento()); + XMLNode &after = playlist->get_state(); + session->add_command (new MementoCommand<Playlist> (*playlist, before, after)); } commit_reversible_command (); @@ -2976,7 +3006,7 @@ Editor::cut_copy_regions (CutCopyOp op) insert_result = freezelist.insert (pl); if (insert_result.second) { pl->freeze (); - session->add_undo (pl->get_memento()); + session->add_command (new MementoUndoCommand<Playlist>(*pl, pl->get_state())); } } } @@ -3040,7 +3070,7 @@ Editor::cut_copy_regions (CutCopyOp op) for (set<Playlist*>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) { (*pl)->thaw (); - session->add_redo_no_execute ((*pl)->get_memento()); + session->add_command (new MementoRedoCommand<Playlist>(*(*pl), (*pl)->get_state())); } } @@ -3153,9 +3183,9 @@ Editor::paste_named_selection (float times) tmp = chunk; ++tmp; - session->add_undo (apl->get_memento()); + XMLNode &before = apl->get_state(); apl->paste (**chunk, edit_cursor->current_frame, times); - session->add_redo_no_execute (apl->get_memento()); + session->add_command(new MementoCommand<AudioPlaylist>(*apl, before, apl->get_state())); if (tmp != ns->playlists.end()) { chunk = tmp; @@ -3184,9 +3214,9 @@ Editor::duplicate_some_regions (RegionSelection& regions, float times) sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); playlist = (*i)->region().playlist(); - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->duplicate (r, r.last_frame(), times); - session->add_redo_no_execute (playlist->get_memento()); + session->add_command(new MementoCommand<Playlist>(*playlist, before, playlist->get_state())); c.disconnect (); @@ -3224,9 +3254,10 @@ Editor::duplicate_selection (float times) if ((playlist = (*i)->playlist()) == 0) { continue; } - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->duplicate (**ri, selection->time[clicked_selection].end, times); - session->add_redo_no_execute (playlist->get_memento()); + XMLNode &after = playlist->get_state(); + session->add_command (new MementoCommand<Playlist>(*playlist, before, after)); ++ri; if (ri == new_regions.end()) { @@ -3274,9 +3305,10 @@ void Editor::clear_playlist (Playlist& playlist) { begin_reversible_command (_("clear playlist")); - session->add_undo (playlist.get_memento()); + XMLNode &before = playlist.get_state(); playlist.clear (); - session->add_redo_no_execute (playlist.get_memento()); + XMLNode &after = playlist.get_state(); + session->add_command (new MementoCommand<Playlist>(playlist, before, after)); commit_reversible_command (); } @@ -3310,9 +3342,10 @@ Editor::nudge_track (bool use_edit_cursor, bool forwards) continue; } - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->nudge_after (start, distance, forwards); - session->add_redo_no_execute (playlist->get_memento()); + XMLNode &after = playlist->get_state(); + session->add_command (new MementoCommand<Playlist>(*playlist, before, after)); } commit_reversible_command (); @@ -3366,9 +3399,9 @@ Editor::normalize_region () AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r); if (!arv) continue; - session->add_undo (arv->region().get_memento()); + XMLNode &before = arv->region().get_state(); arv->audio_region().normalize_to (0.0f); - session->add_redo_no_execute (arv->region().get_memento()); + session->add_command (new MementoCommand<Region>(arv->region(), before, arv->region().get_state())); } commit_reversible_command (); @@ -3393,9 +3426,9 @@ Editor::denormalize_region () AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r); if (!arv) continue; - session->add_undo (arv->region().get_memento()); + XMLNode &before = arv->region().get_state(); arv->audio_region().set_scale_amplitude (1.0f); - session->add_redo_no_execute (arv->region().get_memento()); + session->add_command (new MementoCommand<Region>(arv->region(), before, arv->region().get_state())); } commit_reversible_command (); @@ -3439,9 +3472,10 @@ Editor::apply_filter (AudioFilter& filter, string command) if (arv->audio_region().apply (filter) == 0) { - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->replace_region (arv->region(), *(filter.results.front()), arv->region().position()); - session->add_redo_no_execute (playlist->get_memento()); + XMLNode &after = playlist->get_state(); + session->add_command(new MementoCommand<Playlist>(*playlist, before, after)); } else { goto out; } diff --git a/gtk2_ardour/editor_tempodisplay.cc b/gtk2_ardour/editor_tempodisplay.cc index 5f998ada9f..9f7fe7cf09 100644 --- a/gtk2_ardour/editor_tempodisplay.cc +++ b/gtk2_ardour/editor_tempodisplay.cc @@ -27,6 +27,7 @@ #include <libgnomecanvasmm.h> #include <pbd/error.h> +#include <pbd/memento_command.h> #include <gtkmm2ext/utils.h> #include <gtkmm2ext/gtk_ui.h> @@ -273,9 +274,10 @@ Editor::mouse_add_new_tempo_event (jack_nframes_t frame) tempo_dialog.get_bbt_time (requested); begin_reversible_command (_("add tempo mark")); - session->add_undo (map.get_memento()); + XMLNode &before = map.get_state(); map.add_tempo (Tempo (bpm), requested); - session->add_redo_no_execute (map.get_memento()); + XMLNode &after = map.get_state(); + session->add_command(new MementoCommand<TempoMap>(map, before, after)); commit_reversible_command (); map.dump (cerr); @@ -313,9 +315,9 @@ Editor::mouse_add_new_meter_event (jack_nframes_t frame) meter_dialog.get_bbt_time (requested); begin_reversible_command (_("add meter mark")); - session->add_undo (map.get_memento()); + XMLNode &before = map.get_state(); map.add_meter (Meter (bpb, note_type), requested); - session->add_redo_no_execute (map.get_memento()); + session->add_command(new MementoCommand<TempoMap>(map, before, map.get_state())); commit_reversible_command (); map.dump (cerr); @@ -364,9 +366,10 @@ Editor::edit_meter_section (MeterSection* section) double note_type = meter_dialog.get_note_type (); begin_reversible_command (_("replace tempo mark")); - session->add_undo (session->tempo_map().get_memento()); + XMLNode &before = session->tempo_map().get_state(); session->tempo_map().replace_meter (*section, Meter (bpb, note_type)); - session->add_redo_no_execute (session->tempo_map().get_memento()); + XMLNode &after = session->tempo_map().get_state(); + session->add_command(new MementoCommand<TempoMap>(session->tempo_map(), before, after)); commit_reversible_command (); } @@ -392,10 +395,11 @@ Editor::edit_tempo_section (TempoSection* section) bpm = max (0.01, bpm); begin_reversible_command (_("replace tempo mark")); - session->add_undo (session->tempo_map().get_memento()); + XMLNode &before = session->tempo_map().get_state(); session->tempo_map().replace_tempo (*section, Tempo (bpm)); session->tempo_map().move_tempo (*section, when); - session->add_redo_no_execute (session->tempo_map().get_memento()); + XMLNode &after = session->tempo_map().get_state(); + session->add_command (new MementoCommand<TempoMap>(session->tempo_map(), before, after)); commit_reversible_command (); } @@ -441,9 +445,10 @@ gint Editor::real_remove_tempo_marker (TempoSection *section) { begin_reversible_command (_("remove tempo mark")); - session->add_undo (session->tempo_map().get_memento()); + XMLNode &before = session->tempo_map().get_state(); session->tempo_map().remove_tempo (*section); - session->add_redo_no_execute (session->tempo_map().get_memento()); + XMLNode &after = session->tempo_map().get_state(); + session->add_command(new MementoCommand<TempoMap>(session->tempo_map(), before, after)); commit_reversible_command (); return FALSE; @@ -474,9 +479,10 @@ gint Editor::real_remove_meter_marker (MeterSection *section) { begin_reversible_command (_("remove tempo mark")); - session->add_undo (session->tempo_map().get_memento()); + XMLNode &before = session->tempo_map().get_state(); session->tempo_map().remove_meter (*section); - session->add_redo_no_execute (session->tempo_map().get_memento()); + XMLNode &after = session->tempo_map().get_state(); + session->add_command(new MementoCommand<TempoMap>(session->tempo_map(), before, after)); commit_reversible_command (); return FALSE; } diff --git a/gtk2_ardour/editor_timefx.cc b/gtk2_ardour/editor_timefx.cc index 79772090f6..3fe0023d07 100644 --- a/gtk2_ardour/editor_timefx.cc +++ b/gtk2_ardour/editor_timefx.cc @@ -25,6 +25,7 @@ #include <pbd/error.h> #include <pbd/pthread_utils.h> +#include <pbd/memento_command.h> #include "editor.h" #include "audio_time_axis.h" @@ -206,9 +207,10 @@ Editor::do_timestretch (TimeStretchDialog& dialog) return; } - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->replace_region (region, *new_region, region.position()); - session->add_redo_no_execute (playlist->get_memento()); + XMLNode &after = playlist->get_state(); + session->add_command (new MementoCommand<Playlist>(*playlist, before, after)); i = tmp; } diff --git a/gtk2_ardour/gain_automation_time_axis.cc b/gtk2_ardour/gain_automation_time_axis.cc index 5352015f11..c86c1390f3 100644 --- a/gtk2_ardour/gain_automation_time_axis.cc +++ b/gtk2_ardour/gain_automation_time_axis.cc @@ -20,6 +20,7 @@ #include <ardour/curve.h> #include <ardour/route.h> +#include <pbd/memento_command.h> #include "gain_automation_time_axis.h" #include "automation_line.h" @@ -63,9 +64,10 @@ GainAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkE _session.begin_reversible_command (_("add gain automation event")); - _session.add_undo (curve.get_memento()); + XMLNode &before = curve.get_state(); curve.add (when, y); - _session.add_redo_no_execute (curve.get_memento()); + XMLNode &after = curve.get_state(); + _session.add_command(new MementoCommand<ARDOUR::Curve>(curve, before, after)); _session.commit_reversible_command (); _session.set_dirty (); } diff --git a/gtk2_ardour/location_ui.cc b/gtk2_ardour/location_ui.cc index f0fe230b57..deb4c1da36 100644 --- a/gtk2_ardour/location_ui.cc +++ b/gtk2_ardour/location_ui.cc @@ -27,6 +27,7 @@ #include <ardour/utils.h> #include <ardour/configuration.h> #include <ardour/session.h> +#include <pbd/memento_command.h> #include "ardour_ui.h" #include "prompter.h" @@ -654,9 +655,10 @@ gint LocationUI::do_location_remove (ARDOUR::Location *loc) } session->begin_reversible_command (_("remove marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->remove (loc); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after)); session->commit_reversible_command (); return FALSE; @@ -772,9 +774,10 @@ LocationUI::add_new_location() jack_nframes_t where = session->audible_frame(); Location *location = new Location (where, where, "mark", Location::IsMark); session->begin_reversible_command (_("add marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (location, true); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand<Locations>(*(session->locations()), before, after)); session->commit_reversible_command (); } @@ -788,9 +791,10 @@ LocationUI::add_new_range() Location *location = new Location (where, where, "unnamed", Location::IsRangeMarker); session->begin_reversible_command (_("add range marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (location, true); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand<Locations>(*(session->locations()), before, after)); session->commit_reversible_command (); } } diff --git a/gtk2_ardour/pan_automation_time_axis.cc b/gtk2_ardour/pan_automation_time_axis.cc index 34426c127f..3169f65059 100644 --- a/gtk2_ardour/pan_automation_time_axis.cc +++ b/gtk2_ardour/pan_automation_time_axis.cc @@ -23,6 +23,7 @@ #include <ardour/panner.h> #include <gtkmm2ext/popup.h> +#include <pbd/memento_command.h> #include "pan_automation_time_axis.h" #include "automation_line.h" @@ -88,9 +89,10 @@ PanAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEv AutomationList& alist (lines[line_index]->the_list()); _session.begin_reversible_command (_("add pan automation event")); - _session.add_undo (alist.get_memento()); + XMLNode &before = alist.get_state(); alist.add (when, y); - _session.add_redo_no_execute (alist.get_memento()); + XMLNode &after = alist.get_state(); + _session.add_command(new MementoCommand<AutomationList>(alist, before, after)); _session.commit_reversible_command (); _session.set_dirty (); } diff --git a/gtk2_ardour/redirect_automation_time_axis.cc b/gtk2_ardour/redirect_automation_time_axis.cc index a53c1a20e4..e527fd1d5e 100644 --- a/gtk2_ardour/redirect_automation_time_axis.cc +++ b/gtk2_ardour/redirect_automation_time_axis.cc @@ -21,6 +21,7 @@ #include <ardour/redirect.h> #include <ardour/session.h> #include <cstdlib> +#include <pbd/memento_command.h> #include "redirect_automation_time_axis.h" #include "automation_line.h" @@ -98,9 +99,10 @@ RedirectAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, lines.front()->view_to_model_y (y); _session.begin_reversible_command (description); - _session.add_undo (alist.get_memento()); + XMLNode &before = alist.get_state(); alist.add (when, y); - _session.add_redo_no_execute (alist.get_memento()); + XMLNode &after = alist.get_state(); + _session.add_command(new MementoCommand<AutomationList>(alist, before, after)); _session.commit_reversible_command (); _session.set_dirty (); } diff --git a/gtk2_ardour/region_editor.h b/gtk2_ardour/region_editor.h index 176ced0792..70590b0db5 100644 --- a/gtk2_ardour/region_editor.h +++ b/gtk2_ardour/region_editor.h @@ -15,7 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: region_editor.h 231 2006-01-03 14:16:27Z karstenweise $ + $Id: /local/undo/gtk2_ardour/region_editor.h 5 2006-05-31T02:48:48.738745Z paul $ */ #ifndef __gtk_ardour_region_edit_h__ diff --git a/gtk2_ardour/region_gain_line.cc b/gtk2_ardour/region_gain_line.cc index a542be054e..0a4a3d29ea 100644 --- a/gtk2_ardour/region_gain_line.cc +++ b/gtk2_ardour/region_gain_line.cc @@ -1,5 +1,6 @@ #include <ardour/curve.h> #include <ardour/audioregion.h> +#include <pbd/memento_command.h> #include "region_gain_line.h" #include "audio_region_view.h" @@ -47,7 +48,8 @@ AudioRegionGainLine::start_drag (ControlPoint* cp, float fraction) { AutomationLine::start_drag(cp,fraction); if (!rv.audio_region().envelope_active()) { - trackview.session().add_undo( bind( mem_fun(rv.audio_region(), &AudioRegion::set_envelope_active), false) ); + trackview.session().add_command(new MementoUndoCommand<AudioRegion>(rv.audio_region(), rv.audio_region().get_state())); + rv.audio_region().set_envelope_active(false); } } @@ -60,17 +62,18 @@ AudioRegionGainLine::remove_point (ControlPoint& cp) model_representation (cp, mr); trackview.editor.current_session()->begin_reversible_command (_("remove control point")); - trackview.editor.current_session()->add_undo (get_memento()); + XMLNode &before = get_state(); if (!rv.audio_region().envelope_active()) { - trackview.session().add_undo( bind( mem_fun(rv.audio_region(), &AudioRegion::set_envelope_active), false) ); - trackview.session().add_redo( bind( mem_fun(rv.audio_region(), &AudioRegion::set_envelope_active), true) ); + XMLNode &before = rv.audio_region().get_state(); rv.audio_region().set_envelope_active(true); + XMLNode &after = rv.audio_region().get_state(); + trackview.session().add_command(new MementoCommand<AudioRegion>(rv.audio_region(), before, after)); } alist.erase (mr.start, mr.end); - trackview.editor.current_session()->add_redo_no_execute (get_memento()); + trackview.editor.current_session()->add_command (new MementoCommand<AudioRegionGainLine>(*this, before, get_state())); trackview.editor.current_session()->commit_reversible_command (); trackview.editor.current_session()->set_dirty (); } @@ -79,8 +82,8 @@ void AudioRegionGainLine::end_drag (ControlPoint* cp) { if (!rv.audio_region().envelope_active()) { - trackview.session().add_redo( bind( mem_fun(rv.audio_region(), &AudioRegion::set_envelope_active), true) ); rv.audio_region().set_envelope_active(true); + trackview.session().add_command(new MementoRedoCommand<AudioRegion>(rv.audio_region(), rv.audio_region().get_state())); } AutomationLine::end_drag(cp); } diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 8dca7be480..82d5b53cba 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -29,6 +29,7 @@ #include <pbd/error.h> #include <pbd/stl_delete.h> #include <pbd/whitespace.h> +#include <pbd/memento_command.h> #include <gtkmm/menu.h> #include <gtkmm/menuitem.h> @@ -1050,12 +1051,12 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) } } + XMLNode &before = playlist->get_state(); switch (op) { case Cut: - _session.add_undo (playlist->get_memento()); if ((what_we_got = playlist->cut (time)) != 0) { editor.get_cut_buffer().add (what_we_got); - _session.add_redo_no_execute (playlist->get_memento()); + _session.add_command( new MementoCommand<Playlist>(*playlist, before, playlist->get_state())); ret = true; } break; @@ -1066,9 +1067,8 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) break; case Clear: - _session.add_undo (playlist->get_memento()); if ((what_we_got = playlist->cut (time)) != 0) { - _session.add_redo_no_execute (playlist->get_memento()); + _session.add_command( new MementoCommand<Playlist>(*playlist, before, playlist->get_state())); what_we_got->unref (); ret = true; } @@ -1097,9 +1097,9 @@ RouteTimeAxisView::paste (jack_nframes_t pos, float times, Selection& selection, if (get_diskstream()->speed() != 1.0f) pos = session_frame_to_track_frame(pos, get_diskstream()->speed() ); - _session.add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->paste (**p, pos, times); - _session.add_redo_no_execute (playlist->get_memento()); + _session.add_command( new MementoCommand<Playlist>(*playlist, before, playlist->get_state())); return true; } diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc index eaf28470da..863e73d33e 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -25,6 +25,7 @@ #include <gtkmm2ext/bindable_button.h> #include <ardour/route_group.h> +#include <pbd/memento_command.h> #include "route_ui.h" #include "keyboard.h" @@ -128,9 +129,10 @@ RouteUI::mute_press(GdkEventButton* ev) /* ctrl-shift-click applies change to all routes */ _session.begin_reversible_command (_("mute change")); - _session.add_undo (_session.global_mute_memento(this)); + Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this); _session.set_all_mute (!_route->muted()); - _session.add_redo_no_execute (_session.global_mute_memento(this)); + cmd->mark(); + _session.add_command(cmd); _session.commit_reversible_command (); } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) { @@ -203,9 +205,10 @@ RouteUI::solo_press(GdkEventButton* ev) /* ctrl-shift-click applies change to all routes */ _session.begin_reversible_command (_("solo change")); - _session.add_undo (_session.global_solo_memento(this)); + Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this); _session.set_all_solo (!_route->soloed()); - _session.add_redo_no_execute (_session.global_solo_memento(this)); + cmd->mark(); + _session.add_command (cmd); _session.commit_reversible_command (); } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) { @@ -213,10 +216,11 @@ RouteUI::solo_press(GdkEventButton* ev) // ctrl-alt-click: exclusively solo this track, not a toggle */ _session.begin_reversible_command (_("solo change")); - _session.add_undo (_session.global_solo_memento(this)); + Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this); _session.set_all_solo (false); _route->set_solo (true, this); - _session.add_redo_no_execute (_session.global_solo_memento(this)); + cmd->mark(); + _session.add_command(cmd); _session.commit_reversible_command (); } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Shift)) { @@ -276,7 +280,7 @@ RouteUI::rec_enable_press(GdkEventButton* ev) else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) { _session.begin_reversible_command (_("rec-enable change")); - _session.add_undo (_session.global_record_enable_memento(this)); + Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this); if (rec_enable_button->get_active()) { _session.record_disenable_all (); @@ -284,7 +288,8 @@ RouteUI::rec_enable_press(GdkEventButton* ev) _session.record_enable_all (); } - _session.add_redo_no_execute (_session.global_record_enable_memento(this)); + cmd->mark(); + _session.add_command(cmd); _session.commit_reversible_command (); } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) { @@ -553,9 +558,10 @@ RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn) if((mix_group = route->mix_group()) != 0){ _session.begin_reversible_command (_("mix group solo change")); - _session.add_undo (_session.global_solo_memento (this)); + Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this); mix_group->apply(&Route::set_solo, yn, this); - _session.add_redo_no_execute (_session.global_solo_memento(this)); + cmd->mark(); + _session.add_command (cmd); _session.commit_reversible_command (); } else { reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this); @@ -566,8 +572,10 @@ void RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg) { _session.begin_reversible_command (name); - _session.add_undo (bind (mem_fun (*_route, func), !yn, (void *) arg)); - _session.add_redo (bind (mem_fun (*_route, func), yn, (void *) arg)); + XMLNode &before = _route->get_state(); + bind(mem_fun(*_route, func), yn, arg)(); + XMLNode &after = _route->get_state(); + _session.add_command (new MementoCommand<Route>(*_route, before, after)); _session.commit_reversible_command (); } @@ -575,8 +583,10 @@ void RouteUI::reversibly_apply_audio_track_boolean (string name, void (AudioTrack::*func)(bool, void *), bool yn, void *arg) { _session.begin_reversible_command (name); - _session.add_undo (bind (mem_fun (*audio_track(), func), !yn, (void *) arg)); - _session.add_redo (bind (mem_fun (*audio_track(), func), yn, (void *) arg)); + XMLNode &before = audio_track()->get_state(); + bind (mem_fun (*audio_track(), func), yn, arg)(); + XMLNode &after = audio_track()->get_state(); + _session.add_command (new MementoCommand<AudioTrack>(*audio_track(), before, after)); _session.commit_reversible_command (); } @@ -587,9 +597,10 @@ RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn) if((mix_group = route->mix_group()) != 0){ _session.begin_reversible_command (_("mix group mute change")); - _session.add_undo (_session.global_mute_memento (this)); + Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this); mix_group->apply(&Route::set_mute, yn, this); - _session.add_redo_no_execute (_session.global_mute_memento(this)); + cmd->mark(); + _session.add_command(cmd); _session.commit_reversible_command (); } else { reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this); @@ -603,9 +614,10 @@ RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn) if((mix_group = route->mix_group()) != 0){ _session.begin_reversible_command (_("mix group rec-enable change")); - _session.add_undo (_session.global_record_enable_memento (this)); + Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this); mix_group->apply (&Route::set_record_enable, yn, this); - _session.add_redo_no_execute (_session.global_record_enable_memento(this)); + cmd->mark(); + _session.add_command(cmd); _session.commit_reversible_command (); } else { reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this); diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index 0c76699aef..44cec8638c 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -77,6 +77,7 @@ send.cc session.cc session_butler.cc session_click.cc +session_command.cc session_events.cc session_export.cc session_midi.cc diff --git a/libs/ardour/ardour/automation_event.h b/libs/ardour/ardour/automation_event.h index 78daa531dd..1fa29d4adf 100644 --- a/libs/ardour/ardour/automation_event.h +++ b/libs/ardour/ardour/automation_event.h @@ -51,7 +51,7 @@ struct ControlEvent { }; -class AutomationList : public StateManager +class AutomationList : public StateManager, public Stateful { public: typedef std::list<ControlEvent*> AutomationEventList; @@ -153,6 +153,9 @@ class AutomationList : public StateManager virtual void store_state (XMLNode& node) const; virtual void load_state (const XMLNode&); + XMLNode &get_state(void); + int set_state (const XMLNode &s); + void set_max_xval (double); double get_max_xval() const { return max_xval; } diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 8d10d9f598..0c53cc32e7 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -489,7 +489,7 @@ class Session : public sigc::trackable, public Stateful static vector<string*>* possible_states(string path); XMLNode& get_state(); - int set_state(const XMLNode& node); + int set_state(const XMLNode& node); // not idempotent XMLNode& get_template(); void add_instant_xml (XMLNode&, const std::string& dir); @@ -830,23 +830,65 @@ class Session : public sigc::trackable, public Stateful string next_undo() const { return history.next_undo(); } string next_redo() const { return history.next_redo(); } - void begin_reversible_command (string cmd_name, UndoAction *private_undo = 0); - void commit_reversible_command (UndoAction* private_redo = 0); + void begin_reversible_command (string cmd_name); + void commit_reversible_command (Command* cmd = 0); - void add_undo (const UndoAction& ua) { - current_cmd.add_undo (ua); - } - void add_redo (const UndoAction& ua) { - current_cmd.add_redo (ua); - } - void add_redo_no_execute (const UndoAction& ua) { - current_cmd.add_redo_no_execute (ua); + void add_command (Command *const cmd) { + current_trans.add_command (cmd); } - UndoAction global_solo_memento (void *src); - UndoAction global_mute_memento (void *src); - UndoAction global_record_enable_memento (void *src); - UndoAction global_metering_memento (void *src); + // these commands are implemented in libs/ardour/session_command.cc + class GlobalSoloStateCommand : public Command + { + GlobalRouteBooleanState before, after; + void *src; + Session &sess; + public: + GlobalSoloStateCommand(Session &, void *src); + void operator()(); + void undo(); + XMLNode &serialize(); + void mark(); + }; + + class GlobalMuteStateCommand : public Command + { + GlobalRouteBooleanState before, after; + void *src; + Session &sess; + public: + GlobalMuteStateCommand(Session &, void *src); + void operator()(); + void undo(); + XMLNode &serialize(); + void mark(); + }; + + class GlobalRecordEnableStateCommand : public Command + { + GlobalRouteBooleanState before, after; + void *src; + Session &sess; + public: + GlobalRecordEnableStateCommand(Session &, void *src); + void operator()(); + void undo(); + XMLNode &serialize(); + void mark(); + }; + + class GlobalMeteringStateCommand : public Command + { + GlobalRouteMeterState before, after; + void *src; + Session &sess; + public: + GlobalMeteringStateCommand(Session &, void *src); + void operator()(); + void undo(); + XMLNode &serialize(); + void mark(); + }; /* edit mode */ @@ -1624,7 +1666,7 @@ class Session : public sigc::trackable, public Stateful void reverse_diskstream_buffers (); UndoHistory history; - UndoCommand current_cmd; + UndoTransaction current_trans; GlobalRouteBooleanState get_global_route_boolean (bool (Route::*method)(void) const); GlobalRouteMeterState get_global_route_metering (); diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index 7f0cb55821..7d2a2103bb 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -34,6 +34,7 @@ #include <pbd/basename.h> #include <glibmm/thread.h> #include <pbd/xml++.h> +#include <pbd/memento_command.h> #include <ardour/ardour.h> #include <ardour/audioengine.h> @@ -1594,7 +1595,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca // cerr << _name << ": there are " << capture_info.size() << " capture_info records\n"; - _session.add_undo (_playlist->get_memento()); + XMLNode &before = _playlist->get_state(); _playlist->freeze (); for (buffer_position = channels[0].write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) { @@ -1625,7 +1626,8 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca } _playlist->thaw (); - _session.add_redo_no_execute (_playlist->get_memento()); + XMLNode &after = _playlist->get_state(); + _session.add_command (new MementoCommand<Playlist>(*_playlist, before, after)); } mark_write_completed = true; diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc index 63492b375b..dc1767d1e7 100644 --- a/libs/ardour/automation_event.cc +++ b/libs/ardour/automation_event.cc @@ -1246,3 +1246,17 @@ AutomationList::load_state (const XMLNode& node) add (x, y); } } + +XMLNode &AutomationList::get_state () +{ + XMLNode *node = new XMLNode("AutomationList"); + store_state(*node); + return *node; +} + +int AutomationList::set_state(const XMLNode &s) +{ + load_state(s); + return 0; +} + diff --git a/libs/ardour/session_command.cc b/libs/ardour/session_command.cc new file mode 100644 index 0000000000..6482de41fb --- /dev/null +++ b/libs/ardour/session_command.cc @@ -0,0 +1,93 @@ +#include <ardour/session.h> +#include <ardour/route.h> + +namespace ARDOUR { +// solo +Session::GlobalSoloStateCommand::GlobalSoloStateCommand(Session &sess, void *src) + : sess(sess), src(src) +{ + after = before = sess.get_global_route_boolean(&Route::soloed); +} +void Session::GlobalSoloStateCommand::mark() +{ + after = sess.get_global_route_boolean(&Route::soloed); +} +void Session::GlobalSoloStateCommand::operator()() +{ + sess.set_global_solo(after, src); +} +void Session::GlobalSoloStateCommand::undo() +{ + sess.set_global_solo(before, src); +} +XMLNode &Session::GlobalSoloStateCommand::serialize() +{ +} + +// mute +Session::GlobalMuteStateCommand::GlobalMuteStateCommand(Session &sess, void *src) + : sess(sess), src(src) +{ + after = before = sess.get_global_route_boolean(&Route::muted); +} +void Session::GlobalMuteStateCommand::mark() +{ + after = sess.get_global_route_boolean(&Route::muted); +} +void Session::GlobalMuteStateCommand::operator()() +{ + sess.set_global_mute(after, src); +} +void Session::GlobalMuteStateCommand::undo() +{ + sess.set_global_mute(before, src); +} +XMLNode &Session::GlobalMuteStateCommand::serialize() +{ +} + +// record enable +Session::GlobalRecordEnableStateCommand::GlobalRecordEnableStateCommand(Session &sess, void *src) + : sess(sess), src(src) +{ + after = before = sess.get_global_route_boolean(&Route::record_enabled); +} +void Session::GlobalRecordEnableStateCommand::mark() +{ + after = sess.get_global_route_boolean(&Route::record_enabled); +} +void Session::GlobalRecordEnableStateCommand::operator()() +{ + sess.set_global_record_enable(after, src); +} +void Session::GlobalRecordEnableStateCommand::undo() +{ + sess.set_global_record_enable(before, src); +} +XMLNode &Session::GlobalRecordEnableStateCommand::serialize() +{ +} + +// metering +Session::GlobalMeteringStateCommand::GlobalMeteringStateCommand(Session &sess, void *src) + : sess(sess), src(src) +{ + after = before = sess.get_global_route_metering(); +} +void Session::GlobalMeteringStateCommand::mark() +{ + after = sess.get_global_route_metering(); +} +void Session::GlobalMeteringStateCommand::operator()() +{ + sess.set_global_route_metering(after, src); +} +void Session::GlobalMeteringStateCommand::undo() +{ + sess.set_global_route_metering(before, src); +} +XMLNode &Session::GlobalMeteringStateCommand::serialize() +{ +} + +} // namespace ARDOUR diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index c90fd91d73..9619e77ad1 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -2569,29 +2569,25 @@ Session::set_meter_falloff (float val) void -Session::begin_reversible_command (string name, UndoAction* private_undo) +Session::begin_reversible_command (string name) { - current_cmd.clear (); - current_cmd.set_name (name); - - if (private_undo) { - current_cmd.add_undo (*private_undo); - } + current_trans.clear (); + current_trans.set_name (name); } void -Session::commit_reversible_command (UndoAction* private_redo) +Session::commit_reversible_command (Command *cmd) { struct timeval now; - if (private_redo) { - current_cmd.add_redo_no_execute (*private_redo); + if (cmd) { + current_trans.add_command (cmd); } gettimeofday (&now, 0); - current_cmd.set_timestamp (now); + current_trans.set_timestamp (now); - history.add (current_cmd); + history.add (current_trans); } Session::GlobalRouteBooleanState @@ -2670,6 +2666,7 @@ Session::set_global_record_enable (GlobalRouteBooleanState s, void* src) set_global_route_boolean (s, &Route::set_record_enable, src); } +#if 0 UndoAction Session::global_mute_memento (void* src) { @@ -2693,6 +2690,7 @@ Session::global_record_enable_memento (void* src) { return sigc::bind (mem_fun (*this, &Session::set_global_record_enable), get_global_route_boolean (&Route::record_enabled), src); } +#endif static bool template_filter (const string &str, void *arg) diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index d850fb94c8..3bd54aa69c 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -29,6 +29,7 @@ #include <pbd/error.h> #include <glibmm/thread.h> #include <pbd/pthread_utils.h> +#include <pbd/memento_command.h> #include <midi++/mmc.h> #include <midi++/port.h> @@ -320,8 +321,10 @@ Session::non_realtime_stop (bool abort) } if (change_end) { - add_undo (sigc::retype_return<void>(sigc::bind (mem_fun (*loc, &Location::set_end), loc->end()))); - add_redo (sigc::retype_return<void>(sigc::bind (mem_fun (*loc, &Location::set_end), _transport_frame))); + XMLNode &before = loc->get_state(); + loc->set_end(_transport_frame); + XMLNode &after = loc->get_state(); + add_command (new MementoCommand<Location>(*loc, before, after)); } _end_location_is_free = false; diff --git a/libs/pbd/SConscript b/libs/pbd/SConscript index 36fb02885f..4b15dd70d1 100644 --- a/libs/pbd/SConscript +++ b/libs/pbd/SConscript @@ -21,6 +21,7 @@ pbd_files = Split(""" basename.cc base_ui.cc convert.cc +command.cc controllable.cc dmalloc.cc error.cc diff --git a/libs/pbd/command.cc b/libs/pbd/command.cc new file mode 100644 index 0000000000..3f5aca8e51 --- /dev/null +++ b/libs/pbd/command.cc @@ -0,0 +1,10 @@ +#include <pbd/command.h> + +class XMLNode; + +XMLNode &Command::serialize() +{ + XMLNode *node = new XMLNode ("Command"); + // TODO + return *node; +} diff --git a/libs/pbd/pbd/command.h b/libs/pbd/pbd/command.h new file mode 100644 index 0000000000..35ae011530 --- /dev/null +++ b/libs/pbd/pbd/command.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2006 Hans Fugal & 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. + + $Id: /local/undo/libs/pbd3/pbd/undo.h 80 2006-06-22T22:37:01.079855Z fugalh $ +*/ + +#ifndef __lib_pbd_command_h__ +#define __lib_pbd_command_h__ + +#include <pbd/serializable.h> + +class Command : public Serializable +{ + public: + virtual ~Command() {} + virtual void operator() () = 0; + virtual void undo() = 0; + virtual void redo() { (*this)(); } + virtual XMLNode &serialize(); +}; + +#endif // __lib_pbd_command_h_ diff --git a/libs/pbd/pbd/memento_command.h b/libs/pbd/pbd/memento_command.h new file mode 100644 index 0000000000..c8bfe5de4c --- /dev/null +++ b/libs/pbd/pbd/memento_command.h @@ -0,0 +1,94 @@ +/* + Copyright (C) 2006 Hans Fugal & 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. + + $Id: /local/undo/libs/pbd3/pbd/undo.h 132 2006-06-29T18:45:16.609763Z fugalh $ +*/ + +#ifndef __lib_pbd_memento_command_h__ +#define __lib_pbd_memento_command_h__ + +#include <pbd/command.h> +#include <sigc++/slot.h> + +/** This command class is initialized with before and after mementos + * (from Stateful::get_state()), so undo becomes restoring the before + * memento, and redo is restoring the after memento. + */ +template <class obj_T> +class MementoCommand : public Command +{ + public: + MementoCommand(obj_T &obj, + XMLNode &before, + XMLNode &after + ) + : obj(obj), before(before), after(after) {} + void operator() () { obj.set_state(after); } + void undo() { obj.set_state(before); } + virtual XMLNode &serialize() {} + //{ + // obj.id + // key is "MementoCommand" or something + // before and after mementos + //} + // TODO does this need a copy constructor? + protected: + obj_T &obj; + XMLNode &before, &after; +}; + +template <class obj_T> +class MementoUndoCommand : public Command +{ +public: + MementoUndoCommand(obj_T &obj, + XMLNode &before) + : obj(obj), before(before) {} + void operator() () { /* noop */ } + void undo() { obj.set_state(before); } + virtual XMLNode &serialize() {} + //{ + // obj.id + // key is "MementoCommand" or something + // before and after mementos + //} +protected: + obj_T &obj; + XMLNode &before; +}; + +template <class obj_T> +class MementoRedoCommand : public Command +{ +public: + MementoRedoCommand(obj_T &obj, + XMLNode &after) + : obj(obj), after(after) {} + void operator() () { obj.set_state(after); } + void undo() { /* noop */ } + virtual XMLNode &serialize() {} + //{ + // obj.id + // key is "MementoCommand" or something + // before and after mementos + //} +protected: + obj_T &obj; + XMLNode &after; +}; + +#endif // __lib_pbd_memento_h__ diff --git a/libs/pbd/pbd/serializable.h b/libs/pbd/pbd/serializable.h new file mode 100644 index 0000000000..f6ac4e92fb --- /dev/null +++ b/libs/pbd/pbd/serializable.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2006 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. + + $Id: /local/undo/libs/pbd3/pbd/undo.h 59 2006-06-15T18:16:20.960977Z fugalh $ +*/ + +#ifndef __lib_pbd_serializable_h__ +#define __lib_pbd_serializable_h__ + +#include <pbd/xml++.h> + +class Serializable +{ +public: + virtual XMLNode &serialize() = 0; + virtual ~Serializable() {} +}; + +#endif // __lib_pbd_serializable_h__ diff --git a/libs/pbd/pbd/undo.h b/libs/pbd/pbd/undo.h index f067635ed3..33577ed4d7 100644 --- a/libs/pbd/pbd/undo.h +++ b/libs/pbd/pbd/undo.h @@ -23,29 +23,33 @@ #include <string> #include <list> +#include <map> #include <sigc++/slot.h> +#include <sigc++/bind.h> #include <sys/time.h> +#include <pbd/command.h> using std::string; using std::list; typedef sigc::slot<void> UndoAction; -class UndoCommand +class UndoTransaction : public Command { public: - UndoCommand (); - UndoCommand (const UndoCommand&); - UndoCommand& operator= (const UndoCommand&); + UndoTransaction (); + UndoTransaction (const UndoTransaction&); + UndoTransaction& operator= (const UndoTransaction&); void clear (); - void add_undo (const UndoAction&); - void add_redo (const UndoAction&); - void add_redo_no_execute (const UndoAction&); + void add_command (Command *const); + void operator() (); void undo(); void redo(); + + XMLNode &serialize(); void set_name (const string& str) { _name = str; @@ -61,8 +65,7 @@ class UndoCommand } private: - list<UndoAction> redo_actions; - list<UndoAction> undo_actions; + list<Command*> actions; struct timeval _timestamp; string _name; }; @@ -73,7 +76,7 @@ class UndoHistory UndoHistory() {} ~UndoHistory() {} - void add (UndoCommand uc); + void add (UndoTransaction ut); void undo (unsigned int n); void redo (unsigned int n); @@ -88,8 +91,8 @@ class UndoHistory void clear_redo (); private: - list<UndoCommand> UndoList; - list<UndoCommand> RedoList; + list<UndoTransaction> UndoList; + list<UndoTransaction> RedoList; }; diff --git a/libs/pbd/undo.cc b/libs/pbd/undo.cc index f2f11b1c5c..aa27f95789 100644 --- a/libs/pbd/undo.cc +++ b/libs/pbd/undo.cc @@ -25,77 +25,74 @@ using namespace std; using namespace sigc; -UndoCommand::UndoCommand () +UndoTransaction::UndoTransaction () { } -UndoCommand::UndoCommand (const UndoCommand& rhs) +UndoTransaction::UndoTransaction (const UndoTransaction& rhs) { _name = rhs._name; clear (); - undo_actions.insert(undo_actions.end(),rhs.undo_actions.begin(),rhs.undo_actions.end()); - redo_actions.insert(redo_actions.end(),rhs.redo_actions.begin(),rhs.redo_actions.end()); + actions.insert(actions.end(),rhs.actions.begin(),rhs.actions.end()); } -UndoCommand& -UndoCommand::operator= (const UndoCommand& rhs) +UndoTransaction& +UndoTransaction::operator= (const UndoTransaction& rhs) { if (this == &rhs) return *this; _name = rhs._name; clear (); - undo_actions.insert(undo_actions.end(),rhs.undo_actions.begin(),rhs.undo_actions.end()); - redo_actions.insert(redo_actions.end(),rhs.redo_actions.begin(),rhs.redo_actions.end()); + actions.insert(actions.end(),rhs.actions.begin(),rhs.actions.end()); return *this; } void -UndoCommand::add_undo (const UndoAction& action) +UndoTransaction::add_command (Command *const action) { - undo_actions.push_back (action); + actions.push_back (action); } void -UndoCommand::add_redo (const UndoAction& action) +UndoTransaction::clear () { - redo_actions.push_back (action); - redo_actions.back()(); // operator() + actions.clear (); } void -UndoCommand::add_redo_no_execute (const UndoAction& action) +UndoTransaction::operator() () { - redo_actions.push_back (action); -} - -void -UndoCommand::clear () -{ - undo_actions.clear (); - redo_actions.clear (); + for (list<Command*>::iterator i = actions.begin(); i != actions.end(); ++i) { + (*(*i))(); + } } void -UndoCommand::undo () +UndoTransaction::undo () { cerr << "Undo " << _name << endl; - for (list<UndoAction>::reverse_iterator i = undo_actions.rbegin(); i != undo_actions.rend(); ++i) { - (*i)(); + for (list<Command*>::reverse_iterator i = actions.rbegin(); i != actions.rend(); ++i) { + (*i)->undo(); } } void -UndoCommand::redo () +UndoTransaction::redo () { cerr << "Redo " << _name << endl; - for (list<UndoAction>::iterator i = redo_actions.begin(); i != redo_actions.end(); ++i) { - (*i)(); - } + (*this)(); +} + +XMLNode &UndoTransaction::serialize() +{ + XMLNode *node = new XMLNode ("UndoTransaction"); + // TODO + return *node; } void -UndoHistory::add (UndoCommand uc) +UndoHistory::add (UndoTransaction ut) { - UndoList.push_back (uc); + UndoList.push_back (ut); } void @@ -105,10 +102,10 @@ UndoHistory::undo (unsigned int n) if (UndoList.size() == 0) { return; } - UndoCommand uc = UndoList.back (); + UndoTransaction ut = UndoList.back (); UndoList.pop_back (); - uc.undo (); - RedoList.push_back (uc); + ut.undo (); + RedoList.push_back (ut); } } @@ -119,10 +116,10 @@ UndoHistory::redo (unsigned int n) if (RedoList.size() == 0) { return; } - UndoCommand cmd = RedoList.back (); + UndoTransaction ut = RedoList.back (); RedoList.pop_back (); - cmd.redo (); - UndoList.push_back (cmd); + ut.redo (); + UndoList.push_back (ut); } } |