summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Jung <flo@windfisch.org>2013-09-05 16:52:18 +0200
committerFlorian Jung <flo@windfisch.org>2013-09-05 16:52:18 +0200
commit0c795e466729deaf72ec8c067b116ca546fe98b8 (patch)
tree0492e27cba99468f5a16e247697050043844d3b0
parent66995bf5b29125666884f5fa9f9dddd46574abc9 (diff)
Undo groups can now be auto-grouped.
-rw-r--r--muse2/muse/functions.cpp14
-rw-r--r--muse2/muse/midiedit/scoreedit.cpp8
-rw-r--r--muse2/muse/undo.cpp47
-rw-r--r--muse2/muse/undo.h16
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<const Part*>& parts)
{
Undo operations;
+ operations.combobreaker=true;
+
for (set<const Part*>::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<const Part*>& parts)
void select_none(const set<const Part*>& parts)
{
Undo operations;
+ operations.combobreaker=true;
+
for (set<const Part*>::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<const Part*>& parts)
void select_invert(const set<const Part*>& parts)
{
Undo operations;
+ operations.combobreaker=true;
+
for (set<const Part*>::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<const Part*>& parts)
void select_in_loop(const set<const Part*>& parts)
{
- select_none(parts); // this will automatically be grouped into one OperationGroup
+ select_none(parts);
Undo operations;
+ operations.combobreaker=true;
+
for (set<const Part*>::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<const Part*>& parts)
void select_not_in_loop(const set<const Part*>& parts)
{
- select_none(parts); // this will automatically be grouped into one OperationGroup
+ select_none(parts);
Undo operations;
+ operations.combobreaker=true;
+
for (set<const Part*>::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<const MusECore::Part*> all_parts=get_all_parts();
+
+ Undo operations;
+ operations.combobreaker=true;
for (set<const MusECore::Part*>::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<const Track*> 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<UndoOp> {
public:
+ Undo() : std::list<UndoOp>() { combobreaker=false; }
+ Undo(const Undo& other) : std::list<UndoOp>(other) { this->combobreaker=other.combobreaker; }
+ Undo& operator=(const Undo& other) { std::list<UndoOp>::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;