Separate selection operations into their own temporary history mechanism.
The user can now replay *all* earlier selection operations until the next session undo/redo command, or the completion of a new operation. Nothing relating to selection ops is stored, and selection operation history is begun on first idle. Selection operation history is fundamentally different from the history of operations which act on a selection in terms of both their viewport and the amount of information required to replay them. WRT undo, the user of a selection op doesn't care about the viewport state at the beginning of an op, but rather that at the end of the previous one.
This commit is contained in:
parent
b5c9a92a58
commit
a795892492
@ -151,6 +151,10 @@
|
||||
<menu name='Edit' action='Edit'>
|
||||
<menuitem action='undo'/>
|
||||
<menuitem action='redo'/>
|
||||
<separator/>
|
||||
<menuitem action='undo-last-selection-op'/>
|
||||
<menuitem action='redo-last-selection-op'/>
|
||||
<separator/>
|
||||
<menuitem action='editor-cut'/>
|
||||
<menuitem action='editor-copy'/>
|
||||
<menuitem action='editor-paste'/>
|
||||
|
@ -284,6 +284,8 @@ Editor::Editor ()
|
||||
, _tools_tearoff (0)
|
||||
|
||||
, _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
|
||||
, selection_op_cmd_depth (0)
|
||||
, selection_op_history_it (0)
|
||||
|
||||
/* nudge */
|
||||
|
||||
@ -309,6 +311,7 @@ Editor::Editor ()
|
||||
selection = new Selection (this);
|
||||
cut_buffer = new Selection (this);
|
||||
_selection_memento = new SelectionMemento ();
|
||||
selection_op_history.clear();
|
||||
before.clear();
|
||||
|
||||
clicked_regionview = 0;
|
||||
@ -3311,6 +3314,95 @@ Editor::map_transport_state ()
|
||||
|
||||
/* UNDO/REDO */
|
||||
|
||||
void
|
||||
Editor::begin_selection_op_history ()
|
||||
{
|
||||
selection_op_cmd_depth = 0;
|
||||
selection_op_history_it = 0;
|
||||
selection_op_history.clear();
|
||||
selection_undo_action->set_sensitive (false);
|
||||
selection_redo_action->set_sensitive (false);
|
||||
selection_op_history.push_front (&_selection_memento->get_state ());
|
||||
}
|
||||
|
||||
void
|
||||
Editor::begin_reversible_selection_op (string name)
|
||||
{
|
||||
if (_session) {
|
||||
//cerr << name << endl;
|
||||
/* begin/commit pairs can be nested */
|
||||
selection_op_cmd_depth++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Editor::commit_reversible_selection_op ()
|
||||
{
|
||||
if (_session) {
|
||||
if (selection_op_cmd_depth == 1) {
|
||||
|
||||
if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
|
||||
list<XMLNode *>::iterator it = selection_op_history.begin();
|
||||
advance (it, selection_op_history_it);
|
||||
selection_op_history.erase (selection_op_history.begin(), it);
|
||||
}
|
||||
selection_op_history.push_front (&_selection_memento->get_state ());
|
||||
selection_op_history_it = 0;
|
||||
}
|
||||
|
||||
if (selection_op_cmd_depth > 0) {
|
||||
selection_op_cmd_depth--;
|
||||
}
|
||||
|
||||
selection_undo_action->set_sensitive (true);
|
||||
selection_redo_action->set_sensitive (false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Editor::undo_reversible_selection_op ()
|
||||
{
|
||||
if (_session) {
|
||||
selection_op_history_it++;
|
||||
uint32_t n = 0;
|
||||
for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
|
||||
if (n == selection_op_history_it) {
|
||||
_selection_memento->set_state (*(*i), Stateful::current_state_version);
|
||||
selection_redo_action->set_sensitive (true);
|
||||
}
|
||||
++n;
|
||||
|
||||
}
|
||||
/* is there an earlier entry? */
|
||||
if ((selection_op_history_it + 1) >= selection_op_history.size()) {
|
||||
selection_undo_action->set_sensitive (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Editor::redo_reversible_selection_op ()
|
||||
{
|
||||
if (_session) {
|
||||
if (selection_op_history_it > 0) {
|
||||
selection_op_history_it--;
|
||||
}
|
||||
uint32_t n = 0;
|
||||
for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
|
||||
if (n == selection_op_history_it) {
|
||||
_selection_memento->set_state (*(*i), Stateful::current_state_version);
|
||||
selection_undo_action->set_sensitive (true);
|
||||
}
|
||||
++n;
|
||||
|
||||
}
|
||||
|
||||
if (selection_op_history_it == 0) {
|
||||
selection_redo_action->set_sensitive (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Editor::begin_reversible_command (string name)
|
||||
{
|
||||
@ -3335,9 +3427,12 @@ Editor::commit_reversible_command ()
|
||||
if (_session) {
|
||||
if (before.size() == 1) {
|
||||
_session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
|
||||
begin_selection_op_history ();
|
||||
}
|
||||
|
||||
if (!before.empty()) {
|
||||
if (before.empty()) {
|
||||
cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
|
||||
} else {
|
||||
before.pop_back();
|
||||
}
|
||||
|
||||
@ -4922,6 +5017,9 @@ Editor::first_idle ()
|
||||
_routes->redisplay ();
|
||||
|
||||
delete dialog;
|
||||
|
||||
begin_selection_op_history ();
|
||||
|
||||
_have_idled = true;
|
||||
}
|
||||
|
||||
|
@ -440,6 +440,11 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
||||
ARDOUR::RoundMode direction = ARDOUR::RoundNearest,
|
||||
bool for_mark = false);
|
||||
|
||||
void begin_selection_op_history ();
|
||||
void begin_reversible_selection_op (std::string cmd_name);
|
||||
void commit_reversible_selection_op ();
|
||||
void undo_reversible_selection_op ();
|
||||
void redo_reversible_selection_op ();
|
||||
void begin_reversible_command (std::string cmd_name);
|
||||
void begin_reversible_command (GQuark);
|
||||
void commit_reversible_command ();
|
||||
@ -1941,6 +1946,10 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
||||
|
||||
void write_selection ();
|
||||
|
||||
uint32_t selection_op_cmd_depth;
|
||||
uint32_t selection_op_history_it;
|
||||
|
||||
std::list<XMLNode *> selection_op_history; /* used in *_reversible_selection_op */
|
||||
std::list<XMLNode *> before; /* used in *_reversible_command */
|
||||
|
||||
void update_title ();
|
||||
@ -2066,6 +2075,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
||||
|
||||
Glib::RefPtr<Gtk::Action> undo_action;
|
||||
Glib::RefPtr<Gtk::Action> redo_action;
|
||||
Glib::RefPtr<Gtk::Action> selection_undo_action;
|
||||
Glib::RefPtr<Gtk::Action> selection_redo_action;
|
||||
|
||||
void history_changed ();
|
||||
|
||||
|
@ -317,6 +317,9 @@ Editor::register_actions ()
|
||||
redo_action = reg_sens (editor_actions, "alternate-redo", _("Redo"), sigc::bind (sigc::mem_fun(*this, &Editor::redo), 1U));
|
||||
redo_action = reg_sens (editor_actions, "alternate-alternate-redo", _("Redo"), sigc::bind (sigc::mem_fun(*this, &Editor::redo), 1U));
|
||||
|
||||
selection_undo_action = reg_sens (editor_actions, "undo-last-selection-op", _("Undo Last Selection Op"), sigc::mem_fun(*this, &Editor::undo_reversible_selection_op));
|
||||
selection_redo_action = reg_sens (editor_actions, "redo-last-selection-op", _("Redo Last Selection Op"), sigc::mem_fun(*this, &Editor::redo_reversible_selection_op));
|
||||
|
||||
reg_sens (editor_actions, "export-audio", _("Export Audio"), sigc::mem_fun(*this, &Editor::export_audio));
|
||||
reg_sens (editor_actions, "export-range", _("Export Range"), sigc::mem_fun(*this, &Editor::export_range));
|
||||
|
||||
|
@ -4379,6 +4379,7 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
|
||||
{
|
||||
Session* s = _editor->session();
|
||||
|
||||
_editor->begin_reversible_selection_op (_("Change Time Selection"));
|
||||
if (movement_occurred) {
|
||||
motion (event, false);
|
||||
/* XXX this is not object-oriented programming at all. ick */
|
||||
@ -4435,6 +4436,7 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
|
||||
|
||||
_editor->stop_canvas_autoscroll ();
|
||||
_editor->clicked_selection = 0;
|
||||
_editor->commit_reversible_selection_op ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -5192,11 +5194,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->begin_reversible_selection_op (_("rubberband selection"));
|
||||
|
||||
_editor->select_all_within (x1, x2 - 1, y1, y2, _editor->track_views, op, false);
|
||||
|
||||
_editor->commit_reversible_command ();
|
||||
_editor->commit_reversible_selection_op ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1465,7 +1465,11 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
||||
}
|
||||
|
||||
/* do any (de)selection operations that should occur on button release */
|
||||
|
||||
begin_reversible_selection_op (_("Button Select"));
|
||||
button_selection (item, event, item_type);
|
||||
commit_reversible_selection_op ();
|
||||
|
||||
return true;
|
||||
break;
|
||||
|
||||
|
@ -122,6 +122,8 @@ Editor::undo (uint32_t n)
|
||||
|
||||
if (_session) {
|
||||
_session->undo (n);
|
||||
redo_action->set_sensitive(true);
|
||||
begin_selection_op_history ();
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,6 +136,11 @@ Editor::redo (uint32_t n)
|
||||
|
||||
if (_session) {
|
||||
_session->redo (n);
|
||||
cerr << "redo depth is : " << _session->redo_depth() << endl;
|
||||
if (_session->redo_depth() == 0) {
|
||||
redo_action->set_sensitive(false);
|
||||
}
|
||||
begin_selection_op_history ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,6 +270,8 @@ Editor::set_selected_track_as_side_effect (Selection::Operation op)
|
||||
void
|
||||
Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
|
||||
{
|
||||
begin_reversible_selection_op(_("Set Selected Track"));
|
||||
|
||||
switch (op) {
|
||||
case Selection::Toggle:
|
||||
if (selection->selected (&view)) {
|
||||
@ -295,6 +297,8 @@ Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no
|
||||
extend_selection_to_track (view);
|
||||
break;
|
||||
}
|
||||
|
||||
commit_reversible_selection_op ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -892,7 +896,7 @@ Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> regi
|
||||
return;
|
||||
}
|
||||
|
||||
begin_reversible_command (_("set selected regions"));
|
||||
begin_reversible_selection_op (_("set selected regions"));
|
||||
|
||||
switch (op) {
|
||||
case Selection::Toggle:
|
||||
@ -910,7 +914,7 @@ Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> regi
|
||||
break;
|
||||
}
|
||||
|
||||
commit_reversible_command () ;
|
||||
commit_reversible_selection_op () ;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -935,11 +939,11 @@ Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView*
|
||||
return true;
|
||||
}
|
||||
|
||||
begin_reversible_command (_("set selected regions"));
|
||||
begin_reversible_selection_op (_("set selected regions"));
|
||||
|
||||
selection->set (rv);
|
||||
|
||||
commit_reversible_command () ;
|
||||
commit_reversible_selection_op () ;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1348,6 +1352,8 @@ Editor::select_all_in_track (Selection::Operation op)
|
||||
return;
|
||||
}
|
||||
|
||||
begin_reversible_selection_op(_("Select All in Track"));
|
||||
|
||||
clicked_routeview->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
|
||||
|
||||
switch (op) {
|
||||
@ -1364,6 +1370,8 @@ Editor::select_all_in_track (Selection::Operation op)
|
||||
selection->add (touched);
|
||||
break;
|
||||
}
|
||||
|
||||
commit_reversible_selection_op ();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1408,7 +1416,7 @@ Editor::select_all_objects (Selection::Operation op)
|
||||
}
|
||||
|
||||
|
||||
begin_reversible_command (_("select all"));
|
||||
begin_reversible_selection_op (_("select all"));
|
||||
switch (op) {
|
||||
case Selection::Add:
|
||||
selection->add (touched);
|
||||
@ -1423,7 +1431,7 @@ Editor::select_all_objects (Selection::Operation op)
|
||||
/* meaningless, because we're selecting everything */
|
||||
break;
|
||||
}
|
||||
commit_reversible_command ();
|
||||
commit_reversible_selection_op ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1435,8 +1443,10 @@ Editor::invert_selection_in_track ()
|
||||
return;
|
||||
}
|
||||
|
||||
begin_reversible_selection_op(_("Invert Selection in Track"));
|
||||
clicked_routeview->get_inverted_selectables (*selection, touched);
|
||||
selection->set (touched);
|
||||
commit_reversible_selection_op ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1461,7 +1471,9 @@ Editor::invert_selection ()
|
||||
(*iter)->get_inverted_selectables (*selection, touched);
|
||||
}
|
||||
|
||||
begin_reversible_selection_op(_("Invert Selection"));
|
||||
selection->set (touched);
|
||||
commit_reversible_selection_op ();
|
||||
}
|
||||
|
||||
/** @param start Start time in session frames.
|
||||
@ -1502,7 +1514,7 @@ Editor::select_all_within (framepos_t start, framepos_t end, double top, double
|
||||
}
|
||||
}
|
||||
|
||||
begin_reversible_command (_("select all within"));
|
||||
begin_reversible_selection_op (_("select all within"));
|
||||
switch (op) {
|
||||
case Selection::Add:
|
||||
selection->add (found);
|
||||
@ -1518,7 +1530,7 @@ Editor::select_all_within (framepos_t start, framepos_t end, double top, double
|
||||
break;
|
||||
}
|
||||
|
||||
commit_reversible_command ();
|
||||
commit_reversible_selection_op ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1560,9 +1572,9 @@ Editor::set_selection_from_loop()
|
||||
void
|
||||
Editor::set_selection_from_range (Location& loc)
|
||||
{
|
||||
begin_reversible_command (_("set selection from range"));
|
||||
begin_reversible_selection_op (_("set selection from range"));
|
||||
selection->set (loc.start(), loc.end());
|
||||
commit_reversible_command ();
|
||||
commit_reversible_selection_op ();
|
||||
|
||||
if (!Profile->get_sae()) {
|
||||
set_mouse_mode (Editing::MouseRange, false);
|
||||
@ -1600,9 +1612,9 @@ Editor::select_all_selectables_using_time_selection ()
|
||||
(*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
|
||||
}
|
||||
|
||||
begin_reversible_command (_("select all from range"));
|
||||
begin_reversible_selection_op (_("select all from range"));
|
||||
selection->set (touched);
|
||||
commit_reversible_command ();
|
||||
commit_reversible_selection_op ();
|
||||
}
|
||||
|
||||
|
||||
@ -1631,9 +1643,9 @@ Editor::select_all_selectables_using_punch()
|
||||
}
|
||||
(*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
|
||||
}
|
||||
begin_reversible_command (_("select all from punch"));
|
||||
begin_reversible_selection_op (_("select all from punch"));
|
||||
selection->set (touched);
|
||||
commit_reversible_command ();
|
||||
commit_reversible_selection_op ();
|
||||
|
||||
}
|
||||
|
||||
@ -1662,9 +1674,9 @@ Editor::select_all_selectables_using_loop()
|
||||
}
|
||||
(*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
|
||||
}
|
||||
begin_reversible_command (_("select all from loop"));
|
||||
begin_reversible_selection_op (_("select all from loop"));
|
||||
selection->set (touched);
|
||||
commit_reversible_command ();
|
||||
commit_reversible_selection_op ();
|
||||
|
||||
}
|
||||
|
||||
@ -1698,9 +1710,9 @@ Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
|
||||
}
|
||||
|
||||
if (after) {
|
||||
begin_reversible_command (_("select all after cursor"));
|
||||
begin_reversible_selection_op (_("select all after cursor"));
|
||||
} else {
|
||||
begin_reversible_command (_("select all before cursor"));
|
||||
begin_reversible_selection_op (_("select all before cursor"));
|
||||
}
|
||||
|
||||
TrackViewList* ts;
|
||||
@ -1718,7 +1730,7 @@ Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
|
||||
(*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
|
||||
}
|
||||
selection->set (touched);
|
||||
commit_reversible_command ();
|
||||
commit_reversible_selection_op ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1749,9 +1761,9 @@ Editor::select_all_selectables_using_edit (bool after)
|
||||
}
|
||||
|
||||
if (after) {
|
||||
begin_reversible_command (_("select all after edit"));
|
||||
begin_reversible_selection_op (_("select all after edit"));
|
||||
} else {
|
||||
begin_reversible_command (_("select all before edit"));
|
||||
begin_reversible_selection_op (_("select all before edit"));
|
||||
}
|
||||
|
||||
TrackViewList* ts;
|
||||
@ -1769,7 +1781,7 @@ Editor::select_all_selectables_using_edit (bool after)
|
||||
(*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
|
||||
}
|
||||
selection->set (touched);
|
||||
commit_reversible_command ();
|
||||
commit_reversible_selection_op ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1806,7 +1818,9 @@ Editor::select_all_selectables_between (bool /*within*/)
|
||||
(*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
|
||||
}
|
||||
|
||||
begin_reversible_selection_op(_("Select all Selectables Between"));
|
||||
selection->set (touched);
|
||||
commit_reversible_selection_op ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1823,8 +1837,10 @@ Editor::select_range_between ()
|
||||
return;
|
||||
}
|
||||
|
||||
begin_reversible_selection_op(_("Select Range Between"));
|
||||
set_mouse_mode (MouseRange);
|
||||
selection->set (start, end);
|
||||
commit_reversible_selection_op ();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1931,13 +1947,18 @@ Editor::get_edit_op_range (framepos_t& start, framepos_t& end) const
|
||||
void
|
||||
Editor::deselect_all ()
|
||||
{
|
||||
begin_reversible_selection_op(_("Clear Selection"));
|
||||
selection->clear ();
|
||||
commit_reversible_selection_op ();
|
||||
}
|
||||
|
||||
long
|
||||
Editor::select_range (framepos_t s, framepos_t e)
|
||||
{
|
||||
begin_reversible_selection_op(_("Select Range"));
|
||||
selection->add (clicked_axisview);
|
||||
selection->time.clear ();
|
||||
return selection->set (s, e);
|
||||
long ret = selection->set (s, e);
|
||||
commit_reversible_selection_op ();
|
||||
return ret;
|
||||
}
|
||||
|
@ -1261,6 +1261,7 @@ Selection::set_state (XMLNode const & node, int)
|
||||
}
|
||||
|
||||
clear_regions ();
|
||||
clear_points ();
|
||||
clear_time ();
|
||||
clear_tracks ();
|
||||
clear_markers ();
|
||||
|
Loading…
Reference in New Issue
Block a user