diff options
Diffstat (limited to 'muse2')
30 files changed, 531 insertions, 2232 deletions
diff --git a/muse2/ChangeLog b/muse2/ChangeLog index f7b15ef7..79452eb9 100644 --- a/muse2/ChangeLog +++ b/muse2/ChangeLog @@ -1,7 +1,9 @@ +06.06.2011: + - removed (unused) support for disabling the keymap (flo93) 04.06.2011: - fixed regression with switching ctrl/shift when manipulating items in canvas. drag+shift limits movement, drag+ctrl copies (rj) - + - changed behaviour of middle click in all canvases to "delete" (flo93) 02.06.2011: - the score editor now allows batch-movements, that is, you can transpose or move the whole selection and not diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp index 89947102..9e2f6c9a 100644 --- a/muse2/muse/app.cpp +++ b/muse2/muse/app.cpp @@ -2971,14 +2971,13 @@ void MusE::cmd(int cmd) arranger->cmd(Arranger::CMD_INSERT_EMPTYMEAS); break; case CMD_DELETE: - song->startUndo(); - if (song->msgRemoveParts()) { - song->endUndo(SC_PART_REMOVED); - break; - } - else - audio->msgRemoveTracks(); - song->endUndo(SC_TRACK_REMOVED); + if (!song->msgRemoveParts()) //automatically does undo if neccessary and returns true then + { + //msgRemoveParts() returned false -> no parts to remove? + song->startUndo(); + audio->msgRemoveTracks(); //TODO FINDME this could still be speeded up! + song->endUndo(SC_TRACK_REMOVED); + } break; case CMD_DELETE_TRACK: song->startUndo(); diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp index 8c7c89ad..e17d08e1 100644 --- a/muse2/muse/arranger/pcanvas.cpp +++ b/muse2/muse/arranger/pcanvas.cpp @@ -21,7 +21,6 @@ #include <QPainter> #include <QUrl> #include <QPoint> -//#include <QLinearGradient> #include "fastlog.h" #include "widgets/tools.h" @@ -44,55 +43,6 @@ #include "midictrl.h" #include "utils.h" -// Moved into global config by Tim. -/* -const char* partColorNames[] = { - "Default", - "Refrain", - "Bridge", - "Intro", - "Coda", - "Chorus", - "Solo", - "Brass", - "Percussion", - "Drums", - "Guitar", - "Bass", - "Flute", - "Strings", - "Keyboard", - "Piano", - "Saxophon", - }; -*/ - -/* -//--------------------------------------------------------- -// ColorListItem -//--------------------------------------------------------- - -class ColorListItem { //: public QCustomMenuItem { ddskrjo - QColor color; - int h; - int fontheight; - QString label; - virtual QSize sizeHint() { return QSize(80, h); } - virtual void paint(QPainter* p, const QColorGroup&, bool act, bool enabled, int x, int y, int w, int h) - { - p->fillRect(x+5, y+2, h-4, h-4, QBrush(color)); - p->drawText(x+5 + h - 4 + 3, y+(fontheight * 3) / 4, label); - } - - public: - ColorListItem(const QColor& c, int _h, int _fh, const char* txt) - : color(c), h(_h), fontheight(_fh), label(txt) { - } - QString text() const { return QString("PartColor"); } - }; -*/ -// ORCAN : colorRect does the same job as the above class. -// Shall we get rid of the class? //--------------------------------------------------------- // colorRect @@ -119,7 +69,6 @@ NPart::NPart(Part* e) : CItem(Event(), e) { int th = track()->height(); int y = track()->y(); - //printf("NPart::NPart track name:%s, y:%d h:%d\n", track()->name().toLatin1().constData(), y, th); ///setPos(QPoint(e->tick(), y + 1)); setPos(QPoint(e->tick(), y)); @@ -214,9 +163,7 @@ void PartCanvas::returnPressed() newPart->setName(lineEditor->text()); // Indicate do undo, and do port controller values but not clone parts. - //audio->msgChangePart(oldPart, newPart); audio->msgChangePart(oldPart, newPart, true, true, false); - //printf("PartCanvas::returnPressed after msgChangePart oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oldPart->events()->refCount(), oldPart->events()->arefCount(), newPart->events()->refCount(), newPart->events()->arefCount()); editMode = false; } @@ -299,21 +246,12 @@ void PartCanvas::viewMouseDoubleClickEvent(QMouseEvent* event) } //--------------------------------------------------------- -// startUndo -//--------------------------------------------------------- - -void PartCanvas::startUndo(DragType) - { - song->startUndo(); - } - -//--------------------------------------------------------- -// endUndo +// update //--------------------------------------------------------- -void PartCanvas::endUndo(DragType t, int flags) +void PartCanvas::updateSong(DragType t, int flags) { - song->endUndo(flags | ((t == MOVE_COPY || t == MOVE_CLONE) + song->update(flags | ((t == MOVE_COPY || t == MOVE_CLONE) ? SC_PART_INSERTED : SC_PART_MODIFIED)); } @@ -321,103 +259,10 @@ void PartCanvas::endUndo(DragType t, int flags) // moveCanvasItems //--------------------------------------------------------- -void PartCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtype, int*) +void PartCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtype) { - /* - if(editor->parts()->empty()) - return; - - //struct p2c - //{ - // Part* newp; - // int xdiff; - //} + Undo operations; - //std::set<Part*> parts2change; - //typedef std::set<Part*>::iterator iptc; - std::map<Part*, Part*> parts2change; - typedef std::map<Part*, Part*>::iterator iP2C; - - int modified = 0; - for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) - { - Part* part = ip->second; - if(!part) - continue; - - int npartoffset = 0; - for(iCItem ici = items.begin(); ici != items.end(); ++ici) - { - CItem* ci = ici->second; - //Part* pt = ci->part(); - //if(!pt) - if(ci->part() != part) - continue; - - int x = ci->pos().x() + dx; - int y = pitch2y(y2pitch(ci->pos().y()) + dp); - QPoint newpos = raster(QPoint(x, y)); - - // Test moving the item... - - //int offset = testMoveItem(ci, newpos, dragtype); - NEvent* nevent = (NEvent*) ci; - Event event = nevent->event(); - //int npitch = y2pitch(newpos.y()); - x = newpos.x(); - if (x < 0) - x = 0; - - int ntick = editor->rasterVal(x) - part->tick(); - if (ntick < 0) - ntick = 0; - int diff = ntick + event.lenTick() - part->lenTick(); - - // If moving the item would require a new part size... - if(diff > npartoffset) - npartoffset = diff; - } - - if(npartoffset > 0) - { - // Create new part... - // if there are several events that are moved outside the part, it will be recreated for each - // so the part _in_ the event will not be valid, ask the authority. - Part* newPart = part->clone(); - //Part* newPart = Canvas::part()->clone(); - - newPart->setLenTick(newPart->lenTick() + npartoffset); - audio->msgChangePart(part, newPart,false); - - modified = SC_PART_MODIFIED; - - // BUG FIX: #1650953 - // Added by T356. - // Fixes posted "select and drag past end of part - crashing" bug - for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) - { - if(ip->second == part) - { - editor->parts()->erase(ip); - break; - } - } - - editor->parts()->add(newPart); - if(parts2change.find(part) == parts2change.end()) - parts2change.insert(std::pair<Part*, Part*> (part, newPart)); - -// part = newPart; // reassign -// item->setPart(part); -// item->setEvent(newEvent); -// curPart = part; -// curPartId = curPart->sn(); - - } - } -*/ - -// int modified = 0; for(iCItem ici = items.begin(); ici != items.end(); ++ici) { CItem* ci = ici->second; @@ -435,18 +280,21 @@ void PartCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp QPoint newpos = raster(QPoint(nx, ny)); selectItem(ci, true); - if(moveItem(ci, newpos, dtype)) - ci->move(newpos); + UndoOp operation=moveItem(ci, newpos, dtype); + if (operation.type != UndoOp::DoNothing) + { + ci->move(newpos); + operations.push_back(operation); + } + if(moving.size() == 1) { itemReleased(curItem, newpos); } if(dtype == MOVE_COPY || dtype == MOVE_CLONE) selectItem(ci, false); - } - + } - //if(pflags) - // *pflags = modified; + song->applyOperationGroup(operations); } //--------------------------------------------------------- @@ -455,9 +303,9 @@ void PartCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp //--------------------------------------------------------- // Changed by T356. -//bool PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragType t, int*) -bool PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragType t) +UndoOp PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragType t) { + UndoOp result; NPart* npart = (NPart*) item; Part* spart = npart->part(); Track* track = npart->track(); @@ -465,7 +313,7 @@ bool PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragType t) unsigned ntrack = y2pitch(item->mp().y()); Track::TrackType type = track->type(); if (tracks->index(track) == ntrack && (dtick == spart->tick())) { - return false; + return UndoOp(UndoOp::DoNothing); } if (ntrack >= tracks->size()) { ntrack = tracks->size(); @@ -483,12 +331,10 @@ bool PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragType t) if (dtrack->type() != type) { QMessageBox::critical(this, QString("MusE"), tr("Cannot copy/move/clone to different Track-Type")); - return false; + return UndoOp(UndoOp::DoNothing); } Part* dpart; - //bool clone = (t == MOVE_CLONE) || (spart->events()->arefCount() > 1); - //bool clone = (t == MOVE_CLONE); bool clone = (t == MOVE_CLONE || (t == MOVE_COPY && spart->events()->arefCount() > 1)); if(t == MOVE_MOVE) @@ -503,14 +349,13 @@ bool PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragType t) // This increments aref count if cloned, and chains clones. // It also gives the new part a new serial number. dpart = dtrack->newPart(spart, clone); + dpart->events()->incARef(-1); // the later song->applyOperationGroup() will increment it + // so we must decrement it first :/ dpart->setTick(dtick); - //printf("PartCanvas::moveItem before add/changePart clone:%d spart:%p events:%p refs:%d Arefs:%d sn:%d dpart:%p events:%p refs:%d Arefs:%d sn:%d\n", clone, spart, spart->events(), spart->events()->refCount(), spart->events()->arefCount(), spart->sn(), dpart, dpart->events(), dpart->events()->refCount(), dpart->events()->arefCount(), dpart->sn()); - if(t == MOVE_MOVE) item->setPart(dpart); - //if (!clone) { if (t == MOVE_COPY && !clone) { // // Copy Events @@ -524,35 +369,24 @@ bool PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragType t) } } if (t == MOVE_COPY || t == MOVE_CLONE) { - // These will not increment ref count, and will not chain clones... - if (dtrack->type() == Track::WAVE) - audio->msgAddPart((WavePart*)dpart,false); - else - audio->msgAddPart(dpart,false); + // These will not increment ref count, and will not chain clones... + // TODO: is this still correct (by flo93)? + result=UndoOp(UndoOp::AddPart,dpart); } else if (t == MOVE_MOVE) { dpart->setSelected(spart->selected()); // These will increment ref count if not a clone, and will chain clones... - - if (dtrack->type() == Track::WAVE) { - // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgChangePart((WavePart*)spart, (WavePart*)dpart,false); - audio->msgChangePart((WavePart*)spart, (WavePart*)dpart, false, false, false); - } - else { - // Indicate no undo, and do port controller values but not clone parts. - //audio->msgChangePart(spart, dpart, false); - audio->msgChangePart(spart, dpart, false, true, false); - } + // TODO: is this still correct (by flo93)? + result=UndoOp(UndoOp::ModifyPart,spart, dpart, true, false); + spart->setSelected(false); - } - //printf("PartCanvas::moveItem after add/changePart spart:%p events:%p refs:%d Arefs:%d dpart:%p events:%p refs:%d Arefs:%d\n", spart, spart->events(), spart->events()->refCount(), spart->events()->arefCount(), dpart, dpart->events(), dpart->events()->refCount(), dpart->events()->arefCount()); + // else // will never happen -> result will always be defined if (song->len() < (dpart->lenTick() + dpart->tick())) song->setLen(dpart->lenTick() + dpart->tick()); - //endUndo(t); - return true; + + return result; } //--------------------------------------------------------- @@ -688,7 +522,7 @@ void PartCanvas::newItem(CItem* i, bool noSnap) len = AL::sigmap.rasterStep(p->tick(), *_raster); p->setLenTick(len); p->setSelected(true); - audio->msgAddPart(p); + audio->msgAddPart(p, true); //indicate undo } //--------------------------------------------------------- @@ -698,7 +532,7 @@ void PartCanvas::newItem(CItem* i, bool noSnap) bool PartCanvas::deleteItem(CItem* i) { Part* p = ((NPart*)(i))->part(); - audio->msgRemovePart(p); //Invokes songChanged which calls partsChanged which makes it difficult to delete them there + audio->msgRemovePart(p, true); //Invokes songChanged which calls partsChanged which makes it difficult to delete them there return true; } @@ -764,11 +598,7 @@ QMenu* PartCanvas::genItemPopup(CItem* item) QMenu* colorPopup = partPopup->addMenu(tr("color")); // part color selection - //const QFontMetrics& fm = colorPopup->fontMetrics(); - //int h = fm.lineSpacing(); - for (int i = 0; i < NUM_PARTCOLORS; ++i) { - //ColorListItem* item = new ColorListItem(config.partColors[i], h, fontMetrics().height(), partColorNames[i]); //ddskrjo QAction *act_color = colorPopup->addAction(colorRect(config.partColors[i], 80, 80), config.partColorNames[i]); act_color->setData(20+i); } @@ -868,28 +698,13 @@ void PartCanvas::itemPopup(CItem* item, int n, const QPoint& pt) break; case 14: // wave edit - { - // Changed to allow multiple selected parts to be shown. By T356 - // Slightly inefficient to add (above), then clear here. - // Should really only add npart->part() to pl only if NOT here. - // Removed. Added wave editor menu item instead. - //pl->clear(); - //PartList* ptl = npart->track()->parts(); - //for(ciPart pi = ptl->begin(); pi != ptl->end(); pi++) - //{ - // if(pi->second->selected()) - // pl->add(pi->second); - //} emit startEditor(pl, 4); - } return; case 15: // declone { Part* spart = npart->part(); Track* track = npart->track(); Part* dpart = track->newPart(spart, false); - //printf("PartCanvas::itemPopup: #1 spart %s %p next:%s %p prev:%s %p\n", spart->name().toLatin1().constData(), spart, spart->nextClone()->name().toLatin1().constData(), spart->nextClone(), spart->prevClone()->name().toLatin1().constData(), spart->prevClone()); - //printf("PartCanvas::itemPopup: #1 dpart %s %p next:%s %p prev:%s %p\n", dpart->name().toLatin1().constData(), dpart, dpart->nextClone()->name().toLatin1().constData(), dpart->nextClone(), dpart->prevClone()->name().toLatin1().constData(), dpart->prevClone()); EventList* se = spart->events(); EventList* de = dpart->events(); @@ -898,27 +713,20 @@ void PartCanvas::itemPopup(CItem* item, int n, const QPoint& pt) Event ev = oldEvent.clone(); de->add(ev); } - song->startUndo(); - // Indicate no undo, and do port controller values but not clone parts. - //audio->msgChangePart(spart, dpart, false); - audio->msgChangePart(spart, dpart, false, true, false); - //printf("PartCanvas::itemPopup: #2 spart %s %p next:%s %p prev:%s %p\n", spart->name().toLatin1().constData(), spart, spart->nextClone()->name().toLatin1().constData(), spart->nextClone(), spart->prevClone()->name().toLatin1().constData(), spart->prevClone()); - //printf("PartCanvas::itemPopup: #2 dpart %s %p next:%s %p prev:%s %p\n", dpart->name().toLatin1().constData(), dpart, dpart->nextClone()->name().toLatin1().constData(), dpart->nextClone(), dpart->prevClone()->name().toLatin1().constData(), dpart->prevClone()); - - song->endUndo(SC_PART_MODIFIED); + // Indicate undo, and do port controller values but not clone parts. + // changed by flo93: removed start and endUndo, instead changed first bool to true + audio->msgChangePart(spart, dpart, true, true, false); break; // Has to be break here, right? } case 16: // Export to file { const Part* part = item->part(); bool popenFlag = false; - //QString fn = getSaveFileName(QString(""), part_file_pattern, this, tr("MusE: save part")); QString fn = getSaveFileName(QString(""), part_file_save_pattern, this, tr("MusE: save part")); if (!fn.isEmpty()) { FILE* fp = fileOpen(this, fn, ".mpt", "w", popenFlag, false, false); if (fp) { Xml tmpXml = Xml(fp); - //part->write(0, tmpXml); // Write the part. Indicate that it's a copy operation - to add special markers, // and force full wave paths. part->write(0, tmpXml, true, true); @@ -939,7 +747,6 @@ void PartCanvas::itemPopup(CItem* item, int n, const QPoint& pt) SndFileR f = event.sndFile(); if (f.isNull()) continue; - //str.append("\n" + f.path()); str.append(QString("\n@") + QString().setNum(event.tick()) + QString(" len:") + QString().setNum(event.lenTick()) + QString(" ") + f.path()); } @@ -958,14 +765,11 @@ void PartCanvas::itemPopup(CItem* item, int n, const QPoint& pt) { for(int i = 0; i < j; ++i) { - //printf("PartCanvas::itemPopup i:%d %s %p events %p refs:%d arefs:%d\n", i, p->name().toLatin1().constData(), p, part->cevents(), part->cevents()->refCount(), j); - p->setSelected(true); p = p->nextClone(); if(p == part) break; } - //song->update(); song->update(SC_SELECTION); } @@ -1124,14 +928,10 @@ void PartCanvas::keyPress(QKeyEvent* event) key += Qt::CTRL; if (key == shortcuts[SHRT_DELETE].key) { - if (getCurrentDrag()) { - //printf("dragging!!\n"); + if (getCurrentDrag()) return; - } - song->startUndo(); song->msgRemoveParts(); - song->endUndo(SC_PART_REMOVED); return; } else if (key == shortcuts[SHRT_POS_DEC].key) { @@ -1493,13 +1293,6 @@ void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect) QRect r = item->bbox(); - //printf("PartCanvas::drawItem %s evRefs:%d pTick:%d pLen:%d\nbb.x:%d bb.y:%d bb.w:%d bb.h:%d\n" - // "rect.x:%d rect.y:%d rect.w:%d rect.h:%d\nr.x:%d r.y:%d r.w:%d r.h:%d\n", - // part->name().toLatin1().constData(), part->events()->arefCount(), pTick, part->lenTick(), - // bb.x(), bb.y(), bb.width(), bb.height(), - // rect.x(), rect.y(), rect.width(), rect.height(), - // r.x(), r.y(), r.width(), r.height()); - int i = part->colorIndex(); p.setPen(Qt::black); if (part->mute()) { @@ -1513,7 +1306,6 @@ void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect) // NOTE: For one-pixel border use first line For two-pixel border use second. p.drawRect(QRect(r.x(), r.y()-1, r.width(), r.height())); - //p.drawRect(r); return; } @@ -1528,11 +1320,7 @@ void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect) // NOTE: For one-pixel border use first line. For two-pixel border use second. p.drawRect(QRect(r.x(), r.y()-1, r.width(), r.height())); - //p.drawRect(r); - } - //else if (part->mute()) - // return; else if (part->selected()) { bool clone = part->events()->arefCount() > 1; @@ -1641,8 +1429,6 @@ void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect) void PartCanvas::drawMoving(QPainter& p, const CItem* item, const QRect&) { - //if(!item->isMoving()) - // return; p.setPen( Qt::black); //p.setBrush( Qt::NoBrush); @@ -1669,7 +1455,6 @@ void PartCanvas::drawMoving(QPainter& p, const CItem* item, const QRect&) void PartCanvas::drawMidiPart(QPainter& p, const QRect&, EventList* events, MidiTrack *mt, MidiPart *pt, const QRect& r, int pTick, int from, int to) { - //printf("x=%d y=%d h=%d w=%d\n",r.x(),r.y(),r.height(),r.width()); int color_brightness; if(pt) @@ -1894,9 +1679,6 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, EventList* events, Midi void PartCanvas::drawWavePart(QPainter& p, const QRect& bb, WavePart* wp, const QRect& _pr) { - //printf("PartCanvas::drawWavePart bb.x:%d bb.y:%d bb.w:%d bb.h:%d pr.x:%d pr.y:%d pr.w:%d pr.h:%d\n", - // bb.x(), bb.y(), bb.width(), bb.height(), _pr.x(), _pr.y(), _pr.width(), _pr.height()); - QRect rr = p.worldMatrix().mapRect(bb); QRect pr = p.worldMatrix().mapRect(_pr); @@ -2020,26 +1802,23 @@ void PartCanvas::cmd(int cmd) } switch (cmd) { case CMD_CUT_PART: + { copy(&pl); - song->startUndo(); - bool loop; - do - { - loop = false; - for (iCItem i = items.begin(); i != items.end(); ++i) { - if (!i->second->isSelected()) - continue; - NPart* p = (NPart*)(i->second); - Part* part = p->part(); - audio->msgRemovePart(part); - - loop = true; - break; - } - } while (loop); - song->endUndo(SC_PART_REMOVED); + Undo operations; + + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (i->second->isSelected()) { + NPart* p = (NPart*)(i->second); + Part* part = p->part(); + operations.push_back(UndoOp(UndoOp::DeletePart, part)); + } + } + + song->applyOperationGroup(operations); + break; + } case CMD_COPY_PART: copy(&pl); break; @@ -2059,11 +1838,10 @@ void PartCanvas::cmd(int cmd) paste(false, false, true); break; case CMD_INSERT_EMPTYMEAS: - song->startUndo(); int startPos=song->vcpos(); int oneMeas=AL::sigmap.ticksMeasure(startPos); - movePartsTotheRight(startPos,oneMeas); - song->endUndo(SC_PART_INSERTED); + Undo temp=movePartsTotheRight(startPos,oneMeas); + song->applyOperationGroup(temp); break; } } @@ -2075,11 +1853,8 @@ void PartCanvas::cmd(int cmd) void PartCanvas::copy(PartList* pl) { - //printf("void PartCanvas::copy(PartList* pl)\n"); if (pl->empty()) return; - // Changed by T356. Support mixed .mpt files. - //bool isWave = pl->begin()->second->track()->type() == Track::WAVE; bool wave = false; bool midi = false; for(ciPart p = pl->begin(); p != pl->end(); ++p) @@ -2109,13 +1884,11 @@ void PartCanvas::copy(PartList* pl) // Clear the copy clone list. cloneList.clear(); - //copyCloneList.clear(); int level = 0; int tick = 0; for (ciPart p = pl->begin(); p != pl->end(); ++p) { // Indicate this is a copy operation. Also force full wave paths. - //p->second->write(level, xml); p->second->write(level, xml, true, true); int endTick = p->second->endTick(); @@ -2165,21 +1938,20 @@ void PartCanvas::copy(PartList* pl) // pasteAt //--------------------------------------------------------- -int PartCanvas::pasteAt(const QString& pt, Track* track, unsigned int pos, bool clone, bool toTrack) +Undo PartCanvas::pasteAt(const QString& pt, Track* track, unsigned int pos, bool clone, bool toTrack, int* finalPosPtr) { - //printf("int PartCanvas::pasteAt(const QString& pt, Track* track, int pos)\n"); + Undo operations; + QByteArray ba = pt.toLatin1(); const char* ptxt = ba.constData(); Xml xml(ptxt); bool firstPart=true; int posOffset=0; - //int finalPos=0; unsigned int finalPos = pos; int notDone = 0; int done = 0; bool end = false; - //song->startUndo(); for (;;) { Xml::Token token = xml.parse(); const QString& tag = xml.s1(); @@ -2189,29 +1961,11 @@ int PartCanvas::pasteAt(const QString& pt, Track* track, unsigned int pos, bool end = true; break; case Xml::TagStart: - if (tag == "part") { - /* - Part* p = 0; - if(clone) - { - if(!(p = readClone(xml, track, toTrack))) - break; - } - else - { - if (track->type() == Track::MIDI || track->type() == Track::DRUM) - p = new MidiPart((MidiTrack*)track); - else if (track->type() == Track::WAVE) - p = new WavePart((WaveTrack*)track); - else - break; - p->read(xml, 0, toTrack); - } - */ - + if (tag == "part") { // Read the part. Part* p = 0; p = readXmlPart(xml, track, clone, toTrack); + // If it could not be created... if(!p) { @@ -2219,6 +1973,9 @@ int PartCanvas::pasteAt(const QString& pt, Track* track, unsigned int pos, bool ++notDone; break; } + + p->events()->incARef(-1); // the later song->applyOperationGroup() will increment it + // so we must decrement it first :/ // Increment the number of parts done. ++done; @@ -2231,8 +1988,7 @@ int PartCanvas::pasteAt(const QString& pt, Track* track, unsigned int pos, bool if (p->tick()+p->lenTick()>finalPos) { finalPos=p->tick()+p->lenTick(); } - //pos += p->lenTick(); - audio->msgAddPart(p,false); + operations.push_back(UndoOp(UndoOp::AddPart,p)); } else xml.unknown("PartCanvas::pasteAt"); @@ -2247,8 +2003,6 @@ int PartCanvas::pasteAt(const QString& pt, Track* track, unsigned int pos, bool break; } - //song->endUndo(SC_PART_INSERTED); - //return pos; if(notDone) { @@ -2259,406 +2013,16 @@ int PartCanvas::pasteAt(const QString& pt, Track* track, unsigned int pos, bool tr(" could not be pasted.\nLikely the selected track is the wrong type.")); } - return finalPos; + if (finalPosPtr) *finalPosPtr=finalPos; + return operations; } -/* -//--------------------------------------------------------- -// PartCanvas::readPart -//--------------------------------------------------------- - -Part* PartCanvas::readPart(Xml& xml, Track* track, bool doClone, bool toTrack) - { - int id = -1; - Part* npart = 0; - uuid_t uuid; - uuid_clear(uuid); - bool uuidvalid = false; - bool clone = true; - - for (;;) { - Xml::Token token = xml.parse(); - const QString& tag = xml.s1(); - switch (token) { - case Xml::Error: - case Xml::End: - return npart; - case Xml::TagStart: - // If the part has not been created yet... - if(!npart) - { - // Attribute section did not create a clone from any matching part. Create a non-clone part now. - if(!track) - { - xml.skip("part"); - return 0; - } - if (track->type() == Track::MIDI || track->type() == Track::DRUM) - npart = new MidiPart((MidiTrack*)track); - else if (track->type() == Track::WAVE) - npart = new WavePart((WaveTrack*)track); - else - { - xml.skip("part"); - return 0; - } - - // Signify a new non-clone part was created. - // Even if the original part was itself a clone, clear this because the - // attribute section did not create a clone from any matching part. - clone = false; - - // If an id or uuid was found, add the part to the clone list - // so that subsequent parts can look it up and clone from it... - if(id != -1) - { - ClonePart ncp(npart, id); - cloneList.push_back(ncp); - } - else - if(uuidvalid) - { - ClonePart ncp(npart); - // New ClonePart creates its own uuid, but we need to replace it. - uuid_copy(ncp.uuid, uuid); - cloneList.push_back(ncp); - } - } - - if (tag == "name") - npart->setName(xml.parse1()); - else if (tag == "poslen") { - ((PosLen*)npart)->read(xml, "poslen"); - } - else if (tag == "pos") { - Pos pos; - pos.read(xml, "pos"); // obsolete - npart->setTick(pos.tick()); - } - else if (tag == "len") { - Pos len; - len.read(xml, "len"); // obsolete - npart->setLenTick(len.tick()); - } - else if (tag == "selected") - npart->setSelected(xml.parseInt()); - else if (tag == "color") - npart->setColorIndex(xml.parseInt()); - else if (tag == "mute") - npart->setMute(xml.parseInt()); - else if (tag == "event") - { - // If a new non-clone part was created, accept the events... - if(!clone) - { - EventType type = Wave; - if(track->isMidiTrack()) - type = Note; - Event e(type); - e.read(xml); - // stored tickpos for event has absolute value. However internally - // tickpos is relative to start of part, we substract tick(). - // TODO: better handling for wave event - e.move( -npart->tick() ); - int tick = e.tick(); - - // Do not discard events belonging to clone parts, - // at least not yet. A later clone might have a longer, - // fully accommodating part length! - //if ((tick < 0) || (tick >= (int) lenTick())) { - //if ((tick < 0) || ( id == -1 && !clone && (tick >= (int)lenTick()) )) - // No way to tell at the moment whether there will be clones referencing this... - // No choice but to accept all events past 0. - if(tick < 0) - { - //printf("readClone: warning: event not in part: %d - %d -%d, discarded\n", - printf("readClone: warning: event at tick:%d not in part:%s, discarded\n", - tick, npart->name().toLatin1().constData()); - } - else - { - npart->events()->add(e); - } - } - else - // ...Otherwise a clone was created, so we don't need the events. - xml.skip(tag); - } - else - xml.unknown("PartCanvas::readClone"); - break; - case Xml::Attribut: - if (tag == "cloneId") - { - id = xml.s2().toInt(); - if(id != -1) - { - for(iClone i = cloneList.begin(); i != cloneList.end(); ++i) - { - // Is a matching part found in the clone list? - if(i->id == id) - { - // If it's a regular paste (not paste clone), and the original part is - // not a clone, defer so that a new copy is created in TagStart above. - if(!doClone && i->cp->cevents()->arefCount() <= 1) - break; - - // This makes a clone, chains the part, and increases ref counts. - npart = track->newPart((Part*)i->cp, true); - break; - } - } - } - } - else if (tag == "uuid") - { - uuid_parse(xml.s2().toLatin1().constData(), uuid); - if(!uuid_is_null(uuid)) - { - uuidvalid = true; - for(iClone i = cloneList.begin(); i != cloneList.end(); ++i) - { - // Is a matching part found in the clone list? - if(uuid_compare(uuid, i->uuid) == 0) - { - Track* cpt = i->cp->track(); - // If we want to paste to the given track... - if(toTrack) - { - // If the given track type is not the same as the part's - // original track type, we can't continue. Just return. - if(!track || cpt->type() != track->type()) - { - xml.skip("part"); - return 0; - } - } - else - // ...else we want to paste to the part's original track. - { - // Make sure the track exists (has not been deleted). - if((cpt->isMidiTrack() && song->midis()->find(cpt) != song->midis()->end()) || - (cpt->type() == Track::WAVE && song->waves()->find(cpt) != song->waves()->end())) - track = cpt; - else - // Track was not found. Try pasting to the given track, as above... - { - if(!track || cpt->type() != track->type()) - { - // No luck. Just return. - xml.skip("part"); - return 0; - } - } - } - - // If it's a regular paste (not paste clone), and the original part is - // not a clone, defer so that a new copy is created in TagStart above. - if(!doClone && i->cp->cevents()->arefCount() <= 1) - break; - - // This makes a clone, chains the part, and increases ref counts. - npart = track->newPart((Part*)i->cp, true); - break; - } - } - } - } - //else if(tag == "isclone") // Ignore - // clone = xml.s2().toInt(); - break; - case Xml::TagEnd: - if (tag == "part") - return npart; - default: - break; - } - } - return npart; -} -*/ - -/* -//--------------------------------------------------------- -// PartCanvas::readClone -//--------------------------------------------------------- - -Part* PartCanvas::readClone(Xml& xml, Track* track, bool toTrack) - { - int id = -1; - Part* npart = 0; - uuid_t uuid; - uuid_clear(uuid); - bool uuidvalid = false; - bool clone = true; - - for (;;) { - Xml::Token token = xml.parse(); - const QString& tag = xml.s1(); - switch (token) { - case Xml::Error: - case Xml::End: - return npart; - case Xml::TagStart: - // If the part has not been created yet... - if(!npart) - { - // Attribute section did not create a clone from any matching part. Create a non-clone part now. - if (track->type() == Track::MIDI || track->type() == Track::DRUM) - npart = new MidiPart((MidiTrack*)track); - else if (track->type() == Track::WAVE) - npart = new WavePart((WaveTrack*)track); - else - return 0; - - // Signify a new non-clone part was created. - // Even if the original part was itself a clone, clear this because the - // attribute section did not create a clone from any matching part. - clone = false; - - // If an id or uuid was found, add the part to the clone list - // so that subsequent parts can look it up and clone from it... - if(id != -1) - { - ClonePart ncp(npart, id); - cloneList.push_back(ncp); - } - else - if(uuidvalid) - { - ClonePart ncp(npart); - // New ClonePart creates its own uuid, but we need to replace it. - uuid_copy(ncp.uuid, uuid); - cloneList.push_back(ncp); - } - } - - if (tag == "name") - npart->setName(xml.parse1()); - else if (tag == "poslen") { - ((PosLen*)npart)->read(xml, "poslen"); - } - else if (tag == "pos") { - Pos pos; - pos.read(xml, "pos"); // obsolete - npart->setTick(pos.tick()); - } - else if (tag == "len") { - Pos len; - len.read(xml, "len"); // obsolete - npart->setLenTick(len.tick()); - } - else if (tag == "selected") - npart->setSelected(xml.parseInt()); - else if (tag == "color") - npart->setColorIndex(xml.parseInt()); - else if (tag == "mute") - npart->setMute(xml.parseInt()); - else if (tag == "event") - { - // If a new non-clone part was created, accept the events... - if(!clone) - { - EventType type = Wave; - if(track->isMidiTrack()) - type = Note; - Event e(type); - e.read(xml); - // stored tickpos for event has absolute value. However internally - // tickpos is relative to start of part, we substract tick(). - // TODO: better handling for wave event - e.move( -npart->tick() ); - int tick = e.tick(); - - // Do not discard events belonging to clone parts, - // at least not yet. A later clone might have a longer, - // fully accommodating part length! - //if ((tick < 0) || (tick >= (int) lenTick())) { - //if ((tick < 0) || ( id == -1 && !clone && (tick >= (int)lenTick()) )) - // No way to tell at the moment whether there will be clones referencing this... - // No choice but to accept all events past 0. - if(tick < 0) - { - //printf("readClone: warning: event not in part: %d - %d -%d, discarded\n", - printf("readClone: warning: event at tick:%d not in part:%s, discarded\n", - tick, npart->name().toLatin1().constData()); - } - else - { - npart->events()->add(e); - } - } - else - // ...Otherwise a clone was created, so we don't need the events. - xml.skip(tag); - } - else - xml.unknown("PartCanvas::readClone"); - break; - case Xml::Attribut: - if (tag == "cloneId") - { - id = xml.s2().toInt(); - if(id != -1) - { - for(iClone i = cloneList.begin(); i != cloneList.end(); ++i) - { - // Is a matching part found in the clone list? - if(i->id == id) - { - // This makes a clone, chains the part, and increases ref counts. - npart = track->newPart((Part*)i->cp, true); - break; - } - } - } - } - else if (tag == "uuid") - { - uuid_parse(xml.s2().toLatin1().constData(), uuid); - if(!uuid_is_null(uuid)) - { - uuidvalid = true; - for(iClone i = cloneList.begin(); i != cloneList.end(); ++i) - { - // Is a matching part found in the clone list? - if(uuid_compare(uuid, i->uuid) == 0) - { - // If we want to paste to the part's original track... - if(!toTrack) - { - // Make sure the track exists (has not been deleted). - if((i->cp->track()->isMidiTrack() && song->midis()->find(i->cp->track()) != song->midis()->end()) || - (i->cp->track()->type() == Track::WAVE && song->waves()->find(i->cp->track()) != song->waves()->end())) - track = i->cp->track(); - } - // This makes a clone, chains the part, and increases ref counts. - npart = track->newPart((Part*)i->cp, true); - break; - } - } - } - } - //else if(tag == "isclone") // Ignore - // clone = xml.s2().toInt(); - break; - case Xml::TagEnd: - if (tag == "part") - return npart; - default: - break; - } - } - return npart; -} -*/ //--------------------------------------------------------- // paste // paste part to current selected track at cpos //--------------------------------------------------------- -//void PartCanvas::paste() void PartCanvas::paste(bool clone, bool toTrack, bool doInsert) { Track* track = 0; @@ -2740,44 +2104,39 @@ void PartCanvas::paste(bool clone, bool toTrack, bool doInsert) return; } - int endPos=0; - unsigned int startPos=song->vcpos(); if (!txt.isEmpty()) { - song->startUndo(); - endPos=pasteAt(txt, track, startPos, clone, toTrack); + int endPos=0; + unsigned int startPos=song->vcpos(); + Undo operations=pasteAt(txt, track, startPos, clone, toTrack, &endPos); Pos p(endPos, true); song->setPos(0, p); - if (!doInsert) - song->endUndo(SC_PART_INSERTED); + if (doInsert) { + int offset = endPos-startPos; + Undo temp=movePartsTotheRight(startPos, offset); + operations.insert(operations.end(), temp.begin(), temp.end()); + } + song->applyOperationGroup(operations); } - if (doInsert) { - int offset = endPos-startPos; - movePartsTotheRight(startPos, offset); - song->endUndo(SC_PART_INSERTED); - } } //--------------------------------------------------------- // movePartsToTheRight //--------------------------------------------------------- -void PartCanvas::movePartsTotheRight(unsigned int startTicks, int length) +Undo PartCanvas::movePartsTotheRight(unsigned int startTicks, int length) { + Undo operations; + // all parts that start after the pasted parts will be moved the entire length of the pasted parts for (iCItem i = items.begin(); i != items.end(); ++i) { if (!i->second->isSelected()) { Part* part = i->second->part(); if (part->tick() >= startTicks) { - //void Audio::msgChangePart(Part* oldPart, Part* newPart, bool doUndoFlag, bool doCtrls, bool doClones) Part *newPart = part->clone(); newPart->setTick(newPart->tick()+length); - if (part->track()->type() == Track::WAVE) { - audio->msgChangePart((WavePart*)part,(WavePart*)newPart,false,false,false); - } else { - audio->msgChangePart(part,newPart,false,false,false); - } - + + operations.push_back(UndoOp(UndoOp::ModifyPart,part,newPart,false,false)); } } } @@ -2790,9 +2149,11 @@ void PartCanvas::movePartsTotheRight(unsigned int startTicks, int length) Marker *oldMarker = new Marker(); *oldMarker = *m; m->setTick(m->tick()+length); - song->undoOp(UndoOp::ModifyMarker,oldMarker, m); + operations.push_back(UndoOp(UndoOp::ModifyMarker,oldMarker, m)); } } + + return operations; } //--------------------------------------------------------- // startDrag @@ -2800,7 +2161,6 @@ void PartCanvas::movePartsTotheRight(unsigned int startTicks, int length) void PartCanvas::startDrag(CItem* item, DragType t) { - //printf("PartCanvas::startDrag(CItem* item, DragType t)\n"); NPart* p = (NPart*)(item); Part* part = p->part(); @@ -2861,7 +2221,6 @@ void PartCanvas::startDrag(CItem* item, DragType t) void PartCanvas::dragEnterEvent(QDragEnterEvent* event) { - ///event->accept(Q3TextDrag::canDecode(event)); event->acceptProposedAction(); // TODO CHECK Tim. } @@ -2869,22 +2228,6 @@ void PartCanvas::dragEnterEvent(QDragEnterEvent* event) // dragvent //--------------------------------------------------------- -void PartCanvas::dragMoveEvent(QDragMoveEvent*) - { -// printf("drag move %x\n", this); - //event->acceptProposedAction(); - } - -//--------------------------------------------------------- -// dragLeaveEvent -//--------------------------------------------------------- - -void PartCanvas::dragLeaveEvent(QDragLeaveEvent*) - { -// printf("drag leave\n"); - //event->acceptProposedAction(); - } - //--------------------------------------------------------- // dropEvent //--------------------------------------------------------- @@ -2904,7 +2247,6 @@ void PartCanvas::viewDropEvent(QDropEvent* event) if(event->mimeData()->hasFormat("text/partlist")) type = 1; else - //if(event->mimeData()->hasFormat("text/uri-list")) if(event->mimeData()->hasUrls()) type = 2; else @@ -2934,11 +2276,11 @@ void PartCanvas::viewDropEvent(QDropEvent* event) Track* track = 0; if (trackNo < tracks->size()) track = tracks->index(trackNo); - if (track) { - song->startUndo(); - pasteAt(text, track, x); - song->endUndo(SC_PART_INSERTED); - } + if (track) + { + Undo temp=pasteAt(text, track, x); + song->applyOperationGroup(temp); + } } else if (type == 2) { @@ -2946,7 +2288,7 @@ void PartCanvas::viewDropEvent(QDropEvent* event) Track* track = 0; if (trackNo < tracks->size()) track = tracks->index(trackNo); - //printf("trackNo=%d\n, trackNo track=%d\n", trackNo, track); + int x = AL::sigmap.raster(event->pos().x(), *_raster); if (x < 0) x = 0; @@ -3024,7 +2366,6 @@ void PartCanvas::drawCanvas(QPainter& p, const QRect& rect) //-------------------------------- // vertical lines //------------------------------- - //printf("raster=%d\n", *_raster); if (config.canvasShowGrid) { int bar, beat; unsigned tick; @@ -3083,12 +2424,9 @@ void PartCanvas::drawCanvas(QPainter& p, const QRect& rect) th = track->height(); if (!th) continue; - ///if (/*config.canvasShowGrid ||*/ !track->isMidiTrack()) { if (config.canvasShowGrid && (track->isMidiTrack() || track->type() == Track::WAVE)) // Tim. { - //printf("PartCanvas::drawCanvas track name:%s, y:%d h:%d\n", track->name().toLatin1().constData(), yy, th); p.setPen(baseColor.dark(130)); - ///p.drawLine(x, yy, x + w, yy); p.drawLine(x, yy + th, x + w, yy + th); // Tim. p.setPen(baseColor); } @@ -3195,7 +2533,6 @@ void PartCanvas::drawTopItem(QPainter& p, const QRect& rect) MPEventList *el = mt->mpevents(); if (el->size()) { - //printf("num events %d\n", mt->mpevents()->size()); for (iMPEvent i = el->begin(); i != el->end(); ++i) { MidiPlayEvent pe = *i; @@ -3213,7 +2550,6 @@ void PartCanvas::drawTopItem(QPainter& p, const QRect& rect) if (e.pitch() == pe.dataA() && e.dataC() == 1) { e.setLenTick(pe.time() - e.tick()- startPos); e.setC(0); // reset the variable we borrowed for state handling - //printf("editing event tick=%d startPos=%d\n",e.tick(), startPos); continue; } } @@ -3295,7 +2631,6 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t) // prepare prevVal if (cl->valueType() == VAL_LOG ) { // use db scale for volume - //printf("volume cvval=%f\n", cvFirst.val); prevVal = dbToVal(cvFirst.val); // represent volume between 0 and 1 if (prevVal < 0) prevVal = 0.0; } @@ -3334,13 +2669,11 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t) (rr.bottom()-2)-prevVal*height, currentPixel, (rr.bottom()-2)-nextVal*height); - ///(rr.bottom()-2)- (discrete?prevVal:nextVal)*height); // Tim ///if(discrete) /// p.drawLine( currentPixel, (rr.bottom()-2)-prevVal*height, currentPixel, (rr.bottom()-2)-nextVal*height ); // Tim firstRun=false; - //printf("draw line: %d %f %d %f\n",tempomap.frame2tick(lastPos),rr.bottom()-lastVal*height,tempomap.frame2tick(cv.frame),rr.bottom()-curVal*height); prevPosFrame=cv.frame; prevVal=nextVal; if (currentPixel > rr.x()+ rr.width()) @@ -3350,12 +2683,10 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t) p.drawRect(mapx(tempomap.frame2tick(prevPosFrame))-2, (rr.bottom()-2)-prevVal*height-2, 5, 5); p.drawRect(mapx(tempomap.frame2tick(prevPosFrame))-1, (rr.bottom()-1)-prevVal*height-2, 3, 3); } - //printf("outer draw %f\n", cvFirst.val ); p.drawLine(mapx(tempomap.frame2tick(prevPosFrame)), (rr.bottom()-2)-prevVal*height, rr.x()+rr.width(), (rr.bottom()-2)-prevVal*height); - //printf("draw last line: %d %f %d %f\n",tempomap.frame2tick(prevPosFrame),(rr.bottom()-2)-prevVal*height,tempomap.frame2tick(prevPosFrame)+rr.width(),(rr.bottom()-2)-prevVal*height); } } quitDrawing: @@ -3448,7 +2779,6 @@ void PartCanvas::checkAutomation(Track * t, const QPoint &pointer, bool addNewCt continue; // not the right region } - //printf("firstX=%f lastX=%f firstY=%f lastY=%f proportion=%f currX=%d\n", firstX,lastX,firstY,lastY,proportion, currX); // 10 X(15) 20 // proportion = 0.5 @@ -3473,7 +2803,6 @@ void PartCanvas::checkAutomation(Track * t, const QPoint &pointer, bool addNewCt } } - //printf("point at x=%d xdiff=%d y=%d ydiff=%d\n", mapx(tempomap.frame2tick(cv.frame)), x1, mapx(ypixel), y1); oldX = xpixel; oldY = ypixel; @@ -3527,7 +2856,6 @@ void PartCanvas::controllerChanged(Track* /* t */) void PartCanvas::processAutomationMovements(QPoint pos, bool addPoint) { - //printf("processAutomationMovements %d %d %d %d %d %d\n", pos.x(), pos.y(),mapx(pos.x()), mapy(pos.y()), xpos, ypos); if (_tool == AutomationTool) { if (!automation.moveController) { // currently nothing going lets's check for some action. @@ -3606,9 +2934,7 @@ void PartCanvas::processAutomationMovements(QPoint pos, bool addPoint) if (cvval< min) cvval=min; if (cvval>max) cvval=max; automation.currentCtrl->val = cvval; - //printf("calc cvval=%f yfraction=%f ", cvval, yfraction); } - //printf("mouseY=%d\n", mouseY); controllerChanged(automation.currentTrack); } @@ -3623,3 +2949,28 @@ double PartCanvas::valToDb(double inV) { return exp10((inV*70.0-60.0)/20.0); } + +//--------------------------------------------------------- +// endMoveItems +// dir = 0 move in all directions +// 1 move only horizontal +// 2 move only vertical +//--------------------------------------------------------- + +void PartCanvas::endMoveItems(const QPoint& pos, DragType dragtype, int dir) + { + int dp = y2pitch(pos.y()) - y2pitch(start.y()); + int dx = pos.x() - start.x(); + + if (dir == 1) + dp = 0; + else if (dir == 2) + dx = 0; + + moveCanvasItems(moving, dp, dx, dragtype); + + moving.clear(); + updateSelection(); + redraw(); + } + diff --git a/muse2/muse/arranger/pcanvas.h b/muse2/muse/arranger/pcanvas.h index 3145d034..acfe565e 100644 --- a/muse2/muse/arranger/pcanvas.h +++ b/muse2/muse/arranger/pcanvas.h @@ -12,9 +12,7 @@ #include "canvas.h" #include "trackautomationview.h" -class QDragMoveEvent; class QDropEvent; -class QDragLeaveEvent; class QMouseEvent; class QKeyEvent; class QEvent; @@ -84,19 +82,16 @@ class PartCanvas : public Canvas { virtual int y2pitch(int y) const; virtual int pitch2y(int p) const; - virtual void moveCanvasItems(CItemList&, int, int, DragType, int*); - virtual bool moveItem(CItem*, const QPoint&, DragType); virtual CItem* newItem(const QPoint&, int); virtual void resizeItem(CItem*,bool); virtual void newItem(CItem*,bool); virtual bool deleteItem(CItem*); - virtual void startUndo(DragType); - - virtual void endUndo(DragType, int); + virtual void moveCanvasItems(CItemList&, int, int, DragType); + virtual UndoOp moveItem(CItem*, const QPoint&, DragType); + + virtual void updateSong(DragType, int); virtual void startDrag(CItem*, DragType); virtual void dragEnterEvent(QDragEnterEvent*); - virtual void dragMoveEvent(QDragMoveEvent*); - virtual void dragLeaveEvent(QDragLeaveEvent*); virtual void viewDropEvent(QDropEvent*); virtual QMenu* genItemPopup(CItem*); @@ -107,8 +102,8 @@ class PartCanvas : public Canvas { void copy(PartList*); void paste(bool clone = false, bool toTrack = true, bool doInsert=false); - int pasteAt(const QString&, Track*, unsigned int, bool clone = false, bool toTrack = true); - void movePartsTotheRight(unsigned int startTick, int length); + Undo pasteAt(const QString&, Track*, unsigned int, bool clone = false, bool toTrack = true, int* finalPosPtr = NULL); + Undo movePartsTotheRight(unsigned int startTick, int length); //Part* readClone(Xml&, Track*, bool toTrack = true); void drawWavePart(QPainter&, const QRect&, WavePart*, const QRect&); //void drawMidiPart(QPainter&, const QRect& rect, EventList* events, MidiTrack*mt, const QRect& r, int pTick, int from, int to); @@ -127,6 +122,7 @@ class PartCanvas : public Canvas { protected: virtual void drawCanvas(QPainter&, const QRect&); + virtual void endMoveItems(const QPoint&, DragType, int dir); signals: void timeChanged(unsigned); diff --git a/muse2/muse/audio.h b/muse2/muse/audio.h index 940dd2a5..e332f516 100644 --- a/muse2/muse/audio.h +++ b/muse2/muse/audio.h @@ -124,7 +124,6 @@ class Audio { bool idle; // do nothing in idle mode bool _freewheel; bool _bounce; - //bool loopPassed; unsigned _loopFrame; // Startframe of loop if in LOOP mode. Not quite the same as left marker ! int _loopCount; // Number of times we have looped so far @@ -202,13 +201,9 @@ class Audio { void msgMoveTrack(int idx1, int dx2, bool u = true); void msgAddPart(Part*, bool u = true); void msgRemovePart(Part*, bool u = true); - //void msgChangePart(Part* oldPart, Part* newPart, bool u = true); void msgChangePart(Part* oldPart, Part* newPart, bool u = true, bool doCtrls = true, bool doClones = false); - //void msgAddEvent(Event&, Part*, bool u = true); void msgAddEvent(Event&, Part*, bool u = true, bool doCtrls = true, bool doClones = false); - //void msgDeleteEvent(Event&, Part*, bool u = true); void msgDeleteEvent(Event&, Part*, bool u = true, bool doCtrls = true, bool doClones = false); - //void msgChangeEvent(Event&, Event&, Part*, bool u = true); void msgChangeEvent(Event&, Event&, Part*, bool u = true, bool doCtrls = true, bool doClones = false); void msgScanAlsaMidiPorts(); void msgAddTempo(int tick, int tempo, bool doUndoFlag = true); @@ -250,7 +245,6 @@ class Audio { void msgResetMidiDevices(); void msgIdle(bool); void msgBounce(); - //void msgSetPluginCtrlVal(PluginI* /*plugin*/, int /*param*/, double /*val*/); void msgSetPluginCtrlVal(AudioTrack*, int /*param*/, double /*val*/); void msgSwapControllerIDX(AudioTrack*, int, int); void msgClearControllerEvents(AudioTrack*, int); diff --git a/muse2/muse/ctrl/ctrlcanvas.cpp b/muse2/muse/ctrl/ctrlcanvas.cpp index f2f335cf..d1d6b2fa 100644 --- a/muse2/muse/ctrl/ctrlcanvas.cpp +++ b/muse2/muse/ctrl/ctrlcanvas.cpp @@ -545,14 +545,6 @@ void CtrlCanvas::partControllers(const MidiPart* part, int num, int* dnum, int* } *mcvl = tmcvl; - // Removed by T356. - // MidiCtrlValList not found is now an acceptable state (for multiple part editing). - //if (i == cvll->end()) { - // printf("CtrlCanvas::setController(0x%x): not found\n", num); - // for (i = cvll->begin(); i != cvll->end(); ++i) - // printf(" 0x%x\n", i->second->num()); - // return; - // } } } } @@ -566,98 +558,9 @@ void CtrlCanvas::updateItems() selection.clear(); items.clearDelete(); - /* - if(ctrl) - { - for(ciMidiCtrlVal imcv = ctrl->begin(); imcv != ctrl->end(); ++imcv) - { - MidiPart* part = (MidiPart*)imcv->part; - int val = imcv->val; - - bool edpart = false; - if(editor->parts()->index(part) != -1) - edpart = true; - - MidiController* mc; - MidiCtrlValList* mcvl; - partControllers(part, _cnum, 0, 0, &mc, &mcvl); - - Event e(Controller); - - if(_cnum == CTRL_VELOCITY && e.type() == Note) - { - items.add(new CEvent(e, part, e.velo())); - - } - - } - } - */ - - /* - MidiTrackList* mtl = song->midis(); - for(ciMidiTrack imt = mtl->begin(); imt != mtl->end(); ++imt) - { - //MidiTrack* mt = *imt; - PartList* pl = (*imt)->parts(); - for(ciPart p = pl->begin(); p != pl->end(); ++p) - { - MidiPart* part = (MidiPart*)(p->second); - - bool edpart = false; - if(editor->parts()->index(part) != -1) - edpart = true; - - EventList* el = part->events(); - MidiController* mc; - MidiCtrlValList* mcvl; - partControllers(part, _cnum, 0, 0, &mc, &mcvl); - - for(iEvent i = el->begin(); i != el->end(); ++i) - { - Event e = i->second; - if(_cnum == CTRL_VELOCITY && e.type() == Note) - { - if(curDrumInstrument == -1) - { - items.add(new CEvent(e, part, e.velo())); - } - else if (e.dataA() == curDrumInstrument) //same note - items.add(new CEvent(e, part, e.velo())); - } - else if (e.type() == Controller && e.dataA() == _didx) - { - if(mcvl && last.empty()) - { - Event le(Controller); - //le.setType(Controller); - le.setA(_didx); - //le.setB(e.dataB()); - le.setB(CTRL_VAL_UNKNOWN); - //lastce = new CEvent(Event(), part, mcvl->value(part->tick(), part)); - //lastce = new CEvent(le, part, mcvl->value(part->tick(), part)); - lastce = new CEvent(le, part, mcvl->value(part->tick())); - items.add(lastce); - } - if (lastce) - lastce->setEX(e.tick()); - lastce = new CEvent(e, part, e.dataB()); - items.add(lastce); - last = e; - } - } - } - } - */ - - - - if(!editor->parts()->empty()) { - //Event last; - //CEvent* lastce = 0; CEvent *newev = 0; for (iPart p = editor->parts()->begin(); p != editor->parts()->end(); ++p) @@ -790,7 +693,6 @@ void CtrlCanvas::viewMousePressEvent(QMouseEvent* event) } if(do_redraw) redraw(); // Let songChanged handle the redraw upon SC_SELECTION. - //song->update(SC_SELECTION); // } @@ -947,11 +849,8 @@ void CtrlCanvas::viewMouseReleaseEvent(QMouseEvent* event) } } drag = DRAG_OFF; - //if(do_redraw) - // redraw(); // Let songChanged handle the redraw upon SC_SELECTION. + // Let songChanged handle the redraw upon SC_SELECTION. song->update(SC_SELECTION); // - //else - // redraw(); } break; @@ -995,7 +894,7 @@ void CtrlCanvas::newValRamp(int x1, int y1, int x2, int y2) useRaster = true; } - song->startUndo(); + Undo operations; // delete existing events @@ -1003,44 +902,29 @@ void CtrlCanvas::newValRamp(int x1, int y1, int x2, int y2) int lastpv = CTRL_VAL_UNKNOWN; for (ciCEvent i = items.begin(); i != items.end(); ++i) { CEvent* ev = *i; - if(ev->part() != curPart) + if (ev->part() != curPart) continue; Event event = ev->event(); if (event.empty()) continue; int x = event.tick() + curPartTick; - //printf("CtrlCanvas::newValRamp x:%d xx1:%d xx2:%d len:%d\n", x, xx1, xx2, curPart->lenTick()); if (x < xx1) - { - // if(event.dataB() != CTRL_VAL_UNKNOWN) - // lastpv = event.dataB(); continue; - } - //if (x <= xx1) - //{ - // if(type == CTRL_PROGRAM && event.dataB() != CTRL_VAL_UNKNOWN && ((event.dataB() & 0xffffff) != 0xffffff)) - // lastpv = event.dataB(); - // if (x < xx1) - // continue; - //} + if (x >= xx2) break; - // Indicate no undo, and do port controller values and clone parts. - audio->msgDeleteEvent(event, curPart, false, true, true); + // Do port controller values and clone parts. + operations.push_back(UndoOp(UndoOp::DeleteEvent, event, curPart, true, true)); } - //if(type == CTRL_PROGRAM && lastpv == CTRL_VAL_UNKNOWN) - if(ctrl) + if (ctrl) lastpv = ctrl->hwVal(); unsigned curPartLen = curPart->lenTick(); // insert new events - //for (int x = xx1; x < xx2; x += raster) { - // int y = (x2==x1) ? y1 : (((y2-y1)*(x-x1))/(x2-x1))+y1; - // int nval = computeVal(_controller, y, height()); for (int x = xx1, step; x < xx2 ; x += step ) { step = useRaster ? raster : editor->rasterVal2(x + 1) - x; @@ -1048,21 +932,18 @@ void CtrlCanvas::newValRamp(int x1, int y1, int x2, int y2) int y = x + step >= xx2 || x2 == x1 ? y2 : (x == xx1 ? y1 : (((y2 - y1) * (x + step/2 - x1)) / (x2 - x1)) + y1); int nval = computeVal(_controller, y, height()); - //int tick = x - curPartTick; unsigned tick = x - curPartTick; - //printf("CtrlCanvas::newValRamp x:%d xx1:%d xx2:%d step:%d newtick:%d\n", x, xx1, xx2, step, tick); // Do not add events which are past the end of the part. - //if((unsigned)tick >= curPartLen) - if(tick >= curPartLen) + if (tick >= curPartLen) break; Event event(Controller); event.setTick(tick); event.setA(_didx); - if(type == CTRL_PROGRAM) + if (type == CTRL_PROGRAM) { - if(lastpv == CTRL_VAL_UNKNOWN) + if (lastpv == CTRL_VAL_UNKNOWN) { - if(song->mtype() == MT_GM) + if (song->mtype() == MT_GM) event.setB(0xffff00 | (nval - 1)); else event.setB(nval - 1); @@ -1073,13 +954,11 @@ void CtrlCanvas::newValRamp(int x1, int y1, int x2, int y2) else event.setB(nval); - // Indicate no undo, and do port controller values and clone parts. - audio->msgAddEvent(event, curPart, false, true, true); + // Do port controller values and clone parts. + operations.push_back(UndoOp(UndoOp::AddEvent, event, curPart, true, true)); } - ///song->update(0); - ///redraw(); - song->endUndo(SC_EVENT_MODIFIED | SC_EVENT_INSERTED | SC_EVENT_REMOVED); + song->applyOperationGroup(operations); } //--------------------------------------------------------- @@ -1091,27 +970,24 @@ void CtrlCanvas::changeValRamp(int x1, int y1, int x2, int y2) int h = height(); bool changed = false; int type = _controller->num(); - //int xx1 = editor->rasterVal1(x1); - song->startUndo(); + Undo operations; for (ciCEvent i = items.begin(); i != items.end(); ++i) { if ((*i)->contains(x1, x2)) { - //if ((*i)->contains(xx1, x2)) { CEvent* ev = *i; - if(ev->part() != curPart) + if (ev->part() != curPart) continue; + Event event = ev->event(); if (event.empty()) continue; - //MidiPart* part = ev->part(); - //int x = event.tick() + ev->part()->tick(); int x = event.tick() + curPart->tick(); int y = (x2==x1) ? y1 : (((y2-y1)*(x-x1))/(x2-x1))+y1; int nval = computeVal(_controller, y, h); - if(type == CTRL_PROGRAM) + if (type == CTRL_PROGRAM) { - if(event.dataB() == CTRL_VAL_UNKNOWN) + if (event.dataB() == CTRL_VAL_UNKNOWN) { --nval; if(song->mtype() == MT_GM) @@ -1123,16 +999,13 @@ void CtrlCanvas::changeValRamp(int x1, int y1, int x2, int y2) ev->setVal(nval); - //MidiController::ControllerType type = midiControllerType(_controller->num()); - //if (type == MidiController::Velo) { if (type == CTRL_VELOCITY) { if ((event.velo() != nval)) { Event newEvent = event.clone(); newEvent.setVelo(nval); ev->setEvent(newEvent); - // Indicate no undo, and do not do port controller values and clone parts. - audio->msgChangeEvent(event, newEvent, curPart, false, false, false); - ///ev->setEvent(newEvent); + // Do not do port controller values and clone parts. + operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, curPart, false, false)); changed = true; } } @@ -1142,34 +1015,16 @@ void CtrlCanvas::changeValRamp(int x1, int y1, int x2, int y2) Event newEvent = event.clone(); newEvent.setB(nval); ev->setEvent(newEvent); - // Indicate no undo, and do port controller values and clone parts. - audio->msgChangeEvent(event, newEvent, curPart, false, true, true); - ///ev->setEvent(newEvent); + // Do port controller values and clone parts. + operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, curPart, true, true)); changed = true; } } - else { - //if(!ctrl) - //{ - // ctrl = - //} - - // Removed by T356. Never gets here? A good thing, don't wan't auto-create values. - //int oval = ctrl->value(0); - //if (oval != nval) { - // Changed by T356. - //ctrl->add(0, nval); - // ctrl->add(0, nval, part); - // changed = true; - // } - - } } } } - ///if (changed) - /// redraw(); - song->endUndo(SC_EVENT_MODIFIED); + + song->applyOperationGroup(operations); } //--------------------------------------------------------- @@ -1181,7 +1036,6 @@ void CtrlCanvas::changeVal(int x1, int x2, int y) bool changed = false; int newval = computeVal(_controller, y, height()); int type = _controller->num(); - //int xx1 = editor->rasterVal1(x1); for (ciCEvent i = items.begin(); i != items.end(); ++i) { if (!(*i)->contains(x1, x2)) @@ -1191,26 +1045,7 @@ void CtrlCanvas::changeVal(int x1, int x2, int y) if(ev->part() != curPart) continue; Event event = ev->event(); - //if(event.tick() >= curPart->lenTick()) - // break; - - //MidiPart* part = ev->part(); - //int nval = newval; - //if(type == CTRL_PROGRAM) - //{ - // if(event.dataB() == CTRL_VAL_UNKNOWN) - // { - // --nval; - // if(song->mtype() == MT_GM) - // nval |= 0xffff00; - // } - // else - // nval = (event.dataB() & 0xffff00) | (nval - 1); - //} - //ev->setVal(nval); - - //MidiController::ControllerType type = midiControllerType(_controller->num()); - //if (type == MidiController::Velo) { + if (type == CTRL_VELOCITY) { if ((event.velo() != newval)) { ev->setVal(newval); @@ -1249,160 +1084,12 @@ void CtrlCanvas::changeVal(int x1, int x2, int y) changed = true; } } - else { - //if(!ctrl) - //{ - // ctrl = - //} - - // Removed by T356. Never gets here? A good thing, don't wan't auto-create values. - //int oval = ctrl->value(0); - //if (oval != nval) { - // Changed by T356. - //ctrl->add(0, nval); - // ctrl->add(0, nval, part); - // changed = true; - // } - } } } if (changed) redraw(); } -/* -//--------------------------------------------------------- -// newVal -//--------------------------------------------------------- - -void CtrlCanvas::newVal(int x1, int x2, int y) - { - int xx1 = editor->rasterVal1(x1); - int xx2 = editor->rasterVal2(x2); - int newval = computeVal(_controller, y, height()); - int type = _controller->num(); - - bool found = false; - bool song_changed = false; - - int lastpv = CTRL_VAL_UNKNOWN; - if(ctrl) - lastpv = ctrl->hwVal(); - - for (ciCEvent i = items.begin(); i != items.end(); ++i) { - CEvent* ev = *i; - if(ev->part() != curPart) - continue; - //int partTick = ev->part()->tick(); - int partTick = curPart->tick(); - Event event = ev->event(); - if (event.empty()) - continue; - int ax = event.tick() + partTick; - //printf("CtrlCanvas::newVal ax:%d xx1:%d xx2:%d len:%d\n", ax, xx1, xx2, curPart->lenTick()); - - if (ax < xx1) - continue; - //if(ax <= xx1) - //{ - // if(type == CTRL_PROGRAM && event.dataB() != CTRL_VAL_UNKNOWN && ((event.dataB() & 0xffffff) != 0xffffff)) - // lastpv = event.dataB(); - // if(ax < xx1) - // continue; - //} - if (ax >= xx2) - break; - - // Added by T356. Do not add events which are past the end of the part. - //if(event.tick() >= curPart->lenTick()) - // break; - - int nval = newval; - if(type == CTRL_PROGRAM) - { - if(event.dataB() == CTRL_VAL_UNKNOWN) - { - //if(lastpv == CTRL_VAL_UNKNOWN) - // lastpv = ctrl->hwVal(); - - if(lastpv == CTRL_VAL_UNKNOWN) - { - --nval; - if(song->mtype() == MT_GM) - nval |= 0xffff00; - } - else - nval = (lastpv & 0xffff00) | (nval - 1); - } - else - nval = (event.dataB() & 0xffff00) | (nval - 1); - } - - if (ax == xx1) { - // change event - found = true; - ev->setVal(nval); - if ((event.dataB() != nval)) { - Event newEvent = event.clone(); - newEvent.setB(nval); - // Indicate no undo, and do port controller values and clone parts. - audio->msgChangeEvent(event, newEvent, curPart, false, true, true); - ev->setEvent(newEvent); - song_changed = true; - } - } - else if (ax < xx2) { - // delete event - - //printf("CtrlCanvas::newVal delete xx1:%d xx2:%d len:%d\n", xx1, xx2, curPart->lenTick()); - - // Indicate no undo, and do port controller values and clone parts. - audio->msgDeleteEvent(event, curPart, false, true, true); - - song_changed = true; - } - } - if (!found) { - // new event - int tick = xx1 - curPart->tick(); - // Do not add events which are past the end of the part. - if((unsigned)tick < curPart->lenTick()) - { - Event event(Controller); - event.setTick(tick); - event.setA(_didx); - if(type == CTRL_PROGRAM) - { - if(lastpv == CTRL_VAL_UNKNOWN) - { - if(song->mtype() == MT_GM) - event.setB(0xffff00 | (newval - 1)); - else - event.setB(newval - 1); - } - else - event.setB((lastpv & 0xffff00) | (newval - 1)); - } - else - event.setB(newval); - - //printf("CtrlCanvas::newVal add tick:%d A:%d B:%d\n", tick, event.dataA(), event.dataB()); - - // Indicate no undo, and do port controller values and clone parts. - audio->msgAddEvent(event, curPart, false, true, true); - - song_changed = true; - } - } - if (song_changed) - { - songChanged(0); - return; - } - redraw(); - } -*/ - //--------------------------------------------------------- // newVal //--------------------------------------------------------- @@ -1607,10 +1294,7 @@ void CtrlCanvas::newVal(int x1, int y) } } - //if(do_selchanged) - // song->update(SC_SELECTION); // Let songChanged handle the redraw upon SC_SELECTION. - //else - if(do_redraw) // + if(do_redraw) // Let songChanged handle the redraw upon SC_SELECTION. redraw(); } @@ -1637,12 +1321,8 @@ void CtrlCanvas::newVal(int x1, int y1, int x2, int y2) // So I draw from the first x. (TODO The idea may work now since I wrote this - more work was done.) p4.0.18 Tim. int xx1 = editor->rasterVal1(x1); - // Grab the 'second' raster. Nudge by +1 and let rasterVal2 snap to the next raster. - //int xn1 = editor->rasterVal2(xx1 + 1); int xx2 = editor->rasterVal2(x2); - // Grab the 'second last' raster. Nudge by -1 and let rasterVal1 snap to the previous raster. - //int xn2 = editor->rasterVal1(xx2 - 1); // If x1 and x2 happen to lie directly on the same raster, xx1 will equal xx2, // which is not good - there should always be a spread. Nudge by +1 and recompute. @@ -1661,7 +1341,6 @@ void CtrlCanvas::newVal(int x1, int y1, int x2, int y2) } bool do_redraw = false; - //bool do_selchanged = false; // delete existing events @@ -1671,7 +1350,6 @@ void CtrlCanvas::newVal(int x1, int y1, int x2, int y2) bool curPartFound = false; int lastpv = CTRL_VAL_UNKNOWN; int partTick = curPart->tick(); - //for (ciCEvent i = items.begin(); i != items.end(); ++i) for (iCEvent i = items.begin(); i != items.end() ; ) { CEvent* ev = *i; @@ -1701,10 +1379,7 @@ void CtrlCanvas::newVal(int x1, int y1, int x2, int y2) //printf("CtrlCanvas::newVal x:%d xx1:%d xx2:%d len:%d\n", x, xx1, xx2, curPart->lenTick()); if (x < xx1) - //if (x < (xn1 >= xx2 ? xx1 : xn1)) { - // if(event.dataB() != CTRL_VAL_UNKNOWN) - // lastpv = event.dataB(); prev_ev = i; ++i; continue; @@ -1739,24 +1414,14 @@ void CtrlCanvas::newVal(int x1, int y1, int x2, int y2) } do_redraw = true; // Let songChanged handle the redraw upon SC_SELECTION. - //do_selchanged = true; // prev_ev = i; } - //if(type == CTRL_PROGRAM && lastpv == CTRL_VAL_UNKNOWN) if(ctrl) lastpv = ctrl->hwVal(); // insert new events - //for (int x = xx1; x < xx2; x += raster) { - // Nudge x by +1 and let rasterVal2 snap to the next raster. - //for (int x = xx1; x < xx2; x = useRaster ? x + raster : editor->rasterVal2(x + 1)) - //for (int x = xn1; x < xx2; x = useRaster ? x + raster : editor->rasterVal2(x + 1)) - //for (int x = xn1, step; x < xx2 ; x += (step = useRaster ? raster : editor->rasterVal2(x + 1) - x) ) - // Start from the 'second' raster - the first raster is already set in mouseDown! - //for (int x = xn1, step; x < xx2 ; x += step ) - //for (int x = xn1 >= xx2 ? xx1 : xn1, step; x < xx2 ; x += step ) for (int x = xx1, step; x < xx2 ; x += step ) { step = useRaster ? raster : editor->rasterVal2(x + 1) - x; @@ -1808,9 +1473,6 @@ void CtrlCanvas::newVal(int x1, int y1, int x2, int y2) do_redraw = true; } - //if(do_selchanged) - // song->update(SC_SELECTION); // Let songChanged handle the redraw upon SC_SELECTION. - //else if(do_redraw) // redraw(); } @@ -1841,10 +1503,8 @@ void CtrlCanvas::deleteVal(int x1, int x2, int) iCEvent prev_ev = items.end(); bool curPartFound = false; - //bool song_changed = false; bool do_redraw = false; - //for (ciCEvent i = items.begin(); i != items.end(); ++i) for (iCEvent i = items.begin(); i != items.end() ;) { CEvent* ev = *i; @@ -1895,13 +1555,8 @@ void CtrlCanvas::deleteVal(int x1, int x2, int) prev_ev = i; } - //if (song_changed) { - // songChanged(0); - // return; - // } if(do_redraw) redraw(); // Let songChanged handle the redraw upon SC_SELECTION. - //song->update(SC_SELECTION); // } //--------------------------------------------------------- diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp index 6fab2ee4..a6c9c95a 100644 --- a/muse2/muse/functions.cpp +++ b/muse2/muse/functions.cpp @@ -7,6 +7,7 @@ #include "functions.h" #include "song.h" +#include "undo.h" #include "event.h" #include "audio.h" @@ -26,7 +27,6 @@ #include <QMessageBox> #include <QClipboard> - using namespace std; GateTime* gatetime_dialog=NULL; @@ -216,11 +216,10 @@ bool legato(const set<Part*>& parts) bool modify_velocity(const set<Part*>& parts, int range, int rate, int offset) { map<Event*, Part*> events = get_events(parts, range); + Undo operations; if ( (!events.empty()) && ((rate!=100) || (offset!=0)) ) { - song->startUndo(); - for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) { Event& event=*(it->first); @@ -240,13 +239,11 @@ bool modify_velocity(const set<Part*>& parts, int range, int rate, int offset) { Event newEvent = event.clone(); newEvent.setVelo(velo); - // Indicate no undo, and do not do port controller values and clone parts. - audio->msgChangeEvent(event, newEvent, part, false, false, false); + operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false)); } } - song->endUndo(SC_EVENT_MODIFIED); - return true; + return song->applyOperationGroup(operations); } else return false; @@ -255,11 +252,10 @@ bool modify_velocity(const set<Part*>& parts, int range, int rate, int offset) bool modify_off_velocity(const set<Part*>& parts, int range, int rate, int offset) { map<Event*, Part*> events = get_events(parts, range); + Undo operations; if ( (!events.empty()) && ((rate!=100) || (offset!=0)) ) { - song->startUndo(); - for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) { Event& event=*(it->first); @@ -279,13 +275,11 @@ bool modify_off_velocity(const set<Part*>& parts, int range, int rate, int offse { Event newEvent = event.clone(); newEvent.setVeloOff(velo); - // Indicate no undo, and do not do port controller values and clone parts. - audio->msgChangeEvent(event, newEvent, part, false, false, false); + operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false)); } } - - song->endUndo(SC_EVENT_MODIFIED); - return true; + + return song->applyOperationGroup(operations); } else return false; @@ -294,11 +288,10 @@ bool modify_off_velocity(const set<Part*>& parts, int range, int rate, int offse bool modify_notelen(const set<Part*>& parts, int range, int rate, int offset) { map<Event*, Part*> events = get_events(parts, range); + Undo operations; if ( (!events.empty()) && ((rate!=100) || (offset!=0)) ) { - song->startUndo(); - for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) { Event& event=*(it->first); @@ -316,13 +309,11 @@ bool modify_notelen(const set<Part*>& parts, int range, int rate, int offset) { Event newEvent = event.clone(); newEvent.setLenTick(len); - // Indicate no undo, and do not do port controller values and clone parts. - audio->msgChangeEvent(event, newEvent, part, false, false, false); + operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false)); } } - song->endUndo(SC_EVENT_MODIFIED); - return true; + return song->applyOperationGroup(operations); } else return false; @@ -358,7 +349,7 @@ unsigned quantize_tick(unsigned tick, unsigned raster, int swing) bool quantize_notes(const set<Part*>& parts, int range, int raster, bool quant_len, int strength, int swing, int threshold) { map<Event*, Part*> events = get_events(parts, range); - bool undo_started=false; + Undo operations; if (!events.empty()) { @@ -388,59 +379,50 @@ bool quantize_notes(const set<Part*>& parts, int range, int raster, bool quant_l if ( (event.lenTick() != len) || (event.tick() + part->tick() != begin_tick) ) { - if (!undo_started) - { - song->startUndo(); - undo_started=true; - } - Event newEvent = event.clone(); newEvent.setTick(begin_tick - part->tick()); newEvent.setLenTick(len); - // Indicate no undo, and do not do port controller values and clone parts. - audio->msgChangeEvent(event, newEvent, part, false, false, false); + operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false)); } } - if (undo_started) song->endUndo(SC_EVENT_MODIFIED); + return song->applyOperationGroup(operations); } - - return undo_started; + else + return false; } bool erase_notes(const set<Part*>& parts, int range, int velo_threshold, bool velo_thres_used, int len_threshold, bool len_thres_used) { map<Event*, Part*> events = get_events(parts, range); + Undo operations; if (!events.empty()) { - song->startUndo(); - for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) { Event& event=*(it->first); Part* part=it->second; + if ( (!velo_thres_used && !len_thres_used) || (velo_thres_used && event.velo() < velo_threshold) || (len_thres_used && int(event.lenTick()) < len_threshold) ) - audio->msgDeleteEvent(event, part, false, false, false); + operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, false, false)); } - song->endUndo(SC_EVENT_REMOVED); - return true; + return song->applyOperationGroup(operations); } else return false; } -bool transpose_notes(const set<Part*>& parts, int range, signed int halftonesteps, bool do_undo) +bool transpose_notes(const set<Part*>& parts, int range, signed int halftonesteps) { map<Event*, Part*> events = get_events(parts, range); + Undo operations; if ( (!events.empty()) && (halftonesteps!=0) ) { - if (do_undo) song->startUndo(); - for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) { Event& event=*(it->first); @@ -451,12 +433,10 @@ bool transpose_notes(const set<Part*>& parts, int range, signed int halftonestep if (pitch > 127) pitch=127; if (pitch < 0) pitch=0; newEvent.setPitch(pitch); - // Indicate no undo, and do not do port controller values and clone parts. - audio->msgChangeEvent(event, newEvent, part, false, false, false); + operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false)); } - if (do_undo) song->endUndo(SC_EVENT_MODIFIED); - return do_undo; + return song->applyOperationGroup(operations); } else return false; @@ -465,14 +445,13 @@ bool transpose_notes(const set<Part*>& parts, int range, signed int halftonestep bool crescendo(const set<Part*>& parts, int range, int start_val, int end_val, bool absolute) { map<Event*, Part*> events = get_events(parts, range); + Undo operations; int from=song->lpos(); int to=song->rpos(); if ( (!events.empty()) && (to>from) ) { - song->startUndo(); - for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) { Event& event=*(it->first); @@ -492,25 +471,22 @@ bool crescendo(const set<Part*>& parts, int range, int start_val, int end_val, b if (velo > 127) velo=127; if (velo <= 0) velo=1; newEvent.setVelo(velo); - // Indicate no undo, and do not do port controller values and clone parts. - audio->msgChangeEvent(event, newEvent, part, false, false, false); + operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false)); } - song->endUndo(SC_EVENT_MODIFIED); - return true; + return song->applyOperationGroup(operations); } else return false; } -bool move_notes(const set<Part*>& parts, int range, signed int ticks, bool do_undo) //TODO: clipping +bool move_notes(const set<Part*>& parts, int range, signed int ticks) //TODO: clipping { map<Event*, Part*> events = get_events(parts, range); + Undo operations; if ( (!events.empty()) && (ticks!=0) ) { - if (do_undo) song->startUndo(); - for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) { Event& event=*(it->first); @@ -532,24 +508,22 @@ bool move_notes(const set<Part*>& parts, int range, signed int ticks, bool do_un } if (del==false) - // Indicate no undo, and do not do port controller values and clone parts. - audio->msgChangeEvent(event, newEvent, part, false, false, false); + operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false)); else - // Indicate no undo, and do not do port controller values and clone parts. - audio->msgDeleteEvent(event, part, false, false, false); + operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, false, false)); } - if (do_undo) song->endUndo(SC_EVENT_MODIFIED); - return do_undo; + return song->applyOperationGroup(operations); } else return false; } + bool delete_overlaps(const set<Part*>& parts, int range) { map<Event*, Part*> events = get_events(parts, range); - bool undo_started=false; + Undo operations; set<Event*> deleted_events; @@ -576,17 +550,11 @@ bool delete_overlaps(const set<Part*>& parts, int range) (event1.tick() <= event2.tick()) && (event1.endTick() > event2.tick()) ) //they overlap { - if (undo_started==false) - { - song->startUndo(); - undo_started=true; - } - int new_len = event2.tick() - event1.tick(); if (new_len==0) { - audio->msgDeleteEvent(event1, part1, false, false, false); + operations.push_back(UndoOp(UndoOp::DeleteEvent, event1, part1, false, false)); deleted_events.insert(&event1); } else @@ -594,22 +562,23 @@ bool delete_overlaps(const set<Part*>& parts, int range) Event new_event1 = event1.clone(); new_event1.setLenTick(new_len); - audio->msgChangeEvent(event1, new_event1, part1, false, false, false); + operations.push_back(UndoOp(UndoOp::ModifyEvent, new_event1, event1, part1, false, false)); } } } } } - if (undo_started) song->endUndo(SC_EVENT_MODIFIED); + return song->applyOperationGroup(operations); } - return undo_started; + else + return false; } bool legato(const set<Part*>& parts, int range, int min_len, bool dont_shorten) { map<Event*, Part*> events = get_events(parts, range); - bool undo_started=false; + Undo operations; if (min_len<=0) min_len=1; @@ -643,22 +612,17 @@ bool legato(const set<Part*>& parts, int range, int min_len, bool dont_shorten) if (event1.lenTick() != len) { - if (undo_started==false) - { - song->startUndo(); - undo_started=true; - } - Event new_event1 = event1.clone(); new_event1.setLenTick(len); - audio->msgChangeEvent(event1, new_event1, part1, false, false, false); + operations.push_back(UndoOp(UndoOp::ModifyEvent, new_event1, event1, part1, false, false)); } } - if (undo_started) song->endUndo(SC_EVENT_MODIFIED); + return song->applyOperationGroup(operations); } - return undo_started; + else + return false; } @@ -749,6 +713,8 @@ QMimeData* selected_events_to_mime(const set<Part*>& parts, int range) void paste_at(Part* dest_part, const QString& pt, int pos) { + Undo operations; + Xml xml(pt.toLatin1().constData()); for (;;) { @@ -763,10 +729,8 @@ void paste_at(Part* dest_part, const QString& pt, int pos) case Xml::TagStart: if (tag == "eventlist") { - song->startUndo(); EventList el; el.read(xml, "eventlist", true); - int modified = SC_EVENT_INSERTED; for (iEvent i = el.begin(); i != el.end(); ++i) { Event e = i->second; @@ -774,7 +738,6 @@ void paste_at(Part* dest_part, const QString& pt, int pos) if (tick<0) { printf("ERROR: trying to add event before current part!\n"); - song->endUndo(SC_EVENT_INSERTED); goto end_of_paste_at; } @@ -786,18 +749,17 @@ void paste_at(Part* dest_part, const QString& pt, int pos) Part* newPart = dest_part->clone(); newPart->setLenTick(newPart->lenTick()+diff); // Indicate no undo, and do port controller values but not clone parts. - audio->msgChangePart(dest_part, newPart, false, true, false); - modified=modified|SC_PART_MODIFIED; + operations.push_back(UndoOp(UndoOp::ModifyPart,dest_part, newPart, true, false)); //FINDMICHJETZT oder andersrum? dest_part = newPart; // reassign TODO FINDME does this work, or has dest_part to be a nonconst reference? } // Indicate no undo, and do not do port controller values and clone parts. - audio->msgAddEvent(e, dest_part, false, false, false); + operations.push_back(UndoOp(UndoOp::AddEvent,e, dest_part, false, false)); } - song->endUndo(modified); + song->applyOperationGroup(operations); goto end_of_paste_at; } else - xml.unknown("pasteAt"); + xml.unknown("paste_at"); break; case Xml::Attribut: diff --git a/muse2/muse/functions.h b/muse2/muse/functions.h index 226c43f7..bc2bb8f4 100644 --- a/muse2/muse/functions.h +++ b/muse2/muse/functions.h @@ -51,8 +51,8 @@ bool quantize_notes(const std::set<Part*>& parts, int range, int raster, bool le bool erase_notes(const std::set<Part*>& parts, int range, int velo_threshold=0, bool velo_thres_used=false, int len_threshold=0, bool len_thres_used=false); bool delete_overlaps(const std::set<Part*>& parts, int range); bool set_notelen(const std::set<Part*>& parts, int range, int len); -bool move_notes(const std::set<Part*>& parts, int range, signed int ticks, bool do_undo=true); -bool transpose_notes(const std::set<Part*>& parts, int range, signed int halftonesteps, bool do_undo=true); +bool move_notes(const std::set<Part*>& parts, int range, signed int ticks); +bool transpose_notes(const std::set<Part*>& parts, int range, signed int halftonesteps); bool crescendo(const std::set<Part*>& parts, int range, int start_val, int end_val, bool absolute); bool legato(const std::set<Part*>& parts, int range, int min_len=1, bool dont_shorten=false); diff --git a/muse2/muse/keyevent.cpp b/muse2/muse/keyevent.cpp index 865aef01..5d55fef6 100644 --- a/muse2/muse/keyevent.cpp +++ b/muse2/muse/keyevent.cpp @@ -18,15 +18,15 @@ KeyList keymap; +#define DEFAULT_KEY KEY_C + //--------------------------------------------------------- // KeyList //--------------------------------------------------------- KeyList::KeyList() { - _key = KEY_C; - insert(std::pair<const unsigned, KeyEvent> (MAX_TICK+1, KeyEvent(_key, 0))); - useList = true; + insert(std::pair<const unsigned, KeyEvent> (MAX_TICK+1, KeyEvent(DEFAULT_KEY, 0))); } //--------------------------------------------------------- @@ -71,7 +71,7 @@ void KeyList::dump() const void KeyList::clear() { KEYLIST::clear(); - insert(std::pair<const unsigned, KeyEvent> (MAX_TICK+1, KeyEvent(_key, 0))); + insert(std::pair<const unsigned, KeyEvent> (MAX_TICK+1, KeyEvent(DEFAULT_KEY, 0))); } //--------------------------------------------------------- @@ -80,16 +80,12 @@ void KeyList::clear() key_enum KeyList::keyAtTick(unsigned tick) const { - if (useList) { ciKeyEvent i = upper_bound(tick); if (i == end()) { printf("no key at tick %d,0x%x\n", tick, tick); - return _key; + return DEFAULT_KEY; } return i->second.key; - } - else - return _key; } //--------------------------------------------------------- @@ -129,20 +125,6 @@ void KeyList::change(unsigned tick, key_enum newkey) e->second.key = newkey; } -//--------------------------------------------------------- -// setKey -// called from transport window -// & slave mode key changes -//--------------------------------------------------------- - -//void KeyList::setKey(unsigned tick, int newkey) -// { -// if (useList) -// add(tick, newkey); -// else -// _key = newkey; -// ++_keySN; -// } //--------------------------------------------------------- // addKey @@ -162,29 +144,6 @@ void KeyList::delKey(unsigned tick) del(tick); } -//--------------------------------------------------------- -// changeKey -//--------------------------------------------------------- - -//void KeyList::changeKey(unsigned tick, int newkey) -// { -// change(tick, newkey); -// ++_keySN; -// } - -//--------------------------------------------------------- -// setMasterFlag -//--------------------------------------------------------- - -bool KeyList::setMasterFlag(unsigned /*tick*/, bool val) - { - if (useList != val) { - useList = val; - return true; - } - return false; - } - //--------------------------------------------------------- @@ -193,7 +152,6 @@ bool KeyList::setMasterFlag(unsigned /*tick*/, bool val) void KeyList::write(int level, Xml& xml) const { - xml.put(level++, "<keylist fix=\"%d\">", _key); for (ciKeyEvent i = begin(); i != end(); ++i) i->second.write(level, xml, i->first); xml.tag(level, "/keylist"); @@ -225,8 +183,6 @@ void KeyList::read(Xml& xml) xml.unknown("keyList"); break; case Xml::Attribut: - if (tag == "fix") - _key = key_enum(xml.s2().toInt()); break; case Xml::TagEnd: if (tag == "keylist") { diff --git a/muse2/muse/keyevent.h b/muse2/muse/keyevent.h index 4a7fc8f9..2d127a67 100644 --- a/muse2/muse/keyevent.h +++ b/muse2/muse/keyevent.h @@ -78,9 +78,6 @@ typedef KEYLIST::const_reverse_iterator criKeyEvent; class KeyList : public KEYLIST { - bool useList; - key_enum _key; // key if not using key list - void add(unsigned tick, key_enum tempo); void change(unsigned tick, key_enum newKey); void del(iKeyEvent); @@ -99,8 +96,6 @@ class KeyList : public KEYLIST { void addKey(unsigned t, key_enum newKey); void delKey(unsigned tick); -// void changeKey(unsigned tick, key_enum newKey); - bool setMasterFlag(unsigned tick, bool val); }; extern KeyList keymap; diff --git a/muse2/muse/liste/listedit.cpp b/muse2/muse/liste/listedit.cpp index 080ee01c..5f73a3ba 100644 --- a/muse2/muse/liste/listedit.cpp +++ b/muse2/muse/liste/listedit.cpp @@ -852,7 +852,7 @@ void ListEdit::cmd(int cmd) bool found = false; for (int row = 0; row < liste->topLevelItemCount(); ++row) { - QTreeWidgetItem* i = liste->topLevelItem(row); + QTreeWidgetItem* i = liste->topLevelItem(row); EventListItem *item = (EventListItem *) i; if (i->isSelected() || item->event.selected()) { @@ -862,7 +862,8 @@ void ListEdit::cmd(int cmd) } if(!found) break; - song->startUndo(); + + Undo operations; EventListItem *deletedEvent=NULL; for (int row = 0; row < liste->topLevelItemCount(); ++row) { @@ -871,8 +872,8 @@ void ListEdit::cmd(int cmd) if (i->isSelected() || item->event.selected()) { deletedEvent=item; - // Indicate no undo, and do port controller values and clone parts. - audio->msgDeleteEvent(item->event, item->part, false, true, true); + // Port controller values and clone parts. + operations.push_back(UndoOp(UndoOp::DeleteEvent,item->event, item->part, true, true)); } } @@ -895,9 +896,8 @@ void ListEdit::cmd(int cmd) } } selectedTick=nextTick; - song->endUndo(SC_EVENT_MODIFIED); - //printf("selected tick = %d\n", selectedTick); - //emit selectionChanged(); + + song->applyOperationGroup(operations); break; } } diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp index 89cb1e4c..92e514af 100644 --- a/muse2/muse/midiedit/dcanvas.cpp +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -100,14 +100,14 @@ DrumCanvas::DrumCanvas(MidiEditor* pr, QWidget* parent, int sx, // moveCanvasItems //--------------------------------------------------------- -void DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtype, int* pflags) +Undo DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtype) { if(editor->parts()->empty()) - return; + return Undo(); //return empty list PartsToChangeMap parts2change; + Undo operations; - int modified = 0; for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) { Part* part = ip->second; @@ -143,34 +143,6 @@ void DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp if(npartoffset > 0) { - // Create new part... - // if there are several events that are moved outside the part, it will be recreated for each - // so the part _in_ the event will not be valid, ask the authority. -// Part* newPart = part->clone(); - //Part* newPart = Canvas::part()->clone(); - -// newPart->setLenTick(newPart->lenTick() + npartoffset); - //audio->msgChangePart(part, newPart,false); - -// modified = SC_PART_MODIFIED; - - // BUG FIX: #1650953 - // Added by T356. - // Fixes posted "select and drag past end of part - crashing" bug -// for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) -// { -// if(ip->second == part) -// { -// editor->parts()->erase(ip); -// break; -// } -// } - -// editor->parts()->add(newPart); -// audio->msgChangePart(part, newPart,false); - -// if(parts2change.find(part) == parts2change.end()) -// parts2change.insert(std::pair<Part*, Part*> (part, newPart)); iPartToChange ip2c = parts2change.find(part); if(ip2c == parts2change.end()) { @@ -179,14 +151,6 @@ void DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp } else ip2c->second.xdiff = npartoffset; - - - //part = newPart; // reassign - //item->setPart(part); - //item->setEvent(newEvent); - //curPart = part; - //curPartId = curPart->sn(); - } } @@ -199,8 +163,6 @@ void DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp newPart->setLenTick(newPart->lenTick() + diff); - modified = SC_PART_MODIFIED; - // BUG FIX: #1650953 // Added by T356. // Fixes posted "select and drag past end of part - crashing" bug @@ -214,9 +176,8 @@ void DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp } editor->parts()->add(newPart); - // Indicate no undo, and do port controller values but not clone parts. - //audio->msgChangePart(opart, newPart, false); - audio->msgChangePart(opart, newPart, false, true, false); + // Do port controller values but not clone parts. + operations.push_back(UndoOp(UndoOp::ModifyPart, opart, newPart, true, false)); ip2c->second.npart = newPart; @@ -256,21 +217,12 @@ void DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp break; // Do not process if the event has already been processed (meaning it's an event in a clone part)... - //if(moveItem(ci, newpos, dtype)) - if(idl != doneList.end()) - // Just move the canvas item. - ci->move(newpos); - else + if (idl == doneList.end()) { - // Currently moveItem always returns true. - if(moveItem(ci, newpos, dtype)) - { - // Add the canvas item to the list of done items. - doneList.push_back(ci); - // Move the canvas item. - ci->move(newpos); - } + operations.push_back(moveItem(ci, newpos, dtype)); + doneList.push_back(ci); } + ci->move(newpos); if(moving.size() == 1) { itemReleased(curItem, newpos); @@ -279,22 +231,17 @@ void DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp selectItem(ci, false); } - if(pflags) - *pflags = modified; + return operations; } //--------------------------------------------------------- // moveItem //--------------------------------------------------------- -// Changed by T356. -//bool DrumCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype, int* pflags) -bool DrumCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) +UndoOp DrumCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) { DEvent* nevent = (DEvent*) item; - // Changed by T356. - //MidiPart* part = (MidiPart*)Canvas::part(); // part can be dynamically recreated, ask the authority MidiPart* part = (MidiPart*)nevent->part(); Event event = nevent->event(); @@ -310,40 +257,6 @@ bool DrumCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) newEvent.setPitch(npitch); newEvent.setTick(ntick); - // Removed by T356. - /* - // Added by T356. - int modified = 0; - //song->startUndo(); - int diff = newEvent.endTick()-part->lenTick(); - if (diff > 0) // too short part? extend it - { - // if there are several events that are moved outside the part, it will be recreated for each - // so the part _in_ the event will not be valid, ask the authority. - //Part* newPart = part->clone(); - MidiPart* newPart = (MidiPart*)Canvas::part()->clone(); - newPart->setLenTick(newPart->lenTick()+diff); - audio->msgChangePart(Canvas::part(), newPart,false); - - modified = SC_PART_MODIFIED; - part = newPart; // reassign - for(iPart i = editor->parts()->begin(); i != editor->parts()->end(); ++i) - { - if(i->second == Canvas::part()) - { - editor->parts()->erase(i); - break; - } - } - editor->parts()->add(part); - item->setPart(part); - item->setEvent(newEvent); - curPart = part; - curPartId = curPart->sn(); - } - */ - - // Added by T356. // msgAddEvent and msgChangeEvent (below) will set these, but set them here first? //item->setPart(part); item->setEvent(newEvent); @@ -352,22 +265,10 @@ bool DrumCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) if(((int)newEvent.endTick() - (int)part->lenTick()) > 0) printf("DrumCanvas::moveItem Error! New event end:%d exceeds length:%d of part:%s\n", newEvent.endTick(), part->lenTick(), part->name().toLatin1().constData()); - if (dtype == MOVE_COPY || dtype == MOVE_CLONE) { - // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgAddEvent(newEvent, part, false); - audio->msgAddEvent(newEvent, part, false, false, false); - } - else { - // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgChangeEvent(event, newEvent, part, false); - audio->msgChangeEvent(event, newEvent, part, false, false, false); - } - - // Removed by T356. - //if(pflags) - // *pflags = modified; - - return true; + if (dtype == MOVE_COPY || dtype == MOVE_CLONE) + return UndoOp(UndoOp::AddEvent, newEvent, part, false, false); + else + return UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false); } //--------------------------------------------------------- @@ -412,7 +313,6 @@ void DrumCanvas::resizeItem(CItem* item, bool) DEvent* nevent = (DEvent*) item; Event ev = nevent->event(); // Indicate do undo, and do not do port controller values and clone parts. - //audio->msgDeleteEvent(ev, nevent->part()); audio->msgDeleteEvent(ev, nevent->part(), true, false, false); } @@ -431,7 +331,6 @@ void DrumCanvas::newItem(CItem* item, bool noSnap, bool replace) if (!noSnap) x = editor->rasterVal(x); event.setTick(x - nevent->part()->tick()); - //int npitch = drumMap[y2pitch(item->y())].enote; int npitch = event.pitch(); event.setPitch(npitch); @@ -451,7 +350,6 @@ void DrumCanvas::newItem(CItem* item, bool noSnap, bool replace) if (ev.pitch() == npitch) { // Indicate do undo, and do not do port controller values and clone parts. - //audio->msgDeleteEvent(ev, nevent->part()); audio->msgDeleteEvent(ev, nevent->part(), true, false, false); if (replace) break; @@ -470,16 +368,13 @@ void DrumCanvas::newItem(CItem* item, bool noSnap, bool replace) Part* newPart = part->clone(); newPart->setLenTick(newPart->lenTick()+diff); // Indicate no undo, and do port controller values but not clone parts. - //audio->msgChangePart(part, newPart,false); audio->msgChangePart(part, newPart, false, true, false); modified=modified|SC_PART_MODIFIED; part = newPart; // reassign } // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgAddEvent(event, part,false); audio->msgAddEvent(event, part, false, false, false); song->endUndo(modified); - } //--------------------------------------------------------- @@ -490,7 +385,6 @@ bool DrumCanvas::deleteItem(CItem* item) { Event ev = ((DEvent*)item)->event(); // Indicate do undo, and do not do port controller values and clone parts. - //audio->msgDeleteEvent(ev, ((DEvent*)item)->part()); audio->msgDeleteEvent(ev, ((DEvent*)item)->part(), true, false, false); return false; } @@ -559,10 +453,6 @@ void DrumCanvas::drawItem(QPainter&p, const CItem*item, const QRect& rect) void DrumCanvas::drawMoving(QPainter& p, const CItem* item, const QRect& rect) { - //if(((DEvent*)item)->part() != curPart) - // return; - //if(!item->isMoving()) - // return; QPolygon pa(4); QPoint pt = map(item->mp()); int x = pt.x(); @@ -745,7 +635,6 @@ void DrumCanvas::cmd(int cmd) Event newEvent = event.clone(); newEvent.setLenTick(drumMap[event.pitch()].len); // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgChangeEvent(event, newEvent, devent->part() , false); audio->msgChangeEvent(event, newEvent, devent->part(), false, false, false); } } @@ -785,8 +674,6 @@ void DrumCanvas::cmd(int cmd) case CMD_RIGHT_NOSNAP: { Pos p(pos[0] + editor->rasterStep(pos[0]), true); - //if (p > part->tick()) - // p = part->tick(); song->setPos(0, p, true, true, true); //CDW } break; @@ -796,7 +683,6 @@ void DrumCanvas::cmd(int cmd) } - //--------------------------------------------------------- // startDrag //--------------------------------------------------------- @@ -806,10 +692,6 @@ void DrumCanvas::startDrag(CItem* /* item*/, bool copymode) QMimeData* md = selected_events_to_mime(partlist_to_set(editor->parts()), 1); if (md) { -// QApplication::clipboard()->setData(drag, QClipboard::Clipboard); // This line NOT enabled in muse-1 - //QApplication::clipboard()->setMimeData(md); // TODO CHECK Tim. - //QApplication::clipboard()->setMimeData(drag->mimeData()); // - // "Note that setMimeData() assigns ownership of the QMimeData object to the QDrag object. // The QDrag must be constructed on the heap with a parent QWidget to ensure that Qt can // clean up after the drag and drop operation has been completed. " @@ -848,6 +730,7 @@ void DrumCanvas::dragLeaveEvent(QDragLeaveEvent*) { } + //--------------------------------------------------------- // keyPressed - called from DList //--------------------------------------------------------- @@ -890,13 +773,7 @@ void DrumCanvas::keyReleased(int index, bool) void DrumCanvas::mapChanged(int spitch, int dpitch) { - //TODO: Circumvent undo behaviour, since this isn't really a true change of the events, - // but merely a change in pitch because the pitch relates to the order of the dlist. - // Right now the sequencer spits out internalError: undoOp without startUndo() if start/stopundo is there, which is misleading - // If start/stopundo is there, undo misbehaves since it doesn't undo but messes things up - // Other solution: implement a specific undo-event for this (SC_DRUMMAP_MODIFIED or something) which undoes movement of - // dlist-items (ml) - + Undo operations; std::vector< std::pair<Part*, Event*> > delete_events; std::vector< std::pair<Part*, Event> > add_events; @@ -951,16 +828,10 @@ void DrumCanvas::mapChanged(int spitch, int dpitch) } } - song->startUndo(); for (idel_ev i = delete_events.begin(); i != delete_events.end(); i++) { - //std::pair<Part*, Event*> pair = *i; - //Part* thePart = pair.first; - //Event* theEvent = pair.second; Part* thePart = (*i).first; Event* theEvent = (*i).second; - // Indicate no undo, and do port controller values but not clone parts. - //audio->msgDeleteEvent(*theEvent, thePart, false); - audio->msgDeleteEvent(*theEvent, thePart, false, true, false); + operations.push_back(UndoOp(UndoOp::DeleteEvent, *theEvent, thePart, true, false)); } DrumMap dm = drumMap[spitch]; @@ -972,18 +843,13 @@ void DrumCanvas::mapChanged(int spitch, int dpitch) drumOutmap[int(drumMap[int(dpitch)].anote)] = dpitch; for (iadd_ev i = add_events.begin(); i != add_events.end(); i++) { - //std::pair<Part*, Event> pair = *i; - //Part* thePart = pair.first; - //Event& theEvent = pair.second; Part* thePart = (*i).first; Event& theEvent = (*i).second; - // Indicate no undo, and do port controller values but not clone parts. - //audio->msgAddEvent(theEvent, thePart, false); - audio->msgAddEvent(theEvent, thePart, false, true, false); + operations.push_back(UndoOp(UndoOp::AddEvent, theEvent, thePart, true, false)); } - song->endUndo(SC_EVENT_MODIFIED); - song->update(SC_DRUMMAP); + song->applyOperationGroup(operations, false); // do not indicate undo + song->update(SC_DRUMMAP); //this update is neccessary, as it's not handled by applyOperationGroup() } //--------------------------------------------------------- @@ -1027,40 +893,12 @@ void DrumCanvas::modifySelected(NoteInfo::ValType type, int delta) } break; case NoteInfo::VAL_LEN: - /* - { - int len = event.lenTick() + delta; - if (len < 1) - len = 1; - newEvent.setLenTick(len); - } - */ printf("DrumCanvas::modifySelected - NoteInfo::VAL_LEN not implemented\n"); break; case NoteInfo::VAL_VELON: - /* - { - int velo = event->velo() + delta; - if (velo > 127) - velo = 127; - else if (velo < 0) - velo = 0; - newEvent.setVelo(velo); - } - */ printf("DrumCanvas::modifySelected - NoteInfo::VAL_VELON not implemented\n"); break; case NoteInfo::VAL_VELOFF: - /* - { - int velo = event.veloOff() + delta; - if (velo > 127) - velo = 127; - else if (velo < 0) - velo = 0; - newEvent.setVeloOff(velo); - } - */ printf("DrumCanvas::modifySelected - NoteInfo::VAL_VELOFF not implemented\n"); break; case NoteInfo::VAL_PITCH: @@ -1076,8 +914,7 @@ void DrumCanvas::modifySelected(NoteInfo::ValType type, int delta) } song->changeEvent(event, newEvent, part); // Indicate do not do port controller values and clone parts. - //song->undoOp(UndoOp::ModifyEvent, newEvent, event, part); - song->undoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false); + song->addUndo(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false)); } song->endUndo(SC_EVENT_MODIFIED); audio->msgIdle(false); diff --git a/muse2/muse/midiedit/dcanvas.h b/muse2/muse/midiedit/dcanvas.h index fa087343..868113a6 100644 --- a/muse2/muse/midiedit/dcanvas.h +++ b/muse2/muse/midiedit/dcanvas.h @@ -54,10 +54,8 @@ class DrumCanvas : public EventCanvas { virtual void drawItem(QPainter&, const CItem*, const QRect&); void drawTopItem(QPainter& p, const QRect& rect); virtual void drawMoving(QPainter&, const CItem*, const QRect&); - virtual void moveCanvasItems(CItemList&, int, int, DragType, int*); - // Changed by T356. - //virtual bool moveItem(CItem*, const QPoint&, DragType, int*); - virtual bool moveItem(CItem*, const QPoint&, DragType); + virtual Undo moveCanvasItems(CItemList&, int, int, DragType); + virtual UndoOp moveItem(CItem*, const QPoint&, DragType); virtual CItem* newItem(const QPoint&, int); virtual void resizeItem(CItem*, bool); virtual void newItem(CItem*, bool); diff --git a/muse2/muse/midiedit/dlist.cpp b/muse2/muse/midiedit/dlist.cpp index ab2ed230..66922e83 100644 --- a/muse2/muse/midiedit/dlist.cpp +++ b/muse2/muse/midiedit/dlist.cpp @@ -47,7 +47,6 @@ void DList::draw(QPainter& p, const QRect& rect) if (yy > y + h) break; DrumMap* dm = &drumMap[i]; -// if (dm->selected) if (dm == currentlySelected) p.fillRect(x, yy, w, TH, Qt::yellow); // else @@ -56,13 +55,11 @@ void DList::draw(QPainter& p, const QRect& rect) for (int k = 0; k < h->count(); ++k) { int x = h->sectionPosition(k); int w = h->sectionSize(k); - ///QRect r = p.xForm(QRect(x+2, yy, w-4, TH)); QRect r = p.combinedTransform().mapRect(QRect(x+2, yy, w-4, TH)); QString s; int align = Qt::AlignVCenter | Qt::AlignHCenter; p.save(); - ///p.setWorldXForm(false); p.setWorldMatrixEnabled(false); switch (k) { case COL_VOL: @@ -145,16 +142,13 @@ void DList::draw(QPainter& p, const QRect& rect) // vertical Lines //--------------------------------------------------- - ///p.setWorldXForm(false); p.setWorldMatrixEnabled(false); int n = header->count(); x = 0; for (int i = 0; i < n; i++) { - //x += header->sectionSize(i); x += header->sectionSize(header->visualIndex(i)); p.drawLine(x, 0, x, height()); } - ///p.setWorldXForm(true); p.setWorldMatrixEnabled(true); } @@ -174,7 +168,6 @@ void DList::devicesPopupMenu(DrumMap* t, int x, int y, bool changeAll) if(n != t->port) { audio->msgIdle(true); - //audio->msgRemapPortDrumCtlEvents(getSelectedInstrument(), -1, -1, n); song->remapPortDrumCtrlEvents(getSelectedInstrument(), -1, -1, n); audio->msgIdle(false); t->port = n; @@ -184,13 +177,11 @@ void DList::devicesPopupMenu(DrumMap* t, int x, int y, bool changeAll) else { audio->msgIdle(true); // Delete all port controller events. - //audio->msgChangeAllPortDrumCtrlEvents(false); song->changeAllPortDrumCtrlEvents(false); for (int i = 0; i < DRUM_MAPSIZE; i++) drumMap[i].port = n; // Add all port controller events. - //audio->msgChangeAllPortDrumCtrlEvents(true); song->changeAllPortDrumCtrlEvents(true); audio->msgIdle(false); @@ -323,13 +314,11 @@ void DList::viewMousePressEvent(QMouseEvent* ev) if (ev->modifiers() & Qt::ControlModifier) { audio->msgIdle(true); // Delete all port controller events. - //audio->msgChangeAllPortDrumCtrlEvents(false); song->changeAllPortDrumCtrlEvents(false, true); for (int i = 0; i < DRUM_MAPSIZE; i++) drumMap[i].channel = val; // Add all port controller events. - //audio->msgChangeAllPortDrumCtrlEvents(true); song->changeAllPortDrumCtrlEvents(true, true); audio->msgIdle(false); song->update(SC_DRUMMAP); @@ -339,7 +328,6 @@ void DList::viewMousePressEvent(QMouseEvent* ev) if(val != dm->channel) { audio->msgIdle(true); - //audio->msgRemapPortDrumCtlEvents(pitch, -1, val, -1); song->remapPortDrumCtrlEvents(pitch, -1, val, -1); audio->msgIdle(false); dm->channel = val; @@ -397,7 +385,6 @@ void DList::viewMouseDoubleClickEvent(QMouseEvent* ev) { int x = ev->x(); int y = ev->y(); -// int button = ev->button(); unsigned pitch = y / TH; int section = header->logicalIndexAt(x); @@ -474,7 +461,6 @@ void DList::lineEdit(int line, int section) break; } - // editor->setText(dm->name); editor->end(false); editor->setGeometry(colx, coly, colw, colh); // In all cases but the column name, select all text: @@ -738,7 +724,7 @@ DList::DList(QHeaderView* h, QWidget* parent, int ymag) { setBg(Qt::white); if (!h){ - h = new QHeaderView(Qt::Horizontal, parent);} + h = new QHeaderView(Qt::Horizontal, parent);} header = h; scroll = 0; //ORCAN- CHECK if really needed: header->setTracking(true); @@ -761,8 +747,6 @@ DList::DList(QHeaderView* h, QWidget* parent, int ymag) DList::~DList() { -// if (currentlySelected != 0) -// currentlySelected->selected = false; //Reset the global thingie } //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/ecanvas.cpp b/muse2/muse/midiedit/ecanvas.cpp index d41a383c..ef47e0d6 100644 --- a/muse2/muse/midiedit/ecanvas.cpp +++ b/muse2/muse/midiedit/ecanvas.cpp @@ -102,25 +102,6 @@ QPoint EventCanvas::raster(const QPoint& p) const } //--------------------------------------------------------- -// startUndo -//--------------------------------------------------------- - -void EventCanvas::startUndo(DragType) - { - song->startUndo(); - } - -//--------------------------------------------------------- -// endUndo -//--------------------------------------------------------- - -void EventCanvas::endUndo(DragType dtype, int flags) - { - song->endUndo(flags | ((dtype == MOVE_COPY || dtype == MOVE_CLONE) - ? SC_EVENT_INSERTED : SC_EVENT_MODIFIED)); - } - -//--------------------------------------------------------- // mouseMove //--------------------------------------------------------- @@ -414,3 +395,30 @@ void EventCanvas::viewDropEvent(QDropEvent* event) } } + +//--------------------------------------------------------- +// endMoveItems +// dir = 0 move in all directions +// 1 move only horizontal +// 2 move only vertical +//--------------------------------------------------------- + +void EventCanvas::endMoveItems(const QPoint& pos, DragType dragtype, int dir) + { + int dp = y2pitch(pos.y()) - y2pitch(Canvas::start.y()); + int dx = pos.x() - Canvas::start.x(); + + if (dir == 1) + dp = 0; + else if (dir == 2) + dx = 0; + + + + Undo operations = moveCanvasItems(moving, dp, dx, dragtype); + song->applyOperationGroup(operations); + + moving.clear(); + updateSelection(); + redraw(); + } diff --git a/muse2/muse/midiedit/ecanvas.h b/muse2/muse/midiedit/ecanvas.h index 0ae970ab..b847f0f9 100644 --- a/muse2/muse/midiedit/ecanvas.h +++ b/muse2/muse/midiedit/ecanvas.h @@ -38,12 +38,7 @@ class EventCanvas : public Canvas { Q_OBJECT virtual void leaveEvent(QEvent*e); virtual void enterEvent(QEvent*e); - // Removed by T356. - //virtual QPoint raster(const QPoint&) const; - virtual void startUndo(DragType); - - virtual void endUndo(DragType, int flags = 0); virtual void mouseMove(QMouseEvent* event); protected: @@ -58,6 +53,9 @@ class EventCanvas : public Canvas { virtual void addItem(Part*, Event&) = 0; // Added by T356. virtual QPoint raster(const QPoint&) const; + virtual Undo moveCanvasItems(CItemList&, int, int, DragType) = 0; + virtual UndoOp moveItem(CItem*, const QPoint&, DragType) = 0; + virtual void endMoveItems(const QPoint&, DragType, int dir); public slots: void redrawGrid() { redraw(); } diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp index 4e81b2e9..091582ef 100644 --- a/muse2/muse/midiedit/prcanvas.cpp +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -38,6 +38,8 @@ #include "audio.h" #include "functions.h" +#define CHORD_TIMEOUT 75 + //--------------------------------------------------------- // NEvent //--------------------------------------------------------- @@ -254,14 +256,14 @@ void PianoCanvas::viewMouseDoubleClickEvent(QMouseEvent* event) // moveCanvasItems //--------------------------------------------------------- -void PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtype, int* pflags) +Undo PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtype) { if(editor->parts()->empty()) - return; - + return Undo(); //return empty list + + Undo operations; PartsToChangeMap parts2change; - int modified = 0; for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) { Part* part = ip->second; @@ -297,34 +299,6 @@ void PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dty if(npartoffset > 0) { - // Create new part... - // if there are several events that are moved outside the part, it will be recreated for each - // so the part _in_ the event will not be valid, ask the authority. -// Part* newPart = part->clone(); - //Part* newPart = Canvas::part()->clone(); - -// newPart->setLenTick(newPart->lenTick() + npartoffset); - //audio->msgChangePart(part, newPart,false); - -// modified = SC_PART_MODIFIED; - - // BUG FIX: #1650953 - // Added by T356. - // Fixes posted "select and drag past end of part - crashing" bug -// for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) -// { -// if(ip->second == part) -// { -// editor->parts()->erase(ip); -// break; -// } -// } - -// editor->parts()->add(newPart); -// audio->msgChangePart(part, newPart,false); - - //if(parts2change.find(part) == parts2change.end()) - // parts2change.insert(std::pair<Part*, Part*> (part, newPart)); iPartToChange ip2c = parts2change.find(part); if(ip2c == parts2change.end()) { @@ -333,13 +307,6 @@ void PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dty } else ip2c->second.xdiff = npartoffset; - - //part = newPart; // reassign - //item->setPart(part); - //item->setEvent(newEvent); - //curPart = part; - //curPartId = curPart->sn(); - } } @@ -352,8 +319,6 @@ void PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dty newPart->setLenTick(newPart->lenTick() + diff); - modified = SC_PART_MODIFIED; - // BUG FIX: #1650953 // Added by T356. // Fixes posted "select and drag past end of part - crashing" bug @@ -367,8 +332,8 @@ void PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dty } editor->parts()->add(newPart); - // Indicate no undo, and do port controller values but not clone parts. - audio->msgChangePart(opart, newPart, false, true, false); + // Do port controller values but not clone parts. + operations.push_back(UndoOp(UndoOp::ModifyPart, opart, newPart, true, false)); ip2c->second.npart = newPart; @@ -384,6 +349,7 @@ void PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dty std::vector< CItem* > doneList; typedef std::vector< CItem* >::iterator iDoneList; + for(iCItem ici = items.begin(); ici != items.end(); ++ici) { CItem* ci = ici->second; @@ -408,21 +374,12 @@ void PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dty break; // Do not process if the event has already been processed (meaning it's an event in a clone part)... - //if(moveItem(ci, newpos, dtype)) - if(idl != doneList.end()) - // Just move the canvas item. - ci->move(newpos); - else + if (idl == doneList.end()) { - // Currently moveItem always returns true. - if(moveItem(ci, newpos, dtype)) - { - // Add the canvas item to the list of done items. - doneList.push_back(ci); - // Move the canvas item. - ci->move(newpos); - } + operations.push_back(moveItem(ci, newpos, dtype)); + doneList.push_back(ci); } + ci->move(newpos); if(moving.size() == 1) itemReleased(curItem, newpos); @@ -430,8 +387,7 @@ void PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dty selectItem(ci, false); } - if(pflags) - *pflags = modified; + return operations; } //--------------------------------------------------------- @@ -439,9 +395,7 @@ void PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dty // called after moving an object //--------------------------------------------------------- -// Changed by T356. -//bool PianoCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype, int* pflags) -bool PianoCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) +UndoOp PianoCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) { NEvent* nevent = (NEvent*) item; Event event = nevent->event(); @@ -462,7 +416,7 @@ bool PianoCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) // Changed by T356. Part* part = nevent->part(); // - //Part * part = Canvas::part(); // part can be dynamically recreated, ask the authority + //Part* part = Canvas::part(); // part can be dynamically recreated, ask the authority newEvent.setPitch(npitch); int ntick = editor->rasterVal(x) - part->tick(); @@ -471,46 +425,6 @@ bool PianoCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) newEvent.setTick(ntick); newEvent.setLenTick(event.lenTick()); - // Removed by T356. - /* - int modified=0; - //song->startUndo(); - int diff = newEvent.endTick()-part->lenTick(); - if (diff > 0){// too short part? extend it - // if there are several events that are moved outside the part, it will be recreated for each - // so the part _in_ the event will not be valid, ask the authority. - //Part* newPart = part->clone(); - Part* newPart = Canvas::part()->clone(); - - newPart->setLenTick(newPart->lenTick()+diff); - audio->msgChangePart(Canvas::part(), newPart,false); - - modified = SC_PART_MODIFIED; - part = newPart; // reassign - - // BUG FIX: #1650953 - // Added by T356. - // Fixes posted "select and drag past end of part - crashing" bug - for(iPart i = editor->parts()->begin(); i != editor->parts()->end(); ++i) - { - if(i->second == Canvas::part()) - { - editor->parts()->erase(i); - break; - } - } - editor->parts()->add(part); - item->setPart(part); - item->setEvent(newEvent); - curPart = part; - curPartId = curPart->sn(); - - } - */ - - // Added by T356. - // msgAddEvent and msgChangeEvent (below) will set these, but set them here first? - //item->setPart(part); item->setEvent(newEvent); // Added by T356. @@ -518,20 +432,9 @@ bool PianoCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) printf("PianoCanvas::moveItem Error! New event end:%d exceeds length:%d of part:%s\n", newEvent.endTick(), part->lenTick(), part->name().toLatin1().constData()); if (dtype == MOVE_COPY || dtype == MOVE_CLONE) - // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgAddEvent(newEvent, part, false); - audio->msgAddEvent(newEvent, part, false, false, false); + return UndoOp(UndoOp::AddEvent, newEvent, part, false, false); else - // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgChangeEvent(event, newEvent, part, false); - audio->msgChangeEvent(event, newEvent, part, false, false, false); - //song->endUndo(modified); - - // Removed by T356. - //if(pflags) - // *pflags = modified; - - return true; + return UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false); } //--------------------------------------------------------- @@ -584,13 +487,11 @@ void PianoCanvas::newItem(CItem* item, bool noSnap) Part* newPart = part->clone(); newPart->setLenTick(newPart->lenTick()+diff); // Indicate no undo, and do port controller values but not clone parts. - //audio->msgChangePart(part, newPart,false); audio->msgChangePart(part, newPart, false, true, false); modified=modified|SC_PART_MODIFIED; part = newPart; // reassign } // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgAddEvent(event, part,false); audio->msgAddEvent(event, part, false, false, false); song->endUndo(modified); } @@ -620,14 +521,12 @@ void PianoCanvas::resizeItem(CItem* item, bool noSnap) // experimental c } song->startUndo(); int modified=SC_EVENT_MODIFIED; - //printf("event.tick()=%d len=%d part->lenTick()=%d\n",event.endTick(),len,part->lenTick()); int diff = event.tick()+len-part->lenTick(); if (diff > 0) {// too short part? extend it //printf("extend Part!\n"); Part* newPart = part->clone(); newPart->setLenTick(newPart->lenTick()+diff); // Indicate no undo, and do port controller values but not clone parts. - //audio->msgChangePart(part, newPart,false); audio->msgChangePart(part, newPart, false, true, false); modified=modified|SC_PART_MODIFIED; part = newPart; // reassign @@ -635,7 +534,6 @@ void PianoCanvas::resizeItem(CItem* item, bool noSnap) // experimental c newEvent.setLenTick(len); // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgChangeEvent(event, newEvent, nevent->part(),false); audio->msgChangeEvent(event, newEvent, nevent->part(), false, false, false); song->endUndo(modified); } @@ -650,7 +548,6 @@ bool PianoCanvas::deleteItem(CItem* item) if (nevent->part() == curPart) { Event ev = nevent->event(); // Indicate do undo, and do not do port controller values and clone parts. - //audio->msgDeleteEvent(ev, curPart); audio->msgDeleteEvent(ev, curPart, true, false, false); return true; } @@ -697,8 +594,6 @@ void PianoCanvas::pianoCmd(int cmd) case CMD_RIGHT_NOSNAP: { Pos p(pos[0] + editor->rasterStep(pos[0]), true); - //if (p > part->tick()) - // p = part->tick(); song->setPos(0, p, true, true, true); //CDW } break; @@ -710,8 +605,9 @@ void PianoCanvas::pianoCmd(int cmd) if (part == 0) break; - song->startUndo(); + EventList* el = part->events(); + Undo operations; std::list <Event> elist; for (iEvent e = el->lower_bound(pos[0] - part->tick()); e != el->end(); ++e) @@ -720,11 +616,11 @@ void PianoCanvas::pianoCmd(int cmd) Event event = *i; Event newEvent = event.clone(); newEvent.setTick(event.tick() + editor->raster());// - part->tick()); - // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgChangeEvent(event, newEvent, part, false); - audio->msgChangeEvent(event, newEvent, part, false, false, false); + // Do not do port controller values and clone parts. + operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false)); } - song->endUndo(SC_EVENT_MODIFIED); + song->applyOperationGroup(operations); + Pos p(editor->rasterVal(pos[0] + editor->rasterStep(pos[0])), true); song->setPos(0, p, true, false, true); } @@ -736,7 +632,8 @@ void PianoCanvas::pianoCmd(int cmd) MidiPart* part = (MidiPart*)curPart; if (part == 0) break; - song->startUndo(); + + Undo operations; EventList* el = part->events(); std::list<Event> elist; @@ -746,11 +643,10 @@ void PianoCanvas::pianoCmd(int cmd) Event event = *i; Event newEvent = event.clone(); newEvent.setTick(event.tick() - editor->raster() - part->tick()); - // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgChangeEvent(event, newEvent, part, false); - audio->msgChangeEvent(event, newEvent, part, false, false, false); + // Do not do port controller values and clone parts. + operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false)); } - song->endUndo(SC_EVENT_MODIFIED); + song->applyOperationGroup(operations); Pos p(editor->rasterVal(pos[0] - editor->rasterStep(pos[0])), true); song->setPos(0, p, true, false, true); } @@ -769,14 +665,12 @@ void PianoCanvas::pianoPressed(int pitch, int velocity, bool shift) pitch += track()->transposition; // play note: - //MidiPlayEvent e(0, port, channel, 0x90, pitch, 127); MidiPlayEvent e(0, port, channel, 0x90, pitch, velocity); audio->msgPlayMidiEvent(&e); if (_steprec && pos[0] >= start_tick && pos[0] < end_tick && curPart) { steprec->record(curPart,pitch,editor->raster(),editor->raster(),velocity,globalKeyState&Qt::ControlModifier,shift); } - } //--------------------------------------------------------- @@ -817,14 +711,6 @@ void drawTickRaster(QPainter& p, int x, int y, int w, int h, int raster) int qq = raster; if (q < 8) // grid too dense qq *= 2; - //switch (quant) { - // case 32: - // case 48: - // case 64: - // case 96: - // case 192: // 8tel - // case 128: // 8tel Triolen - // case 288: p.setPen(Qt::lightGray); if (raster>=4) { int xx = x + qq; @@ -835,10 +721,6 @@ void drawTickRaster(QPainter& p, int x, int y, int w, int h, int raster) } xx = xxx; } - // break; - // default: - // break; - // } p.setPen(Qt::gray); for (int beat = 1; beat < z; beat++) { int xx = AL::sigmap.bar2tick(bar, beat, 0); @@ -873,9 +755,7 @@ void PianoCanvas::drawCanvas(QPainter& p, const QRect& rect) p.drawLine(x, yy, x + w, yy); break; default: - //p.setPen(lightGray); p.fillRect(x, yy-3, w, 6, QBrush(QColor(230,230,230))); - //p.drawLine(x, yy, x + w, yy); break; } --key; @@ -971,24 +851,7 @@ void PianoCanvas::cmd(int cmd) } break; - case CMD_FIXED_LEN: //Set notes to the length specified in the drummap - if (!selectionSize()) - break; - song->startUndo(); - for (iCItem k = items.begin(); k != items.end(); ++k) { - if (k->second->isSelected()) { - NEvent* nevent = (NEvent*)(k->second); - Event event = nevent->event(); - Event newEvent = event.clone(); - newEvent.setLenTick(editor->raster()); - // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgChangeEvent(event, newEvent, nevent->part() , false); - audio->msgChangeEvent(event, newEvent, nevent->part(), false, false, false); - } - } - song->endUndo(SC_EVENT_MODIFIED); - break; - + case CMD_FIXED_LEN: case CMD_CRESCENDO: case CMD_TRANSPOSE: case CMD_THIN_OUT: @@ -1047,10 +910,6 @@ void PianoCanvas::startDrag(CItem* /* item*/, bool copymode) QMimeData* md = selected_events_to_mime(partlist_to_set(editor->parts()), 1); if (md) { -// QApplication::clipboard()->setData(drag, QClipboard::Clipboard); // This line NOT enabled in muse-1 - //QApplication::clipboard()->setMimeData(md); // TODO CHECK Tim. - //QApplication::clipboard()->setMimeData(drag->mimeData()); // - // "Note that setMimeData() assigns ownership of the QMimeData object to the QDrag object. // The QDrag must be constructed on the heap with a parent QWidget to ensure that Qt can // clean up after the drag and drop operation has been completed. " @@ -1233,8 +1092,8 @@ void PianoCanvas::modifySelected(NoteInfo::ValType type, int delta) } song->changeEvent(event, newEvent, part); // Indicate do not do port controller values and clone parts. - //song->undoOp(UndoOp::ModifyEvent, newEvent, event, part); - song->undoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false); + //song->addUndo(UndoOp(UndoOp::ModifyEvent, newEvent, event, part)); + song->addUndo(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false)); } song->endUndo(SC_EVENT_MODIFIED); audio->msgIdle(false); diff --git a/muse2/muse/midiedit/prcanvas.h b/muse2/muse/midiedit/prcanvas.h index 663b933a..c6e47c9e 100644 --- a/muse2/muse/midiedit/prcanvas.h +++ b/muse2/muse/midiedit/prcanvas.h @@ -54,10 +54,8 @@ class PianoCanvas : public EventCanvas { virtual void drawItem(QPainter&, const CItem*, const QRect&); void drawTopItem(QPainter &p, const QRect &rect); virtual void drawMoving(QPainter&, const CItem*, const QRect&); - virtual void moveCanvasItems(CItemList&, int, int, DragType, int*); - // Changed by T356. - //virtual bool moveItem(CItem*, const QPoint&, DragType, int*); - virtual bool moveItem(CItem*, const QPoint&, DragType); + virtual Undo moveCanvasItems(CItemList&, int, int, DragType); + virtual UndoOp moveItem(CItem*, const QPoint&, DragType); virtual CItem* newItem(const QPoint&, int); virtual void resizeItem(CItem*, bool noSnap); virtual void newItem(CItem*, bool noSnap); diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index d4915304..9bfbaa45 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -552,8 +552,6 @@ ScoreEdit::~ScoreEdit() } - - void ScoreEdit::velo_box_changed() { emit velo_changed(velo_spinbox->value()); @@ -592,10 +590,9 @@ void ScoreEdit::song_changed(int flags) if (velo>=0) velo_spinbox->setValue(velo); if (velo_off>=0) velo_off_spinbox->setValue(velo_off); } - } - - if (flags & SC_SELECTION) + selection_changed(); + } } void ScoreEdit::canvas_width_changed(int width) @@ -3532,7 +3529,7 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) int y=event->y() + y_pos - staff_it->y_draw; int x=event->x()+x_pos-x_left; int tick=flo_quantize_floor(x_to_tick(x), quant_ticks()); - + if (staff_it!=staves.end()) { if (event->x() <= x_left) //clicked in the preamble? @@ -4446,7 +4443,7 @@ void staff_t::update_part_indices() -//hint: recalculating event- and itemlists "from zero" +//note: recalculating event- and itemlists "from zero" // could happen in realtime, as it is pretty fast. // however, this adds unneccessary cpu usage. // it is NO problem to recalc the stuff "from zero" @@ -4460,13 +4457,19 @@ void staff_t::update_part_indices() * * CURRENT TODO * o either remove these "hidden notes", or deal with them in the score editor + * o insert empty measure should also work inside parts, that is, + * move notes _within_ parts + * + * IMPORTANT TODO + * o canvas editor: create clone via "alt+drag" moves window instead * o investigate with valgrind * o controller view in score editor * o deal with expanding parts * o fix sigedit boxes - * o mid-click in pianoroll: change to "delete", or initiate drag and drop between windows? - * - * IMPORTANT TODO + * o solo button + * o grand staff brace + * o mastertrack editor: key-combobox is buggy + * o drum editor: channel-stuff * o do partial recalculating; recalculating can take pretty long * (0,5 sec) when displaying a whole song in scores * o transpose etc. must also transpose key-pressure events @@ -4487,6 +4490,7 @@ void staff_t::update_part_indices() * keeping its own pos_add variable (which is only an optimisation) * o support edge-scrolling when opening a lasso * o save more configuration stuff (quant, color) + * o drum list: scroll while dragging (not important due to "reorder list") * * really unimportant nice-to-haves * o support in-song clef-changes diff --git a/muse2/muse/midiedit/scoreedit.h b/muse2/muse/midiedit/scoreedit.h index 1c45f578..e7302a46 100644 --- a/muse2/muse/midiedit/scoreedit.h +++ b/muse2/muse/midiedit/scoreedit.h @@ -707,15 +707,14 @@ class ScoreCanvas : public View int old_pitch; unsigned old_dest_tick; - - bool undo_started; - bool temp_undo; bool have_lasso; QPoint lasso_start; QRect lasso; - + bool undo_started; + bool temp_undo; + bool srec; bool held_notes[128]; diff --git a/muse2/muse/miditransform.cpp b/muse2/muse/miditransform.cpp index 1c73b7c2..9e9c87c0 100644 --- a/muse2/muse/miditransform.cpp +++ b/muse2/muse/miditransform.cpp @@ -662,14 +662,14 @@ void MidiTransformerDialog::transformEvent(Event& event, MidiPart* part, // Indicate do clone parts. addPortCtrlEvents(newEvent, part, true); // Indicate do port controller values and clone parts. - //song->undoOp(UndoOp::ModifyEvent, newEvent, event, part); - song->undoOp(UndoOp::ModifyEvent, newEvent, event, part, true, true); + //song->addUndo(UndoOp(UndoOp::ModifyEvent, newEvent, event, part)); + song->addUndo(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, true, true)); song->addUpdateFlags(SC_EVENT_MODIFIED); break; case Insert: // Indicate do port controller values and clone parts. - //song->undoOp(UndoOp::AddEvent, dummy, newEvent, part); - song->undoOp(UndoOp::AddEvent, dummy, newEvent, part, true, true); + //song->addUndo(UndoOp(UndoOp::AddEvent, dummy, newEvent, part)); + song->addUndo(UndoOp(UndoOp::AddEvent, dummy, newEvent, part, true, true)); song->addEvent(newEvent, part); // Indicate do clone parts. addPortCtrlEvents(newEvent, part, true); @@ -677,8 +677,8 @@ void MidiTransformerDialog::transformEvent(Event& event, MidiPart* part, break; case Extract: // Indicate do port controller values and clone parts. - //song->undoOp(UndoOp::DeleteEvent, dummy, event, part); - song->undoOp(UndoOp::DeleteEvent, dummy, event, part, true, true); + //song->addUndo(UndoOp(UndoOp::DeleteEvent, dummy, event, part)); + song->addUndo(UndoOp(UndoOp::DeleteEvent, dummy, event, part, true, true)); // Indicate do clone parts. removePortCtrlEvents(event, part, true); song->deleteEvent(event, part); @@ -713,8 +713,8 @@ void MidiTransformerDialog::processEvent(Event& event, MidiPart* part, MidiPart* // Indicate do clone parts. addPortCtrlEvents(newEvent, part, true); // Indicate do port controller values and clone parts. - //song->undoOp(UndoOp::ModifyEvent, newEvent, event, part); - song->undoOp(UndoOp::ModifyEvent, newEvent, event, part, true, true); + //song->addUndo(UndoOp(UndoOp::ModifyEvent, newEvent, event, part)); + song->addUndo(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, true, true)); song->addUpdateFlags(SC_EVENT_MODIFIED); } } @@ -723,8 +723,8 @@ void MidiTransformerDialog::processEvent(Event& event, MidiPart* part, MidiPart* { Event ev; // Indicate do port controller values and clone parts. - //song->undoOp(UndoOp::DeleteEvent, ev, event, part, true, true); - song->undoOp(UndoOp::DeleteEvent, ev, event, part, true, true); + //song->addUndo(UndoOp(UndoOp::DeleteEvent, ev, event, part, true, true)); + song->addUndo(UndoOp(UndoOp::DeleteEvent, ev, event, part, true, true)); // Indicate do clone parts. removePortCtrlEvents(event, part, true); song->deleteEvent(event, part); diff --git a/muse2/muse/part.cpp b/muse2/muse/part.cpp index 99f070b2..231b947b 100644 --- a/muse2/muse/part.cpp +++ b/muse2/muse/part.cpp @@ -85,9 +85,6 @@ void chainCloneInternal(Part* p) const PartList* pl = mt->cparts(); for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) { - // Added by Tim. p3.3.6 - //printf("chainCloneInternal track %p %s part %p %s evlist %p\n", (*imt), (*imt)->name().toLatin1().constData(), ip->second, ip->second->name().toLatin1().constData(), ip->second->cevents()); - if(ip->second != p && ip->second->cevents() == p->cevents()) { p1 = ip->second; @@ -224,16 +221,9 @@ void replaceClone(Part* p1, Part* p2) else p2->setNextClone(p2); - // Link the replacement... - //p2->setPrevClone(p1->prevClone()); - //p2->setNextClone(p1->nextClone()); - // Isolate the replaced part. p1->setNextClone(p1); p1->setPrevClone(p1); - // Added by Tim. p3.3.6 - //printf("replaceClone p1: %s %p arefs:%d p2: %s %p arefs:%d\n", p1->name().toLatin1().constData(), p1, ); - } //--------------------------------------------------------- @@ -278,9 +268,6 @@ void chainTrackParts(Track* t, bool incRefCount) if(incRefCount) p->events()->incARef(1); - // Added by Tim. p3.3.6 - //printf("chainTrackParts track %p %s part %p %s evlist %p\n", t, t->name().toLatin1().constData(), p, p->name().toLatin1().constData(), p->cevents()); - Part* p1 = 0; // Look for a part with the same event list, that we can chain to. @@ -296,9 +283,6 @@ void chainTrackParts(Track* t, bool incRefCount) const PartList* pl = mt->cparts(); for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) { - // Added by Tim. p3.3.6 - //printf("chainTrackParts track %p %s part %p %s evlist %p\n", mt, mt->name().toLatin1().constData(), ip->second, ip->second->name().toLatin1().constData(), ip->second->cevents()); - if(ip->second != p && ip->second->cevents() == p->cevents()) { p1 = ip->second; @@ -381,21 +365,12 @@ void addPortCtrlEvents(Event& event, Part* part, bool doClones) //for(int i = 0; i < j; ++i) while(1) { - // Added by Tim. p3.3.6 - //printf("addPortCtrlEvents i:%d %s %p events %p refs:%d arefs:%d\n", i, p->name().toLatin1().constData(), p, part->cevents(), part->cevents()->refCount(), j); - Track* t = p->track(); if(t && t->isMidiTrack()) { MidiTrack* mt = (MidiTrack*)t; int port = mt->outPort(); - //const EventList* el = p->cevents(); unsigned len = p->lenTick(); - //for(ciEvent ie = el->begin(); ie != el->end(); ++ie) - //{ - //const Event& ev = ie->second; - // Added by Tim. p3.3.6 - //printf("addPortCtrlEvents %s len:%d end:%d etick:%d\n", p->name().toLatin1().constData(), p->lenTick(), p->endTick(), event.tick()); // Do not add events which are past the end of the part. if(event.tick() >= len) @@ -425,7 +400,6 @@ void addPortCtrlEvents(Event& event, Part* part, bool doClones) mp->setControllerVal(ch, tck, cntrl, val, p); } - //} } if(!doClones) @@ -456,9 +430,6 @@ void addPortCtrlEvents(Part* part, bool doClones) //for(int i = 0; i < j; ++i) while(1) { - // Added by Tim. p3.3.6 - //printf("addPortCtrlEvents i:%d %s %p events %p refs:%d arefs:%d\n", i, p->name().toLatin1().constData(), p, part->cevents(), part->cevents()->refCount(), j); - Track* t = p->track(); if(t && t->isMidiTrack()) { @@ -532,16 +503,6 @@ void removePortCtrlEvents(Event& event, Part* part, bool doClones) { MidiTrack* mt = (MidiTrack*)t; int port = mt->outPort(); - //const EventList* el = p->cevents(); - //unsigned len = p->lenTick(); - //for(ciEvent ie = el->begin(); ie != el->end(); ++ie) - //{ - //const Event& ev = ie->second; - // Added by T356. Do not remove events which are past the end of the part. - // No, actually, do remove ALL of them belonging to the part. - // Just in case there are stray values left after the part end. - //if(ev.tick() >= len) - // break; if(event.type() == Controller) { @@ -566,7 +527,6 @@ void removePortCtrlEvents(Event& event, Part* part, bool doClones) mp->deleteController(ch, tck, cntrl, p); } - //} } if(!doClones) @@ -734,14 +694,6 @@ MidiPart::MidiPart(const MidiPart& p) : Part(p) { _prevClone = this; _nextClone = this; - //setSn(newSn()); - //_sn = p._sn; - //_name = p._name; - //_selected = p._selected; - //_mute = p._mute; - //_colorIndex = p._colorIndex; - //_track = p._track; - //_events = p._events; } //--------------------------------------------------------- @@ -769,14 +721,6 @@ WavePart::WavePart(const WavePart& p) : Part(p) { _prevClone = this; _nextClone = this; - //setSn(newSn()); - //_sn = p._sn; - //_name = p._name; - //_selected = p._selected; - //_mute = p._mute; - //_colorIndex = p._colorIndex; - //_track = p._track; - //_events = p._events; } //--------------------------------------------------------- @@ -790,139 +734,6 @@ Part::~Part() delete _events; } -/* -//--------------------------------------------------------- -// unchainClone -//--------------------------------------------------------- - -void Part::unchainClone() -{ - chainCheckErr(); - - _prevClone->setNextClone(_nextClone); - _nextClone->setPrevClone(_prevClone); - - _prevClone = this; - _nextClone = this; -} - -//--------------------------------------------------------- -// chainClone -// The quick way - if part to chain to is known... -//--------------------------------------------------------- - -void Part::chainClone(const Part* p) -{ - chainCheckErr(); - - // Make sure the part is unchained first. - p->prevClone()->setNextClone(p->nextClone()); - p->nextClone()->setPrevClone(p->prevClone()); - - p->setPrevClone(this); - p->setNextClone(_nextClone->prevClone()); - - _nextClone->setPrevClone(p); - _nextClone = (Part*)p; -} - -//--------------------------------------------------------- -// chainClone -// The slow way - if part to chain to is not known... -//--------------------------------------------------------- - -void Part::chainClone() -{ - chainCheckErr(); - - // Look for a part with the same event list, that we can chain to... - Part* p = 0; - if(!_track || (_track && _track->isMidiTrack())) - { - MidiTrackList* mtl = song->midis(); - for(ciMidiTrack imt = mtl->begin(); imt != mtl->end(); ++imt) - { - const PartList* pl = (*imt)->cparts(); - for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) - { - if(ip->second != this && ip->second->events() == _events) - { - p = ip->second; - break; - } - } - } - } - - if((!p && !_track) || (_track && _track->type() == Track::WAVE)) - { - WaveTrackList* wtl = song->waves(); - for(ciWaveTrack iwt = wtl->begin(); iwt != wtl->end(); ++iwt) - { - const PartList* pl = (*iwt)->cparts(); - for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) - { - if(ip->second != this && ip->second->events() == _events) - { - p = ip->second; - break; - } - } - } - } - - // No part found with same event list? Done. - if(!p) - return; - - // Make sure this part is unchained first. - _prevClone->setNextClone(_nextClone); - _nextClone->setPrevClone(_prevClone); - - _prevClone = p; - _nextClone = p->nextClone(); - - p->nextClone()->setPrevClone(this); - p->setNextClone(this); -} - -//--------------------------------------------------------- -// replaceClone -//--------------------------------------------------------- - -void Part::replaceClone(const Part* p) -{ - chainCheckErr(); - - // Make sure the part is unchained first. - p->prevClone()->setNextClone(p->nextClone()); - p->nextClone()->setPrevClone(p->prevClone()); - - // If this part is a clone, not a single lone part... - if(_prevClone != this) - _prevClone->setNextClone(p); - if(_nextClone != this) - _nextClone->setPrevClone(p); - - p->setPrevClone(_prevClone); - p->setNextClone(_nextClone); - - _nextClone = this; - _prevClone = this; -} - -//--------------------------------------------------------- -// chainCheckErr -//--------------------------------------------------------- - -void Part::chainCheckErr() -{ - if(_nextClone->prevClone() != this) - printf("Part::chainCheckErr Error! Next clone:%s %x prev clone:%s %x != this:%s %x\n", _nextClone->name().toLatin1().constData(), _nextClone, _nextClone->prevClone()->name().toLatin1().constData(), _nextClone->prevClone(), name().toLatin1().constData(), this); - if(_prevClone->nextClone() != this) - printf("Part::chainCheckErr Error! Prev clone:%s %x next clone:%s %x != this:%s %x\n", _prevClone->name().toLatin1().constData(), _prevClone, _prevClone->nextClone()->name().toLatin1().constData(), _prevClone->nextClone(), name().toLatin1().constData(), this); -} -*/ //--------------------------------------------------------- // findPart @@ -988,7 +799,6 @@ void Song::addPart(Part* part) _len = epos; part->track()->addPart(part); - //part->addPortCtrlEvents(); // Indicate do not do clones. addPortCtrlEvents(part, false); } @@ -999,9 +809,7 @@ void Song::addPart(Part* part) void Song::removePart(Part* part) { - //part->removePortCtrlEvents(); // Indicate do not do clones. - //removePortCtrlEvents(part); removePortCtrlEvents(part, false); Track* track = part->track(); track->parts()->remove(part); @@ -1025,7 +833,7 @@ void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len) // - 0 or more events are beginning after the new final position. Those are removed from the part // - The last event begins before new final position and ends after it. If so, it will be resized to end at new part length if (new_partlength < oPart->lenFrame()) { - startUndo(); + Undo operations; for (iEvent i = el->begin(); i != el->end(); i++) { Event e = i->second; @@ -1035,31 +843,30 @@ void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len) if (event_endframe < new_partlength) continue; if (event_startframe > new_partlength) { // If event start was after the new length, remove it from part - // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgDeleteEvent(e, nPart, false); - audio->msgDeleteEvent(e, nPart, false, false, false); + // Do not do port controller values and clone parts. + operations.push_back(UndoOp(UndoOp::DeleteEvent, e, nPart, false, false)); continue; } if (event_endframe > new_partlength) { // If this event starts before new length and ends after, shrink it Event newEvent = e.clone(); newEvent.setLenFrame(new_partlength - event_startframe); - // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgChangeEvent(e, newEvent, nPart, false); + // Do not do port controller values and clone parts. audio->msgChangeEvent(e, newEvent, nPart, false, false, false); + operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, e, nPart, false,false)); } } nPart->setLenFrame(new_partlength); - // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgChangePart(oPart, nPart, false); - audio->msgChangePart(oPart, nPart, false, false, false); + // Do not do port controller values and clone parts. + operations.push_back(UndoOp(UndoOp::ModifyPart, oPart, nPart, false, false)); - endUndo(SC_PART_MODIFIED); + song->applyOperationGroup(operations); } // If the part is expanded there can be no additional events beginning after the previous final position // since those are removed if the part has been shrunk at some time (see above) // The only thing we need to check is the final event: If it has data after the previous final position, // we'll expand that event else { + Undo operations; if(!el->empty()) { iEvent i = el->end(); @@ -1079,33 +886,27 @@ void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len) new_eventlength = clipframes; newEvent.setLenFrame(new_eventlength); - startUndo(); - // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgChangeEvent(last, newEvent, nPart, false); - audio->msgChangeEvent(last, newEvent, nPart, false, false, false); - } - else - { - startUndo(); + // Do not do port controller values and clone parts. + operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, last, nPart, false, false)); } nPart->setLenFrame(new_partlength); - // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgChangePart(oPart, nPart, false); + // Do not do port controller values and clone parts. audio->msgChangePart(oPart, nPart, false, false, false); - endUndo(SC_PART_MODIFIED); + operations.push_back(UndoOp(UndoOp::ModifyPart, oPart, nPart, false, false)); + song->applyOperationGroup(operations); } } break; case Track::MIDI: case Track::DRUM: { - startUndo(); + Undo operations; MidiPart* nPart = new MidiPart(*(MidiPart*)oPart); nPart->setLenTick(len); - // Indicate no undo, and do port controller values but not clone parts. - audio->msgChangePart(oPart, nPart, false, true, false); + // Do port controller values but not clone parts. + operations.push_back(UndoOp(UndoOp::ModifyPart, oPart, nPart, true, false)); // cut Events in nPart // Changed by T356. Don't delete events if this is a clone part. @@ -1118,36 +919,13 @@ void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len) for (; ie != el->end();) { iEvent i = ie; ++ie; - // Indicate no undo, and do port controller values and clone parts. - audio->msgDeleteEvent(i->second, nPart, false, true, true); + // Do port controller values and clone parts. + operations.push_back(UndoOp(UndoOp::DeleteEvent, i->second, nPart, true, true)); } } } - /* - // cut Events in nPart - // Changed by T356. Don't delete events if this is a clone part. - // The other clones might be longer than this one and need these events. - if(oPart->cevents()->arefCount() <= 1) - { - if (oPart->lenTick() > len) { - EventList* el = nPart->events(); - iEvent ie = el->lower_bound(len); - for (; ie != el->end();) { - iEvent i = ie; - ++ie; - // Indicate no undo, and do not do port controller values and clone parts. - //audio->msgDeleteEvent(i->second, nPart, false); - audio->msgDeleteEvent(i->second, nPart, false, false, false); - } - } - } - // Indicate no undo, and do port controller values but not clone parts. - //audio->msgChangePart(oPart, nPart, false); - audio->msgChangePart(oPart, nPart, false, true, false); - */ - - endUndo(SC_PART_MODIFIED); + song->applyOperationGroup(operations); break; } default: @@ -1281,27 +1059,9 @@ void Song::changePart(Part* oPart, Part* nPart) Track* oTrack = oPart->track(); Track* nTrack = nPart->track(); - // Added by Tim. p3.3.6 - //printf("Song::changePart before oPart->removePortCtrlEvents oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oPart->events()->refCount(), oPart->events()->arefCount(), nPart->events()->refCount(), nPart->events()->arefCount()); - - // Removed. Port controller events will have to be add/removed separately from this routine. - //oPart->removePortCtrlEvents(); - //removePortCtrlEvents(oPart); - - // Added by Tim. p3.3.6 - //printf("Song::changePart after oPart->removePortCtrlEvents oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oPart->events()->refCount(), oPart->events()->arefCount(), nPart->events()->refCount(), nPart->events()->arefCount()); - oTrack->parts()->remove(oPart); nTrack->parts()->add(nPart); - // Added by Tim. p3.3.6 - //printf("Song::changePart after add(nPart) oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oPart->events()->refCount(), oPart->events()->arefCount(), nPart->events()->refCount(), nPart->events()->arefCount()); - - //nPart->addPortCtrlEvents(); - //addPortCtrlEvents(nPart); - - // Added by Tim. p3.3.6 - //printf("Song::changePart after nPart->addPortCtrlEvents() oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oPart->events()->refCount(), oPart->events()->arefCount(), nPart->events()->refCount(), nPart->events()->arefCount()); // Added by T356. // adjust song len: @@ -1309,9 +1069,6 @@ void Song::changePart(Part* oPart, Part* nPart) if (epos > len()) _len = epos; - // Added by Tim. p3.3.6 - //printf("Song::changePart after len adjust oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oPart->events()->refCount(), oPart->events()->arefCount(), nPart->events()->refCount(), nPart->events()->arefCount()); - } //--------------------------------------------------------- @@ -1350,13 +1107,6 @@ void Song::cmdGluePart(Track* track, Part* oPart) EventList* sl2 = nextPart->events(); - //int frameOffset = nextPart->frame() - oPart->frame(); - //for (iEvent ie = sl2->begin(); ie != sl2->end(); ++ie) { - // Event event = ie->second.clone(); - // event.setFrame(event.frame() + frameOffset); - // dl->add(event); - // } - // p3.3.54 Changed. if(track->type() == Track::WAVE) { int frameOffset = nextPart->frame() - oPart->frame(); @@ -1382,7 +1132,6 @@ void Song::cmdGluePart(Track* track, Part* oPart) startUndo(); audio->msgRemovePart(nextPart, false); // Indicate no undo, and do port controller values but not clone parts. - //audio->msgChangePart(oPart, nPart, false); audio->msgChangePart(oPart, nPart, false, true, false); endUndo(SC_PART_MODIFIED | SC_PART_REMOVED); } diff --git a/muse2/muse/seqmsg.cpp b/muse2/muse/seqmsg.cpp index b4d65148..57aadc18 100644 --- a/muse2/muse/seqmsg.cpp +++ b/muse2/muse/seqmsg.cpp @@ -751,7 +751,7 @@ void Song::msgInsertTrack(Track* track, int idx, bool doUndoFlag) msg.ival = idx; if (doUndoFlag) { song->startUndo(); - undoOp(UndoOp::AddTrack, idx, track); + addUndo(UndoOp(UndoOp::AddTrack, idx, track)); } audio->sendMsg(&msg); if (doUndoFlag) @@ -893,31 +893,23 @@ void Audio::msgRemovePart(Part* part, bool doUndoFlag) bool Song::msgRemoveParts() { - bool loop; + Undo operations; bool partSelected = false; - do { - loop = false; + TrackList* tl = song->tracks(); for (iTrack it = tl->begin(); it != tl->end(); ++it) { PartList* pl = (*it)->parts(); for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { if (ip->second->selected()) { - if ((*it)->type() == Track::WAVE) { - audio->msgRemovePart((WavePart*)(ip->second)); - } - else { - audio->msgRemovePart(ip->second, false); - } - loop = true; + operations.push_back(UndoOp(UndoOp::DeletePart,ip->second)); partSelected = true; - break; } } - if (loop) - break; } - } while (loop); + + song->applyOperationGroup(operations); + return partSelected; } diff --git a/muse2/muse/song.cpp b/muse2/muse/song.cpp index 6750203a..6d0541a3 100644 --- a/muse2/muse/song.cpp +++ b/muse2/muse/song.cpp @@ -350,7 +350,7 @@ Track* Song::addTrack(int t) void Song::cmdRemoveTrack(Track* track) { int idx = _tracks.index(track); - undoOp(UndoOp::DeleteTrack, idx, track); + addUndo(UndoOp(UndoOp::DeleteTrack, idx, track)); removeTrack2(track); updateFlags |= SC_TRACK_REMOVED; } @@ -395,8 +395,8 @@ void Song::changeTrack(Track* oldTrack, Track* newTrack) oldTrack->setSelected(false); //?? int idx = _tracks.index(newTrack); - //undoOp(UndoOp::ModifyTrack, oldTrack, newTrack); - undoOp(UndoOp::ModifyTrack, idx, oldTrack, newTrack); + //addUndo(UndoOp(UndoOp::ModifyTrack, oldTrack, newTrack)); + addUndo(UndoOp(UndoOp::ModifyTrack, idx, oldTrack, newTrack)); updateFlags |= SC_TRACK_MODIFIED; } @@ -863,7 +863,7 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start // Now add all of the new part's port controller values. Indicate do not do clone parts. addPortCtrlEvents(newPart, false); // Create an undo op. Indicate do port controller values but not clone parts. - undoOp(UndoOp::ModifyPart, part, newPart, true, false); + addUndo(UndoOp(UndoOp::ModifyPart, part, newPart, true, false)); updateFlags |= SC_PART_MODIFIED; if (_recMode == REC_REPLACE) @@ -874,7 +874,7 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start { Event event = i->second; // Create an undo op. Indicate do port controller values and clone parts. - undoOp(UndoOp::DeleteEvent, event, newPart, true, true); + addUndo(UndoOp(UndoOp::DeleteEvent, event, newPart, true, true)); // Remove the event from the new part's port controller values, and do all clone parts. removePortCtrlEvents(event, newPart, true); } @@ -886,7 +886,7 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start event.setTick(event.tick() - partTick); Event e; // Create an undo op. Indicate do port controller values and clone parts. - undoOp(UndoOp::AddEvent, e, event, newPart, true, true); + addUndo(UndoOp(UndoOp::AddEvent, e, event, newPart, true, true)); if(newPart->events()->find(event) == newPart->events()->end()) newPart->events()->add(event); @@ -906,8 +906,8 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start { Event event = i->second; // Create an undo op. Indicate do port controller values and clone parts. - //undoOp(UndoOp::DeleteEvent, event, part); - undoOp(UndoOp::DeleteEvent, event, part, true, true); + //addUndo(UndoOp(UndoOp::DeleteEvent, event, part)); + addUndo(UndoOp(UndoOp::DeleteEvent, event, part, true, true)); //if (event.type() == Controller) { // MidiTrack* track = (MidiTrack*)part->track(); @@ -938,8 +938,8 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start event.setTick(tick); Event e; // Create an undo op. Indicate do port controller values and clone parts. - //undoOp(UndoOp::AddEvent, e, event, newPart); - undoOp(UndoOp::AddEvent, e, event, newPart, true, true); + //addUndo(UndoOp(UndoOp::AddEvent, e, event, newPart)); + addUndo(UndoOp(UndoOp::AddEvent, e, event, newPart, true, true)); // addEvent also adds port controller values. So does msgChangePart, below. Let msgChangePart handle them. //addEvent(event, (MidiPart*)newPart); @@ -965,9 +965,9 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start //printf("Song::cmdAddRecordedEvents after changePart part:%p events:%p refs:%d Arefs:%d newPart:%p events:%p refs:%d Arefs:%d\n", part, part->events(), part->events()->refCount(), part->events()->arefCount(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount()); - //undoOp(UndoOp::ModifyPart, part, newPart); + //addUndo(UndoOp(UndoOp::ModifyPart, part, newPart)); // Create an undo op. Indicate do not do port controller values and clone parts. - undoOp(UndoOp::ModifyPart, part, newPart, false, false); + addUndo(UndoOp(UndoOp::ModifyPart, part, newPart, false, false)); // Removed by T356. //part->events()->incARef(-1); @@ -985,8 +985,8 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start for (iEvent i = si; i != ei; ++i) { Event event = i->second; // Create an undo op. Indicate that controller values and clone parts were handled. - //undoOp(UndoOp::DeleteEvent, event, part); - undoOp(UndoOp::DeleteEvent, event, part, true, true); + //addUndo(UndoOp(UndoOp::DeleteEvent, event, part)); + addUndo(UndoOp(UndoOp::DeleteEvent, event, part, true, true)); /* if (event.type() == Controller) { MidiTrack* track = (MidiTrack*)part->track(); @@ -1007,8 +1007,8 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start event.setTick(tick); // Create an undo op. Indicate that controller values and clone parts were handled. - //undoOp(UndoOp::AddEvent, event, part); - undoOp(UndoOp::AddEvent, event, part, true, true); + //addUndo(UndoOp(UndoOp::AddEvent, event, part)); + addUndo(UndoOp(UndoOp::AddEvent, event, part, true, true)); //addEvent(event, part); if(part->events()->find(event) == part->events()->end()) @@ -1286,7 +1286,7 @@ void Song::setStopPlay(bool f) void Song::swapTracks(int i1, int i2) { - undoOp(UndoOp::SwapTrack, i1, i2); + addUndo(UndoOp(UndoOp::SwapTrack, i1, i2)); Track* track = _tracks[i1]; _tracks[i1] = _tracks[i2]; _tracks[i2] = track; @@ -1906,8 +1906,8 @@ void Song::processMsg(AudioMsg* msg) updateFlags = SC_EVENT_INSERTED; if (addEvent(msg->ev1, (MidiPart*)msg->p2)) { Event ev; - //undoOp(UndoOp::AddEvent, ev, msg->ev1, (Part*)msg->p2); - undoOp(UndoOp::AddEvent, ev, msg->ev1, (Part*)msg->p2, msg->a, msg->b); + //addUndo(UndoOp(UndoOp::AddEvent, ev, msg->ev1, (Part*)msg->p2)); + addUndo(UndoOp(UndoOp::AddEvent, ev, msg->ev1, (Part*)msg->p2, msg->a, msg->b)); } else updateFlags = 0; @@ -1921,8 +1921,8 @@ void Song::processMsg(AudioMsg* msg) if(msg->a) removePortCtrlEvents(event, part, msg->b); Event e; - //undoOp(UndoOp::DeleteEvent, e, event, (Part*)part); - undoOp(UndoOp::DeleteEvent, e, event, (Part*)part, msg->a, msg->b); + //addUndo(UndoOp(UndoOp::DeleteEvent, e, event, (Part*)part)); + addUndo(UndoOp(UndoOp::DeleteEvent, e, event, (Part*)part, msg->a, msg->b)); deleteEvent(event, part); updateFlags = SC_EVENT_REMOVED; } @@ -1933,21 +1933,21 @@ void Song::processMsg(AudioMsg* msg) changeEvent(msg->ev1, msg->ev2, (MidiPart*)msg->p3); if(msg->a) addPortCtrlEvents(msg->ev2, (Part*)msg->p3, msg->b); - //undoOp(UndoOp::ModifyEvent, msg->ev2, msg->ev1, (Part*)msg->p3); - undoOp(UndoOp::ModifyEvent, msg->ev2, msg->ev1, (Part*)msg->p3, msg->a, msg->b); + //addUndo(UndoOp(UndoOp::ModifyEvent, msg->ev2, msg->ev1, (Part*)msg->p3)); + addUndo(UndoOp(UndoOp::ModifyEvent, msg->ev2, msg->ev1, (Part*)msg->p3, msg->a, msg->b)); updateFlags = SC_EVENT_MODIFIED; break; case SEQM_ADD_TEMPO: //printf("processMsg (SEQM_ADD_TEMPO) UndoOp::AddTempo. adding tempo at: %d with tempo=%d\n", msg->a, msg->b); - undoOp(UndoOp::AddTempo, msg->a, msg->b); + addUndo(UndoOp(UndoOp::AddTempo, msg->a, msg->b)); tempomap.addTempo(msg->a, msg->b); updateFlags = SC_TEMPO; break; case SEQM_SET_TEMPO: //printf("processMsg (SEQM_SET_TEMPO) UndoOp::AddTempo. adding tempo at: %d with tempo=%d\n", msg->a, msg->b); - undoOp(UndoOp::AddTempo, msg->a, msg->b); + addUndo(UndoOp(UndoOp::AddTempo, msg->a, msg->b)); tempomap.setTempo(msg->a, msg->b); updateFlags = SC_TEMPO; break; @@ -1958,31 +1958,31 @@ void Song::processMsg(AudioMsg* msg) case SEQM_REMOVE_TEMPO: //printf("processMsg (SEQM_REMOVE_TEMPO) UndoOp::DeleteTempo. adding tempo at: %d with tempo=%d\n", msg->a, msg->b); - undoOp(UndoOp::DeleteTempo, msg->a, msg->b); + addUndo(UndoOp(UndoOp::DeleteTempo, msg->a, msg->b)); tempomap.delTempo(msg->a); updateFlags = SC_TEMPO; break; case SEQM_ADD_SIG: - undoOp(UndoOp::AddSig, msg->a, msg->b, msg->c); + addUndo(UndoOp(UndoOp::AddSig, msg->a, msg->b, msg->c)); AL::sigmap.add(msg->a, AL::TimeSignature(msg->b, msg->c)); updateFlags = SC_SIG; break; case SEQM_REMOVE_SIG: - undoOp(UndoOp::DeleteSig, msg->a, msg->b, msg->c); + addUndo(UndoOp(UndoOp::DeleteSig, msg->a, msg->b, msg->c)); AL::sigmap.del(msg->a); updateFlags = SC_SIG; break; case SEQM_ADD_KEY: - undoOp(UndoOp::AddKey, msg->a, msg->b); + addUndo(UndoOp(UndoOp::AddKey, msg->a, msg->b)); keymap.addKey(msg->a, (key_enum) msg->b); updateFlags = SC_KEY; break; case SEQM_REMOVE_KEY: - undoOp(UndoOp::DeleteKey, msg->a, msg->b); + addUndo(UndoOp(UndoOp::DeleteKey, msg->a, msg->b)); keymap.delKey(msg->a); updateFlags = SC_KEY; break; @@ -2000,7 +2000,7 @@ void Song::processMsg(AudioMsg* msg) void Song::cmdAddPart(Part* part) { addPart(part); - undoOp(UndoOp::AddPart, part); + addUndo(UndoOp(UndoOp::AddPart, part)); updateFlags = SC_PART_INSERTED; } @@ -2011,7 +2011,7 @@ void Song::cmdAddPart(Part* part) void Song::cmdRemovePart(Part* part) { removePart(part); - undoOp(UndoOp::DeletePart, part); + addUndo(UndoOp(UndoOp::DeletePart, part)); part->events()->incARef(-1); //part->unchainClone(); unchainClone(part); @@ -2032,8 +2032,8 @@ void Song::cmdChangePart(Part* oldPart, Part* newPart, bool doCtrls, bool doClon changePart(oldPart, newPart); - //undoOp(UndoOp::ModifyPart, oldPart, newPart); - undoOp(UndoOp::ModifyPart, oldPart, newPart, doCtrls, doClones); + //addUndo(UndoOp(UndoOp::ModifyPart, oldPart, newPart)); + addUndo(UndoOp(UndoOp::ModifyPart, oldPart, newPart, doCtrls, doClones)); // Changed by T356. Do not decrement ref count if the new part is a clone of the old part, since the event list // will still be active. diff --git a/muse2/muse/song.h b/muse2/muse/song.h index 47fd96d4..fd88b278 100644 --- a/muse2/muse/song.h +++ b/muse2/muse/song.h @@ -147,6 +147,8 @@ class Song : public QObject { Song(const char* name = 0); ~Song(); + bool applyOperationGroup(Undo& group, bool doUndo=true); + void putEvent(int pv); void endMsgCmd(); void processMsg(AudioMsg* msg); @@ -316,21 +318,9 @@ class Song : public QObject { void startUndo(); void endUndo(int); - //void undoOp(UndoOp::UndoType, Track* oTrack, Track* nTrack); - void undoOp(UndoOp::UndoType, int n, Track* oTrack, Track* nTrack); - void undoOp(UndoOp::UndoType, int, Track*); - void undoOp(UndoOp::UndoType, int, int, int = 0); - void undoOp(UndoOp::UndoType, Part*); - //void undoOp(UndoOp::UndoType, Event& nevent, Part*); - void undoOp(UndoOp::UndoType, Event& nevent, Part*, bool doCtrls, bool doClones); - //void undoOp(UndoOp::UndoType, Event& oevent, Event& nevent, Part*); - void undoOp(UndoOp::UndoType, Event& oevent, Event& nevent, Part*, bool doCtrls, bool doClones); - void undoOp(UndoOp::UndoType, SigEvent* oevent, SigEvent* nevent); - void undoOp(UndoOp::UndoType, int channel, int ctrl, int oval, int nval); - //void undoOp(UndoOp::UndoType, Part* oPart, Part* nPart); - void undoOp(UndoOp::UndoType, Part* oPart, Part* nPart, bool doCtrls, bool doClones); + void undoOp(UndoOp::UndoType type, const char* changedFile, const char* changeData, int startframe, int endframe); - void undoOp(UndoOp::UndoType type, Marker* copyMarker, Marker* realMarker); + bool doUndo1(); void doUndo2(); void doUndo3(); @@ -338,7 +328,7 @@ class Song : public QObject { void doRedo2(); void doRedo3(); - void addUndo(UndoOp& i); + void addUndo(UndoOp i); //----------------------------------------- // Configuration diff --git a/muse2/muse/structure.cpp b/muse2/muse/structure.cpp index f0a4308a..27246315 100644 --- a/muse2/muse/structure.cpp +++ b/muse2/muse/structure.cpp @@ -99,12 +99,12 @@ void MusE::adjustGlobalLists(int startPos, int diff) Marker *oldMarker = new Marker(); *oldMarker = *m; markerlist->remove(m); - song->undoOp(UndoOp::ModifyMarker,oldMarker, 0); + song->addUndo(UndoOp(UndoOp::ModifyMarker,oldMarker, 0)); } else { Marker *oldMarker = new Marker(); *oldMarker = *m; m->setTick(tick + diff); - song->undoOp(UndoOp::ModifyMarker,oldMarker, m); + song->addUndo(UndoOp(UndoOp::ModifyMarker,oldMarker, m)); } } } diff --git a/muse2/muse/undo.cpp b/muse2/muse/undo.cpp index a31b8e7a..0c05ef08 100644 --- a/muse2/muse/undo.cpp +++ b/muse2/muse/undo.cpp @@ -14,6 +14,8 @@ #include "song.h" #include "globals.h" +#include <QAction> + // iundo points to last Undo() in Undo-list static bool undoMode = false; // for debugging @@ -75,6 +77,7 @@ void UndoOp::dump() case ModifyMarker: case AddKey: case DeleteKey: + case DoNothing: break; } } @@ -184,6 +187,9 @@ void UndoList::clearDelete() void Song::startUndo() { + redoList->clear(); // added by flo93: redo must be invalidated when + redoAction->setEnabled(false); // a new undo is started + undoList->push_back(Undo()); updateFlags = 0; undoMode = true; @@ -200,6 +206,34 @@ void Song::endUndo(int flags) undoMode = false; } + +bool Song::applyOperationGroup(Undo& group, bool doUndo) +{ + if (!group.empty()) + { + //this is a HACK! but it works :) (added by flo93) + redoList->push_back(group); + redo(); + + if (!doUndo) + { + undoList->pop_back(); + undoAction->setEnabled(!undoList->empty()); + } + else + { + redoList->clear(); // added by flo93: redo must be invalidated when + redoAction->setEnabled(false); // a new undo is started + } + + return doUndo; + } + else + return false; +} + + + //--------------------------------------------------------- // doUndo2 // real time part @@ -447,6 +481,7 @@ void Song::doUndo2() break; case UndoOp::ModifyClip: case UndoOp::ModifyMarker: + case UndoOp::DoNothing: break; } } @@ -683,139 +718,120 @@ void Song::doRedo2() break; case UndoOp::ModifyClip: case UndoOp::ModifyMarker: + case UndoOp::DoNothing: break; } } } -void Song::undoOp(UndoOp::UndoType type, int a, int b, int c) +UndoOp::UndoOp() +{ +} + +UndoOp::UndoOp(UndoType type_) +{ + type = type_; +} + +UndoOp::UndoOp(UndoType type_, int a_, int b_, int c_) { - UndoOp i; - i.type = type; - i.a = a; - i.b = b; - i.c = c; - addUndo(i); + type = type_; + a = a_; + b = b_; + c = c_; } -//void Song::undoOp(UndoOp::UndoType type, Track* oldTrack, Track* newTrack) -void Song::undoOp(UndoOp::UndoType type, int n, Track* oldTrack, Track* newTrack) +UndoOp::UndoOp(UndoType type_, int n, Track* oldTrack, Track* newTrack) { - UndoOp i; - i.type = type; - i.trackno = n; - i.oTrack = oldTrack; - i.nTrack = newTrack; - // Added by Tim. p3.3.6 - //printf("Song::undoOp ModifyTrack oTrack %p %s nTrack %p %s\n", i.oTrack, i.oTrack->name().toLatin1().constData(), i.nTrack, i.nTrack->name().toLatin1().constData()); - - addUndo(i); + type = type_; + trackno = n; + oTrack = oldTrack; + nTrack = newTrack; } -void Song::undoOp(UndoOp::UndoType type, int n, Track* track) +UndoOp::UndoOp(UndoType type_, int n, Track* track) { - UndoOp i; - i.type = type; - i.trackno = n; - i.oTrack = track; - if (type == UndoOp::AddTrack) - updateFlags |= SC_TRACK_INSERTED; - addUndo(i); + type = type_; + trackno = n; + oTrack = track; } -void Song::undoOp(UndoOp::UndoType type, Part* part) +UndoOp::UndoOp(UndoType type_, Part* part) { - UndoOp i; - i.type = type; - i.oPart = part; - addUndo(i); + type = type_; + oPart = part; } -//void Song::undoOp(UndoOp::UndoType type, Event& oev, Event& nev, Part* part) -void Song::undoOp(UndoOp::UndoType type, Event& oev, Event& nev, Part* part, bool doCtrls, bool doClones) +UndoOp::UndoOp(UndoType type_, Event& oev, Event& nev, Part* part_, bool doCtrls_, bool doClones_) { - UndoOp i; - i.type = type; - i.nEvent = nev; - i.oEvent = oev; - i.part = part; - i.doCtrls = doCtrls; - i.doClones = doClones; - addUndo(i); + type = type_; + nEvent = nev; + oEvent = oev; + part = part_; + doCtrls = doCtrls_; + doClones = doClones_; } -void Song::undoOp(UndoOp::UndoType type, Event& nev, Part* part, bool doCtrls, bool doClones) +UndoOp::UndoOp(UndoType type_, Event& nev, Part* part_, bool doCtrls_, bool doClones_) { - UndoOp i; - i.type = type; - i.nEvent = nev; - i.part = part; - i.doCtrls = doCtrls; - i.doClones = doClones; - addUndo(i); + type = type_; + nEvent = nev; + part = part_; + doCtrls = doCtrls_; + doClones = doClones_; } -//void Song::undoOp(UndoOp::UndoType type, Part* oPart, Part* nPart) -void Song::undoOp(UndoOp::UndoType type, Part* oPart, Part* nPart, bool doCtrls, bool doClones) +UndoOp::UndoOp(UndoType type_, Part* oPart_, Part* nPart_, bool doCtrls_, bool doClones_) { - UndoOp i; - i.type = type; - i.oPart = nPart; - i.nPart = oPart; - i.doCtrls = doCtrls; - i.doClones = doClones; - addUndo(i); + type = type_; + oPart = nPart_; + nPart = oPart_; + doCtrls = doCtrls_; + doClones = doClones_; } -void Song::undoOp(UndoOp::UndoType type, int c, int ctrl, int ov, int nv) +UndoOp::UndoOp(UndoType type_, int c, int ctrl_, int ov, int nv) { - UndoOp i; - i.type = type; - i.channel = c; - i.ctrl = ctrl; - i.oVal = ov; - i.nVal = nv; - addUndo(i); + type = type_; + channel = c; + ctrl = ctrl_; + oVal = ov; + nVal = nv; } -void Song::undoOp(UndoOp::UndoType type, SigEvent* oevent, SigEvent* nevent) +UndoOp::UndoOp(UndoType type_, SigEvent* oevent, SigEvent* nevent) { - UndoOp i; - i.type = type; - i.oSignature = oevent; - i.nSignature = nevent; - addUndo(i); + type = type_; + oSignature = oevent; + nSignature = nevent; } - -void Song::undoOp(UndoOp::UndoType type, const char* changedFile, const char* changeData, int startframe, int endframe) +UndoOp::UndoOp(UndoType type_, Marker* copyMarker_, Marker* realMarker_) { - UndoOp i; - i.type = type; - i.filename = changedFile; - i.tmpwavfile = changeData; - i.startframe = startframe; - i.endframe = endframe; - addUndo(i); - temporaryWavFiles.push_back(QString(changeData)); - - //printf("Adding ModifyClip undo-operation: origfile=%s tmpfile=%s sf=%d ef=%d\n", changedFile, changeData, startframe, endframe); + type = type_; + realMarker = realMarker_; + copyMarker = copyMarker_; } -void Song::undoOp(UndoOp::UndoType type, Marker* copyMarker, Marker* realMarker) +UndoOp::UndoOp(UndoType type_, const char* changedFile, const char* changeData, int startframe_, int endframe_) { - UndoOp i; - i.type = type; - i.realMarker = realMarker; - i.copyMarker = copyMarker; + type = type_; + filename = changedFile; + tmpwavfile = changeData; + startframe = startframe_; + endframe = endframe_; + } - addUndo(i); +void Song::undoOp(UndoOp::UndoType type, const char* changedFile, const char* changeData, int startframe, int endframe) + { + addUndo(UndoOp(type,changedFile,changeData,startframe,endframe)); + temporaryWavFiles.push_back(QString(changeData)); } //--------------------------------------------------------- // addUndo //--------------------------------------------------------- -void Song::addUndo(UndoOp& i) +void Song::addUndo(UndoOp i) { if (!undoMode) { printf("internal error: undoOp without startUndo()\n"); diff --git a/muse2/muse/undo.h b/muse2/muse/undo.h index eb5600ef..b8f69d9f 100644 --- a/muse2/muse/undo.h +++ b/muse2/muse/undo.h @@ -36,7 +36,8 @@ struct UndoOp { AddKey, DeleteKey, SwapTrack, ModifyClip, - ModifyMarker + ModifyMarker, + DoNothing }; UndoType type; @@ -83,8 +84,23 @@ struct UndoOp { Event nEvent; bool doCtrls; bool doClones; + const char* typeName(); void dump(); + + UndoOp(); + UndoOp(UndoType type, int a, int b, int c=0); + UndoOp(UndoType type, int n, Track* oldTrack, Track* newTrack); + UndoOp(UndoType type, int n, Track* track); + UndoOp(UndoType type, Part* part); + UndoOp(UndoType type, Event& oev, Event& nev, Part* part, bool doCtrls, bool doClones); + UndoOp(UndoType type, Event& nev, Part* part, bool doCtrls, bool doClones); + UndoOp(UndoType type, Part* oPart, Part* nPart, bool doCtrls, bool doClones); + UndoOp(UndoType type, int c, int ctrl, int ov, int nv); + UndoOp(UndoType type, SigEvent* oevent, SigEvent* nevent); + UndoOp(UndoType type, const char* changedFile, const char* changeData, int startframe, int endframe); + UndoOp(UndoType type, Marker* copyMarker, Marker* realMarker); + UndoOp(UndoType type); }; class Undo : public std::list<UndoOp> { diff --git a/muse2/muse/widgets/canvas.cpp b/muse2/muse/widgets/canvas.cpp index eb89af1e..650b10b7 100644 --- a/muse2/muse/widgets/canvas.cpp +++ b/muse2/muse/widgets/canvas.cpp @@ -569,12 +569,9 @@ void Canvas::viewMousePressEvent(QMouseEvent* event) } if (curItem && (event->button() == Qt::MidButton)) { - if (!curItem->isSelected()) { - selectItem(curItem, true); - updateSelection(); - redraw(); - } - startDrag(curItem, ctrl); + deleteItem(start); // changed from "start drag" to "delete" by flo93 + drag = DRAG_DELETE; + setCursor(); } else if (event->button() == Qt::RightButton) { if (curItem) { @@ -1209,56 +1206,6 @@ void Canvas::selectLasso(bool toggle) } } -//--------------------------------------------------------- -// endMoveItems -// dir = 0 move in all directions -// 1 move only horizontal -// 2 move only vertical -//--------------------------------------------------------- - -void Canvas::endMoveItems(const QPoint& pos, DragType dragtype, int dir) - { - startUndo(dragtype); - - int dp = y2pitch(pos.y()) - y2pitch(start.y()); - int dx = pos.x() - start.x(); - - if (dir == 1) - dp = 0; - else if (dir == 2) - dx = 0; - - - - int modified = 0; - - // Removed by T356. - /* - for (iCItem i = moving.begin(); i != moving.end(); ++i) { - int x = i->second->pos().x(); - int y = i->second->pos().y(); - int nx = x + dx; - int ny = pitch2y(y2pitch(y) + dp); - QPoint newpos = raster(QPoint(nx, ny)); - selectItem(i->second, true); - - if (moveItem(i->second, newpos, dragtype, &modified)) - i->second->move(newpos); - if (moving.size() == 1) { - itemReleased(curItem, newpos); - } - if (dragtype == MOVE_COPY || dragtype == MOVE_CLONE) - selectItem(i->second, false); - } - */ - - moveCanvasItems(moving, dp, dx, dragtype, &modified); - - endUndo(dragtype, modified); - moving.clear(); - updateSelection(); - redraw(); - } //--------------------------------------------------------- // getCurrentDrag diff --git a/muse2/muse/widgets/canvas.h b/muse2/muse/widgets/canvas.h index 6e8b9fa8..2eae3d03 100644 --- a/muse2/muse/widgets/canvas.h +++ b/muse2/muse/widgets/canvas.h @@ -11,6 +11,7 @@ #include "citem.h" #include "view.h" #include "tools.h" +#include "undo.h" #include <QWheelEvent> #include <QMouseEvent> @@ -100,17 +101,10 @@ class Canvas : public View { virtual int y2pitch(int) const = 0; //CDW virtual int pitch2y(int) const = 0; //CDW - virtual void moveCanvasItems(CItemList&, int, int, DragType, int*) = 0; - // Changed by T356. - //virtual bool moveItem(CItem*, const QPoint&, DragType, int*) = 0; - virtual bool moveItem(CItem*, const QPoint&, DragType) = 0; virtual CItem* newItem(const QPoint&, int state) = 0; virtual void resizeItem(CItem*, bool noSnap=false) = 0; virtual void newItem(CItem*, bool noSnap=false) = 0; virtual bool deleteItem(CItem*) = 0; - virtual void startUndo(DragType) = 0; - - virtual void endUndo(DragType, int flags) = 0; int getCurrentDrag(); /*! @@ -153,7 +147,7 @@ class Canvas : public View { void startMoving(const QPoint&, DragType); void moveItems(const QPoint&, int dir, bool rasterize = true); - void endMoveItems(const QPoint&, DragType, int dir); + virtual void endMoveItems(const QPoint&, DragType, int dir) = 0; virtual void selectLasso(bool toggle); |