From 0c795e466729deaf72ec8c067b116ca546fe98b8 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Thu, 5 Sep 2013 16:52:18 +0200 Subject: Undo groups can now be auto-grouped. --- muse2/muse/functions.cpp | 14 ++++++++++-- muse2/muse/midiedit/scoreedit.cpp | 8 ++++++- muse2/muse/undo.cpp | 47 +++++++++++++++++++++++++++++++++++++++ muse2/muse/undo.h | 16 +++++++++++++ 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp index f13736b9..7569cc95 100644 --- a/muse2/muse/functions.cpp +++ b/muse2/muse/functions.cpp @@ -1230,6 +1230,8 @@ void paste_at(const QString& pt, int pos, int max_distance, bool always_new_part void select_all(const set& parts) { Undo operations; + operations.combobreaker=true; + for (set::iterator part=parts.begin(); part!=parts.end(); part++) for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++) { @@ -1242,6 +1244,8 @@ void select_all(const set& parts) void select_none(const set& parts) { Undo operations; + operations.combobreaker=true; + for (set::iterator part=parts.begin(); part!=parts.end(); part++) for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++) { @@ -1254,6 +1258,8 @@ void select_none(const set& parts) void select_invert(const set& parts) { Undo operations; + operations.combobreaker=true; + for (set::iterator part=parts.begin(); part!=parts.end(); part++) for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++) { @@ -1265,8 +1271,10 @@ void select_invert(const set& parts) void select_in_loop(const set& parts) { - select_none(parts); // this will automatically be grouped into one OperationGroup + select_none(parts); Undo operations; + operations.combobreaker=true; + for (set::iterator part=parts.begin(); part!=parts.end(); part++) for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++) { @@ -1278,8 +1286,10 @@ void select_in_loop(const set& parts) void select_not_in_loop(const set& parts) { - select_none(parts); // this will automatically be grouped into one OperationGroup + select_none(parts); Undo operations; + operations.combobreaker=true; + for (set::iterator part=parts.begin(); part!=parts.end(); part++) for (ciEvent ev_it=(*part)->events().begin(); ev_it!=(*part)->events().end(); ev_it++) { diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index a827e33c..954cd08a 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -74,6 +74,7 @@ using namespace std; using MusEGlobal::debugMsg; using MusEGlobal::heavyDebugMsg; using MusECore::UndoOp; +using MusECore::Undo; namespace MusEGui { @@ -4502,10 +4503,15 @@ void ScoreCanvas::set_velo_off(int velo) void ScoreCanvas::deselect_all() { set all_parts=get_all_parts(); + + Undo operations; + operations.combobreaker=true; for (set::iterator part=all_parts.begin(); part!=all_parts.end(); part++) for (MusECore::ciEvent event=(*part)->events().begin(); event!=(*part)->events().end(); event++) - MusEGlobal::song->applyOperation(UndoOp(UndoOp::SelectEvent, event->second, false, event->second.selected())); + operations.push_back(UndoOp(UndoOp::SelectEvent, event->second, false, event->second.selected())); + + MusEGlobal::song->applyOperationGroup(operations); } bool staff_t::cleanup_parts() diff --git a/muse2/muse/undo.cpp b/muse2/muse/undo.cpp index 37a0f7c1..b4a2a26f 100644 --- a/muse2/muse/undo.cpp +++ b/muse2/muse/undo.cpp @@ -227,6 +227,15 @@ void Song::startUndo() void Song::endUndo(SongChangedFlags_t flags) { + riUndo prev_undo = undoList->rbegin(); + prev_undo++; + if (prev_undo!=undoList->rend()) + { + // try to merge the current Undo with the last one + if (prev_undo->merge_combo(undoList->back())) + undoList->pop_back(); + } + updateFlags |= flags; endMsgCmd(); undoMode = false; @@ -276,6 +285,42 @@ void Song::setUndoRedoText() } +bool Undo::merge_combo(const Undo& other) +{ + if (this->combobreaker || other.combobreaker) + return false; + + bool has_select_event=false; + bool has_select_part=false; + bool has_other=false; + + for (ciUndoOp op=this->begin(); op!=this->end(); op++) + switch(op->type) + { + case UndoOp::DoNothing: break; + case UndoOp::SelectEvent: has_select_event=true; break; + case UndoOp::SelectPart: has_select_part=true; break; + default: has_other=true; break; + } + + for (ciUndoOp op=other.begin(); op!=other.end(); op++) + switch(op->type) + { + case UndoOp::DoNothing: break; + case UndoOp::SelectEvent: has_select_event=true; break; + case UndoOp::SelectPart: has_select_part=true; break; + default: has_other=true; break; + } + + bool mergeable = (has_select_event && !has_select_part && !has_other) || + (has_select_part && !has_select_event && !has_other); + + if (mergeable) + this->insert(this->end(), other.begin(), other.end()); + + return mergeable; +} + void prepareOperationGroup(Undo& group) { QSet deleted_tracks; @@ -362,6 +407,8 @@ bool Song::applyOperationGroup(Undo& group, bool doUndo) // append all elements from "group" to the end of undoList->back(). Undo& curUndo = undoList->back(); curUndo.insert(curUndo.end(), group.begin(), group.end()); + if (group.combobreaker) + curUndo.combobreaker=true; if (doUndo) endUndo(0); diff --git a/muse2/muse/undo.h b/muse2/muse/undo.h index 4619f797..f83ce491 100644 --- a/muse2/muse/undo.h +++ b/muse2/muse/undo.h @@ -128,7 +128,23 @@ struct UndoOp { class Undo : public std::list { public: + Undo() : std::list() { combobreaker=false; } + Undo(const Undo& other) : std::list(other) { this->combobreaker=other.combobreaker; } + Undo& operator=(const Undo& other) { std::list::operator=(other); this->combobreaker=other.combobreaker; return *this;} + bool empty() const; + + + /** if set, forbid merging (below). + * Defaults to false */ + bool combobreaker; + + /** is possible, merges itself and other by appending + * all contents of other at this->end(). + * returns true if merged, false otherwise. + * in case of success, the caller has to ensure that + * other is deleted from the UndoList. */ + bool merge_combo(const Undo& other); }; typedef Undo::iterator iUndoOp; -- cgit v1.2.1