diff options
Diffstat (limited to 'attic/muse2-oom/muse2/muse/arranger/pcanvas.cpp')
-rw-r--r-- | attic/muse2-oom/muse2/muse/arranger/pcanvas.cpp | 2977 |
1 files changed, 0 insertions, 2977 deletions
diff --git a/attic/muse2-oom/muse2/muse/arranger/pcanvas.cpp b/attic/muse2-oom/muse2/muse/arranger/pcanvas.cpp deleted file mode 100644 index 3e6919a7..00000000 --- a/attic/muse2-oom/muse2/muse/arranger/pcanvas.cpp +++ /dev/null @@ -1,2977 +0,0 @@ -//========================================================= -// MusE -// Linux Music Editor -// $Id: pcanvas.cpp,v 1.48.2.26 2009/11/22 11:08:33 spamatica Exp $ -// (C) Copyright 1999 Werner Schweer (ws@seh.de) -//========================================================= - -#include <stdio.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <errno.h> -#include <values.h> -#include <uuid/uuid.h> -#include <math.h> - -#include <QClipboard> -#include <QLineEdit> -#include <QMenu> -#include <QMessageBox> -#include <QPainter> -#include <QUrl> - -#include "widgets/tools.h" -#include "pcanvas.h" -#include "midieditor.h" -#include "globals.h" -#include "icons.h" -#include "event.h" -#include "xml.h" -#include "wave.h" -#include "audio.h" -#include "shortcuts.h" -#include "gconfig.h" -#include "app.h" -#include "filedialog.h" -#include "marker/marker.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 -// paints a rectangular icon with a given color -//--------------------------------------------------------- - -QIcon colorRect(const QColor& color, int width, int height) { - QPainter painter; - QPixmap image(width, height); - painter.begin(&image); - painter.setBrush(color); - QRect rectangle(0, 0, width, height); - painter.drawRect(rectangle); - painter.end(); - QIcon icon(image); - return icon; -} - -//--------------------------------------------------------- -// NPart -//--------------------------------------------------------- - -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)); - - ///setBBox(QRect(e->tick(), y + 1, e->lenTick(), th)); - // NOTE: For adjustable border size: If using a two-pixel border width while drawing, use second line. - // If one-pixel width, use first line. Tim. - //setBBox(QRect(e->tick(), y, e->lenTick(), th)); - setBBox(QRect(e->tick(), y + 1, e->lenTick(), th)); - } - -//--------------------------------------------------------- -// PartCanvas -//--------------------------------------------------------- - -PartCanvas::PartCanvas(int* r, QWidget* parent, int sx, int sy) - : Canvas(parent, sx, sy) - { - setAcceptDrops(true); - _raster = r; - - setFocusPolicy(Qt::StrongFocus); - // Defaults: - lineEditor = 0; - editMode = false; - - tracks = song->tracks(); - setMouseTracking(true); - drag = DRAG_OFF; - curColorIndex = 0; - partsChanged(); - } - -//--------------------------------------------------------- -// y2pitch -//--------------------------------------------------------- - -int PartCanvas::y2pitch(int y) const - { - TrackList* tl = song->tracks(); - int yy = 0; - int idx = 0; - for (iTrack it = tl->begin(); it != tl->end(); ++it, ++idx) { - int h = (*it)->height(); - // if ((y >= yy) && (y < yy+h)) - if (y < yy+h) - break; - yy += h; - } - return idx; - } - -//--------------------------------------------------------- -// pitch2y -//--------------------------------------------------------- - -int PartCanvas::pitch2y(int p) const - { - TrackList* tl = song->tracks(); - int yy = 0; - int idx = 0; - for (iTrack it = tl->begin(); it != tl->end(); ++it, ++idx) { - if (idx == p) - break; - yy += (*it)->height(); - } - return yy; - } - -//--------------------------------------------------------- -// leaveEvent -//--------------------------------------------------------- - -void PartCanvas::leaveEvent(QEvent*) - { - emit timeChanged(MAXINT); - } - -//--------------------------------------------------------- -// returnPressed -//--------------------------------------------------------- - -void PartCanvas::returnPressed() - { - lineEditor->hide(); - Part* oldPart = editPart->part(); - Part* newPart = oldPart->clone(); - //printf("PartCanvas::returnPressed before msgChangePart oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oldPart->events()->refCount(), oldPart->events()->arefCount(), newPart->events()->refCount(), newPart->events()->arefCount()); - - 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; - } - -//--------------------------------------------------------- -// viewMouseDoubleClick -//--------------------------------------------------------- - -void PartCanvas::viewMouseDoubleClickEvent(QMouseEvent* event) - { - if (_tool != PointerTool) { - viewMousePressEvent(event); - return; - } - QPoint cpos = event->pos(); - curItem = items.find(cpos); - bool shift = event->modifiers() & Qt::ShiftModifier; - if (curItem) { - if (event->button() == Qt::LeftButton && shift) { - editPart = (NPart*)curItem; - QRect r = map(curItem->bbox()); - if (lineEditor == 0) { - lineEditor = new QLineEdit(this); - lineEditor->setFrame(true); - } - editMode = true; - lineEditor->setGeometry(r); - lineEditor->setText(editPart->name()); - lineEditor->setFocus(); - lineEditor->show(); - } - else if (event->button() == Qt::LeftButton) { - deselectAll(); - selectItem(curItem, true); - emit dclickPart(((NPart*)(curItem))->track()); - } - } - // - // double click creates new part between left and - // right mark - - else { - TrackList* tl = song->tracks(); - iTrack it; - int yy = 0; - int y = event->y(); - for (it = tl->begin(); it != tl->end(); ++it) { - int h = (*it)->height(); - if (y >= yy && y < (yy + h)) - break; - yy += h; - } - if (pos[2] - pos[1] > 0 && it != tl->end()) { - Track* track = *it; - switch(track->type()) { - case Track::MIDI: - case Track::DRUM: - { - MidiPart* part = new MidiPart((MidiTrack*)track); - part->setTick(pos[1]); - part->setLenTick(pos[2]-pos[1]); - part->setName(track->name()); - NPart* np = new NPart(part); - items.add(np); - deselectAll(); - part->setSelected(true); - audio->msgAddPart(part); - } - break; - case Track::WAVE: - case Track::AUDIO_OUTPUT: - case Track::AUDIO_INPUT: - case Track::AUDIO_GROUP: - case Track::AUDIO_AUX: - case Track::AUDIO_SOFTSYNTH: - break; - } - } - } - } - -//--------------------------------------------------------- -// startUndo -//--------------------------------------------------------- - -void PartCanvas::startUndo(DragType) - { - song->startUndo(); - } - -//--------------------------------------------------------- -// endUndo -//--------------------------------------------------------- - -void PartCanvas::endUndo(DragType t, int flags) - { - song->endUndo(flags | ((t == MOVE_COPY || t == MOVE_CLONE) - ? SC_PART_INSERTED : SC_PART_MODIFIED)); - } - -//--------------------------------------------------------- -// moveCanvasItems -//--------------------------------------------------------- - -void PartCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtype, int*) -{ - /* - if(editor->parts()->empty()) - return; - - //struct p2c - //{ - // Part* newp; - // int xdiff; - //} - - //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; - - // If this item's part is in the parts2change list, change the item's part to the new part. - //Part* pt = ci->part(); - //iP2C ip2c = parts2change.find(pt); - //if(ip2c != parts2change.end()) - // ci->setPart(ip2c->second); - - int x = ci->pos().x(); - int y = ci->pos().y(); - int nx = x + dx; - int ny = pitch2y(y2pitch(y) + dp); - QPoint newpos = raster(QPoint(nx, ny)); - selectItem(ci, true); - - if(moveItem(ci, newpos, dtype)) - ci->move(newpos); - if(moving.size() == 1) { - itemReleased(curItem, newpos); - } - if(dtype == MOVE_COPY || dtype == MOVE_CLONE) - selectItem(ci, false); - } - - - //if(pflags) - // *pflags = modified; -} - -//--------------------------------------------------------- -// moveItem -// return false, if copy/move not allowed -//--------------------------------------------------------- - -// Changed by T356. -//bool PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragType t, int*) -bool PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragType t) - { - NPart* npart = (NPart*) item; - Part* spart = npart->part(); - Track* track = npart->track(); - unsigned dtick = newpos.x(); - unsigned ntrack = y2pitch(item->mp().y()); - Track::TrackType type = track->type(); - if (tracks->index(track) == ntrack && (dtick == spart->tick())) { - return false; - } - if (ntrack >= tracks->size()) { - ntrack = tracks->size(); - Track* newTrack = song->addTrack(int(type)); - if (type == Track::WAVE) { - WaveTrack* st = (WaveTrack*) track; - WaveTrack* dt = (WaveTrack*) newTrack; - dt->setChannels(st->channels()); - } - emit tracklistChanged(); - } - Track* dtrack = tracks->index(ntrack); - - if (dtrack->type() != type) { - QMessageBox::critical(this, QString("MusE"), - tr("Cannot copy/move/clone to different Track-Type")); - return false; - } - - 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) - { - // This doesn't increment aref count, and doesn't chain clones. - // It also gives the new part a new serial number, but it is - // overwritten with the old one by Song::changePart(), from Audio::msgChangePart() below. - dpart = spart->clone(); - dpart->setTrack(dtrack); - } - else - // 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->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 - // - EventList* se = spart->events(); - EventList* de = dpart->events(); - for (iEvent i = se->begin(); i != se->end(); ++i) { - Event oldEvent = i->second; - Event ev = oldEvent.clone(); - de->add(ev); - } - } - 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); - } - 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); - - 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()); - - if (song->len() < (dpart->lenTick() + dpart->tick())) - song->setLen(dpart->lenTick() + dpart->tick()); - //endUndo(t); - return true; - } - -//--------------------------------------------------------- -// raster -//--------------------------------------------------------- - -QPoint PartCanvas::raster(const QPoint& p) const - { - int y = pitch2y(y2pitch(p.y())); - int x = p.x(); - if (x < 0) - x = 0; - x = AL::sigmap.raster(x, *_raster); - if (x < 0) - x = 0; - return QPoint(x, y); - } - -//--------------------------------------------------------- -// partsChanged -//--------------------------------------------------------- - -void PartCanvas::partsChanged() - { - items.clear(); - int idx = 0; - for (iTrack t = tracks->begin(); t != tracks->end(); ++t) { - PartList* pl = (*t)->parts(); - for (iPart i = pl->begin(); i != pl->end(); ++i) { - NPart* np = new NPart(i->second); - items.add(np); - if (i->second->selected()) { - selectItem(np, true); - } - } - ++idx; - } - redraw(); - } - -//--------------------------------------------------------- -// updateSelection -//--------------------------------------------------------- - -void PartCanvas::updateSelection() - { - for (iCItem i = items.begin(); i != items.end(); ++i) { - NPart* part = (NPart*)(i->second); - part->part()->setSelected(i->second->isSelected()); - } - emit selectionChanged(); - redraw(); - } - -//--------------------------------------------------------- -// resizeItem -//--------------------------------------------------------- - -void PartCanvas::resizeItem(CItem* i, bool noSnap) - { - Track* t = ((NPart*)(i))->track(); - Part* p = ((NPart*)(i))->part(); - - int pos = p->tick() + i->width(); - int snappedpos = p->tick(); - if (!noSnap) { - snappedpos = AL::sigmap.raster(pos, *_raster); - } - unsigned int newwidth = snappedpos - p->tick(); - if (newwidth == 0) - newwidth = AL::sigmap.rasterStep(p->tick(), *_raster); - - song->cmdResizePart(t, p, newwidth); - } - -//--------------------------------------------------------- -// newItem -// first create local Item -//--------------------------------------------------------- - -CItem* PartCanvas::newItem(const QPoint& pos, int) - { - int x = pos.x(); - if (x < 0) - x = 0; - x = AL::sigmap.raster(x, *_raster); - unsigned trackIndex = y2pitch(pos.y()); - if (trackIndex >= tracks->size()) - return 0; - Track* track = tracks->index(trackIndex); - if(!track) - return 0; - - Part* pa = 0; - NPart* np = 0; - switch(track->type()) { - case Track::MIDI: - case Track::DRUM: - pa = new MidiPart((MidiTrack*)track); - pa->setTick(x); - pa->setLenTick(0); - break; - case Track::WAVE: - pa = new WavePart((WaveTrack*)track); - pa->setTick(x); - pa->setLenTick(0); - break; - case Track::AUDIO_OUTPUT: - case Track::AUDIO_INPUT: - case Track::AUDIO_GROUP: - case Track::AUDIO_AUX: - case Track::AUDIO_SOFTSYNTH: - return 0; - } - pa->setName(track->name()); - pa->setColorIndex(curColorIndex); - np = new NPart(pa); - return np; - } - -//--------------------------------------------------------- -// newItem -//--------------------------------------------------------- - -void PartCanvas::newItem(CItem* i, bool noSnap) - { - Part* p = ((NPart*)(i))->part(); - - int len = i->width(); - if (!noSnap) - len = AL::sigmap.raster(len, *_raster); - if (len == 0) - len = AL::sigmap.rasterStep(p->tick(), *_raster); - p->setLenTick(len); - p->setSelected(true); - audio->msgAddPart(p); - } - -//--------------------------------------------------------- -// deleteItem -//--------------------------------------------------------- - -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 - return true; - } - -//--------------------------------------------------------- -// splitItem -//--------------------------------------------------------- - -void PartCanvas::splitItem(CItem* item, const QPoint& pt) - { - NPart* np = (NPart*) item; - Track* t = np->track(); - Part* p = np->part(); - int x = pt.x(); - if (x < 0) - x = 0; - song->cmdSplitPart(t, p, AL::sigmap.raster(x, *_raster)); - } - -//--------------------------------------------------------- -// glueItem -//--------------------------------------------------------- - -void PartCanvas::glueItem(CItem* item) - { - NPart* np = (NPart*) item; - Track* t = np->track(); - Part* p = np->part(); - song->cmdGluePart(t, p); - } - -//--------------------------------------------------------- -// genItemPopup -//--------------------------------------------------------- - -QMenu* PartCanvas::genItemPopup(CItem* item) - { - NPart* npart = (NPart*) item; - Track::TrackType trackType = npart->track()->type(); - - QMenu* partPopup = new QMenu(this); - - QAction *act_cut = partPopup->addAction(*editcutIconSet, tr("C&ut")); - act_cut->setData(4); - act_cut->setShortcut(Qt::CTRL+Qt::Key_X); - - QAction *act_copy = partPopup->addAction(*editcopyIconSet, tr("&Copy")); - act_copy->setData(5); - act_copy->setShortcut(Qt::CTRL+Qt::Key_C); - - partPopup->addSeparator(); - int rc = npart->part()->events()->arefCount(); - QString st = QString(tr("s&elect ")); - if(rc > 1) - st += (QString().setNum(rc) + QString(" ")); - st += QString(tr("clones")); - QAction *act_select = partPopup->addAction(st); - act_select->setData(18); - - partPopup->addSeparator(); - QAction *act_rename = partPopup->addAction(tr("rename")); - act_rename->setData(0); - - 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); - } - - QAction *act_delete = partPopup->addAction(QIcon(*deleteIcon), tr("delete")); // ddskrjo added QIcon to all - act_delete->setData(1); - QAction *act_split = partPopup->addAction(QIcon(*cutIcon), tr("split")); - act_split->setData(2); - QAction *act_glue = partPopup->addAction(QIcon(*glueIcon), tr("glue")); - act_glue->setData(3); - QAction *act_declone = partPopup->addAction(tr("de-clone")); - act_declone->setData(15); - - partPopup->addSeparator(); - switch(trackType) { - case Track::MIDI: { - QAction *act_pianoroll = partPopup->addAction(QIcon(*pianoIconSet), tr("pianoroll")); - act_pianoroll->setData(10); - QAction *act_mlist = partPopup->addAction(QIcon(*edit_listIcon), tr("list")); - act_mlist->setData(12); - QAction *act_mexport = partPopup->addAction(tr("export")); - act_mexport->setData(16); - } - break; - case Track::DRUM: { - QAction *act_dlist = partPopup->addAction(QIcon(*edit_listIcon), tr("list")); - act_dlist->setData(12); - QAction *act_drums = partPopup->addAction(QIcon(*edit_drummsIcon), tr("drums")); - act_drums->setData(13); - QAction *act_dexport = partPopup->addAction(tr("export")); - act_dexport->setData(16); - } - break; - case Track::WAVE: { - QAction *act_wedit = partPopup->addAction(QIcon(*edit_waveIcon), tr("wave edit")); - act_wedit->setData(14); - QAction *act_wexport = partPopup->addAction(tr("export")); - act_wexport->setData(16); - QAction *act_wfinfo = partPopup->addAction(tr("file info")); - act_wfinfo->setData(17); - } - break; - case Track::AUDIO_OUTPUT: - case Track::AUDIO_INPUT: - case Track::AUDIO_GROUP: - case Track::AUDIO_AUX: - case Track::AUDIO_SOFTSYNTH: - break; - } - - act_select->setEnabled( rc > 1); - act_delete->setEnabled( true); - act_cut->setEnabled( true); - act_declone->setEnabled( rc > 1); - - return partPopup; - } - -//--------------------------------------------------------- -// itemPopup -//--------------------------------------------------------- - -void PartCanvas::itemPopup(CItem* item, int n, const QPoint& pt) - { - PartList* pl = new PartList; - NPart* npart = (NPart*)(item); - pl->add(npart->part()); - switch(n) { - case 0: // rename - { - editPart = npart; - QRect r = map(curItem->bbox()); - if (lineEditor == 0) { - lineEditor = new QLineEdit(this); - lineEditor->setFrame(true); - } - lineEditor->setText(editPart->name()); - lineEditor->setFocus(); - lineEditor->show(); - lineEditor->setGeometry(r); - editMode = true; - } - break; - case 1: // delete - deleteItem(item); - break; - case 2: // split - splitItem(item, pt); - break; - case 3: // glue - glueItem(item); - break; - case 4: - copy(pl); - audio->msgRemovePart(npart->part()); - break; - case 5: - copy(pl); - break; - case 10: // pianoroll edit - emit startEditor(pl, 0); - return; - case 12: // list edit - emit startEditor(pl, 1); - return; - case 13: // drum edit - emit startEditor(pl, 3); - return; - 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(); - for (iEvent i = se->begin(); i != se->end(); ++i) { - Event oldEvent = i->second; - 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); - 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); - fclose(fp); - } - } - break; - } - - case 17: // File info - { - Part* p = item->part(); - EventList* el = p->events(); - QString str = tr("Part name") + ": " + p->name() + "\n" + tr("Files") + ":"; - for (iEvent e = el->begin(); e != el->end(); ++e) - { - Event event = e->second; - 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()); - } - QMessageBox::information(this, "File info", str, "Ok", 0); - break; - } - case 18: // Select clones - { - Part* part = item->part(); - - // Traverse and process the clone chain ring until we arrive at the same part again. - // The loop is a safety net. - Part* p = part; - int j = part->cevents()->arefCount(); - if(j > 0) - { - 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); - } - - break; - } - case 20 ... NUM_PARTCOLORS+20: - { - curColorIndex = n - 20; - bool selfound = false; - //Loop through all parts and set color on selected: - for (iCItem i = items.begin(); i != items.end(); i++) { - if (i->second->isSelected()) { - selfound = true; - i->second->part()->setColorIndex(curColorIndex); - } - } - - // If no items selected, use the one clicked on. - if(!selfound) - item->part()->setColorIndex(curColorIndex); - - redraw(); - break; - } - default: - printf("unknown action %d\n", n); - break; - } - delete pl; - } - -//--------------------------------------------------------- -// viewMousePressEvent -//--------------------------------------------------------- - -void PartCanvas::mousePress(QMouseEvent* event) - { - if (event->modifiers() & Qt::ShiftModifier) { - return; - } - QPoint pt = event->pos(); - CItem* item = items.find(pt); - if (item == 0) - return; - switch (_tool) { - default: - emit trackChanged(item->part()->track()); - break; - case CutTool: - splitItem(item, pt); - break; - case GlueTool: - glueItem(item); - break; - case MuteTool: - { - NPart* np = (NPart*) item; - Part* p = np->part(); - p->setMute(!p->mute()); - redraw(); - break; - } - } - } - -//--------------------------------------------------------- -// viewMouseReleaseEvent -//--------------------------------------------------------- - -void PartCanvas::mouseRelease(const QPoint&) - { - } - -//--------------------------------------------------------- -// viewMouseMoveEvent -//--------------------------------------------------------- - -void PartCanvas::mouseMove(const QPoint& pos) - { - int x = pos.x(); - if (x < 0) - x = 0; - emit timeChanged(AL::sigmap.raster(x, *_raster)); - } - -//--------------------------------------------------------- -// y2Track -//--------------------------------------------------------- - -Track* PartCanvas::y2Track(int y) const - { - TrackList* l = song->tracks(); - int ty = 0; - for (iTrack it = l->begin(); it != l->end(); ++it) { - int h = (*it)->height(); - if (y >= ty && y < ty + h) - return *it; - ty += h; - } - return 0; - } - -//--------------------------------------------------------- -// keyPress -//--------------------------------------------------------- - -void PartCanvas::keyPress(QKeyEvent* event) - { - int key = event->key(); - if (editMode) - { - if ( key == Qt::Key_Return || key == Qt::Key_Enter ) - { - returnPressed(); - return; - } - else if ( key == Qt::Key_Escape ) - { - lineEditor->hide(); - editMode = false; - return; - } - } - - if (event->modifiers() & Qt::ShiftModifier) - key += Qt::SHIFT; - if (event->modifiers() & Qt::AltModifier) - key += Qt::ALT; - if (event->modifiers() & Qt::ControlModifier) - key += Qt::CTRL; - - if (key == shortcuts[SHRT_DELETE].key) { - if (getCurrentDrag()) { - //printf("dragging!!\n"); - return; - } - - song->startUndo(); - song->msgRemoveParts(); - song->endUndo(SC_PART_REMOVED); - return; - } - else if (key == shortcuts[SHRT_POS_DEC].key) { - int spos = pos[0]; - if(spos > 0) - { - spos -= 1; // Nudge by -1, then snap down with raster1. - spos = AL::sigmap.raster1(spos, *_raster); - } - if(spos < 0) - spos = 0; - Pos p(spos,true); - song->setPos(0, p, true, true, true); - return; - } - else if (key == shortcuts[SHRT_POS_INC].key) { - int spos = AL::sigmap.raster2(pos[0] + 1, *_raster); // Nudge by +1, then snap up with raster2. - Pos p(spos,true); - song->setPos(0, p, true, true, true); - return; - } - else if (key == shortcuts[SHRT_POS_DEC_NOSNAP].key) { - int spos = pos[0] - AL::sigmap.rasterStep(pos[0], *_raster); - if(spos < 0) - spos = 0; - Pos p(spos,true); - song->setPos(0, p, true, true, true); - return; - } - else if (key == shortcuts[SHRT_POS_INC_NOSNAP].key) { - Pos p(pos[0] + AL::sigmap.rasterStep(pos[0], *_raster), true); - song->setPos(0, p, true, true, true); - return; - } - else if (key == shortcuts[SHRT_TOOL_POINTER].key) { - emit setUsedTool(PointerTool); - return; - } - else if (key == shortcuts[SHRT_TOOL_PENCIL].key) { - emit setUsedTool(PencilTool); - return; - } - else if (key == shortcuts[SHRT_TOOL_RUBBER].key) { - emit setUsedTool(RubberTool); - return; - } - else if (key == shortcuts[SHRT_TOOL_SCISSORS].key) { - emit setUsedTool(CutTool); - return; - } - else if (key == shortcuts[SHRT_TOOL_GLUE].key) { - emit setUsedTool(GlueTool); - return; - } - else if (key == shortcuts[SHRT_TOOL_MUTE].key) { - emit setUsedTool(MuteTool); - return; - } - else if (key == shortcuts[SHRT_SEL_TRACK_ABOVE].key) { - emit selectTrackAbove(); - return; - } - else if (key == shortcuts[SHRT_SEL_TRACK_BELOW].key) { - emit selectTrackBelow(); - return; - } - - // - // Shortcuts that require selected parts from here - // - if (!curItem) { - if (items.size()==0) { - event->ignore(); // give global accelerators a chance - return; - } - for (iCItem i = items.begin(); i != items.end(); ++i) { - NPart* part = (NPart*)(i->second); - if (part->isSelected()) { - curItem=part; - break; - } - } - if (!curItem) - curItem = (NPart*)items.begin()->second; // just grab the first part - } - - CItem* newItem = 0; - bool singleSelection = isSingleSelection(); - bool add = false; - //Locators to selection - if (key == shortcuts[SHRT_LOCATORS_TO_SELECTION].key) { - CItem *leftmost = 0, *rightmost = 0; - for (iCItem i = items.begin(); i != items.end(); i++) { - if (i->second->isSelected()) { - // Check leftmost: - if (!leftmost) - leftmost = i->second; - else - if (leftmost->x() > i->second->x()) - leftmost = i->second; - - // Check rightmost: - if (!rightmost) - rightmost = i->second; - else - if (rightmost->x() < i->second->x()) - rightmost = i->second; - } - } - - int left_tick = leftmost->part()->tick(); - int right_tick = rightmost->part()->tick() + rightmost->part()->lenTick(); - Pos p1(left_tick, true); - Pos p2(right_tick, true); - song->setPos(1, p1); - song->setPos(2, p2); - return; - } - - // Select part to the right - else if (key == shortcuts[SHRT_SEL_RIGHT].key || key == shortcuts[SHRT_SEL_RIGHT_ADD].key) { - if (key == shortcuts[SHRT_SEL_RIGHT_ADD].key) - add = true; - - Part* part = curItem->part(); - Track* track = part->track(); - unsigned int tick = part->tick(); - bool afterthis = false; - for (iCItem i = items.begin(); i != items.end(); ++i) { - NPart* npart = (NPart*)(i->second); - Part* ipart = npart->part(); - if (ipart->track() != track) - continue; - if (ipart->tick() < tick) - continue; - if (ipart == part) - { - afterthis = true; - continue; - } - if(afterthis) - { - newItem = i->second; - break; - } - } - } - // Select part to the left - else if (key == shortcuts[SHRT_SEL_LEFT].key || key == shortcuts[SHRT_SEL_LEFT_ADD].key) { - if (key == shortcuts[SHRT_SEL_LEFT_ADD].key) - add = true; - - Part* part = curItem->part(); - Track* track = part->track(); - unsigned int tick = part->tick(); - - for (iCItem i = items.begin(); i != items.end(); ++i) { - NPart* npart = (NPart*)(i->second); - Part* ipart = npart->part(); - - if (ipart->track() != track) - continue; - if (ipart->tick() > tick) - continue; - if (ipart == part) - break; - newItem = i->second; - } - } - - // Select nearest part on track above - else if (key == shortcuts[SHRT_SEL_ABOVE].key || key == shortcuts[SHRT_SEL_ABOVE_ADD].key) { - if (key == shortcuts[SHRT_SEL_ABOVE_ADD].key) - add = true; - //To get an idea of which track is above us: - int stepsize = rmapxDev(1); - Track* track = curItem->part()->track();//top->part()->track(); - track = y2Track(track->y() - 1); - - //If we're at topmost, leave - if (!track) { - printf("no track above!\n"); - return; - } - int middle = curItem->x() + curItem->part()->lenTick()/2; - CItem *aboveL = 0, *aboveR = 0; - //Upper limit: song end, lower limit: song start - int ulimit = song->len(); - int llimit = 0; - - while (newItem == 0) { - int y = track->y() + 2; - int xoffset = 0; - int xleft = middle - xoffset; - int xright = middle + xoffset; - while ((xleft > llimit || xright < ulimit) && (aboveL == 0) && (aboveR == 0)) { - xoffset += stepsize; - xleft = middle - xoffset; - xright = middle + xoffset; - if (xleft >= 0) - aboveL = items.find(QPoint(xleft,y)); - if (xright <= ulimit) - aboveR = items.find(QPoint(xright,y)); - } - - if ((aboveL || aboveR) != 0) { //We've hit something - CItem* above = 0; - above = (aboveL !=0) ? aboveL : aboveR; - newItem = above; - } - else { //We didn't hit anything. Move to track above, if there is one - track = y2Track(track->y() - 1); - if (track == 0) - return; - } - } - emit trackChanged(track); - } - // Select nearest part on track below - else if (key == shortcuts[SHRT_SEL_BELOW].key || key == shortcuts[SHRT_SEL_BELOW_ADD].key) { - if (key == shortcuts[SHRT_SEL_BELOW_ADD].key) - add = true; - - //To get an idea of which track is below us: - int stepsize = rmapxDev(1); - Track* track = curItem->part()->track();//bottom->part()->track(); - track = y2Track(track->y() + track->height() + 1 ); - int middle = curItem->x() + curItem->part()->lenTick()/2; - //If we're at bottommost, leave - if (!track) - return; - - CItem *belowL = 0, *belowR = 0; - //Upper limit: song end , lower limit: song start - int ulimit = song->len(); - int llimit = 0; - while (newItem == 0) { - int y = track->y() + 1; - int xoffset = 0; - int xleft = middle - xoffset; - int xright = middle + xoffset; - while ((xleft > llimit || xright < ulimit) && (belowL == 0) && (belowR == 0)) { - xoffset += stepsize; - xleft = middle - xoffset; - xright = middle + xoffset; - if (xleft >= 0) - belowL = items.find(QPoint(xleft,y)); - if (xright <= ulimit) - belowR = items.find(QPoint(xright,y)); - } - - if ((belowL || belowR) != 0) { //We've hit something - CItem* below = 0; - below = (belowL !=0) ? belowL : belowR; - newItem = below; - } - else { - //Get next track below, or abort if this is the lowest - track = y2Track(track->y() + track->height() + 1 ); - if (track == 0) - return; - } - } - emit trackChanged(track); - } - else if (key == shortcuts[SHRT_EDIT_PART].key && curItem) { //This should be the other way around - singleSelection first. - if (!singleSelection) { - event->ignore(); - return; - } - PartList* pl = new PartList; - NPart* npart = (NPart*)(curItem); - Track* track = npart->part()->track(); - pl->add(npart->part()); - int type = 0; - - // Check if track is wave or drum, - // else track is midi - - switch (track->type()) { - case Track::DRUM: - type = 3; - break; - - case Track::WAVE: - type = 4; - break; - - case Track::MIDI: - case Track::AUDIO_OUTPUT: - case Track::AUDIO_INPUT: - case Track::AUDIO_GROUP: - case Track::AUDIO_AUX: - case Track::AUDIO_SOFTSYNTH: //TODO - break; - } - emit startEditor(pl, type); - } - else { - event->ignore(); // give global accelerators a chance - return; - } - - - // Check if anything happened to the selected parts - if (newItem) { - //If this is a single selection, toggle previous item - if (singleSelection && !add) - selectItem(curItem, false); - else if(!add) - deselectAll(); - - curItem = newItem; - selectItem(newItem, true); - - //Check if we've hit the upper or lower boundaries of the window. If so, set a new position - if (newItem->x() < mapxDev(0)) { - int curpos = pos[0]; - setPos(0,newItem->x(),true); - setPos(0,curpos,false); //Dummy to put the current position back once we've scrolled - } - else if (newItem->x() > mapxDev(width())) { - int curpos = pos[0]; - setPos(0,newItem->x(),true); - setPos(0,curpos,false); //Dummy to put the current position back once we've scrolled - } - redraw(); - } - } - -//--------------------------------------------------------- -// drawPart -// draws a part -//--------------------------------------------------------- - -void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect) - { - int from = rect.x(); - int to = from + rect.width(); - - //printf("from %d to %d\n", from,to); - Part* part = ((NPart*)item)->part(); - int pTick = part->tick(); - from -= pTick; - to -= pTick; - if(from < 0) - from = 0; - if((unsigned int)to > part->lenTick()) - to = part->lenTick(); - - // Item bounding box x is in tick coordinates, same as rectangle. - if(item->bbox().intersect(rect).isNull()) - { - //printf("PartCanvas::drawItem rectangle is null\n"); - return; - } - - 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()) { - QColor c(Qt::white); - c.setAlpha(config.globalAlphaBlend); - p.setBrush(c); - - // 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; - } - if (item->isMoving()) { - QColor c(Qt::gray); - c.setAlpha(config.globalAlphaBlend); - p.setBrush(c); - - // 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; - - // NOTE: For one-pixel border use first line and don't bother with setCosmetic. - // For a two-pixel border use second line and MUST use setCosmetic! Tim. - //p.setPen(QPen(config.partColors[i], 0, clone ? Qt::DashLine : Qt::SolidLine)); - QPen pen(config.partColors[i], 2, clone ? Qt::DashLine : Qt::SolidLine); - pen.setCosmetic(true); - - p.setPen(pen); - // Hm, put some kind of lower limit? If so do that globally to the adjustment. - QColor c(Qt::black); - c.setAlpha(config.globalAlphaBlend); - p.setBrush(c); - p.drawRect(r); - } - else { - bool clone = part->events()->arefCount() > 1; - - // NOTE: Pixel width: See above note. - //p.setPen(QPen(Qt::black, 0, clone ? Qt::DashLine : Qt::SolidLine)); - QPen pen(Qt::black, 2, clone ? Qt::DashLine : Qt::SolidLine); - pen.setCosmetic(true); - - p.setPen(pen); - QColor c(config.partColors[i]); - c.setAlpha(config.globalAlphaBlend); - p.setBrush(c); - - p.drawRect(r); - } - - MidiPart* mp = 0; - WavePart* wp = 0; - Track::TrackType type = part->track()->type(); - if (type == Track::WAVE) { - wp =(WavePart*)part; - } - else { - mp = (MidiPart*)part; - } - - if (config.canvasShowPartType & 2) { // show events - if (mp) - { - // Do not allow this, causes segfault. - if(from <= to) - { - p.setPen(Qt::darkGray); - EventList* events = mp->events(); - iEvent ito(events->lower_bound(to)); - - for (iEvent i = events->lower_bound(from); i != ito; ++i) { - EventType type = i->second.type(); - if ( - ((config.canvasShowPartEvent & 1) && (type == Note)) - || ((config.canvasShowPartEvent & 2) && (type == PAfter)) - || ((config.canvasShowPartEvent & 4) && (type == Controller)) - || ((config.canvasShowPartEvent &16) && (type == CAfter)) - || ((config.canvasShowPartEvent &64) && (type == Sysex || type == Meta)) - ) { - int t = i->first + pTick; - int th = part->track()->height(); - if(t >= r.left() && t <= r.right()) - p.drawLine(t, r.y()+2, t, r.y()+th-4); - } - } - } - } - else if (wp) - drawWavePart(p, rect, wp, r); - } - - else { // show Cakewalk Style - if (mp) { - p.setPen(Qt::darkGray); - EventList* events = mp->events(); - iEvent ito(events->lower_bound(to)); - //printf("PartCanvas::drawItem pTick:%d from:%d to:%d part len:%d\n", pTick, from, to, part->lenTick()); - - for (iEvent i = events->begin(); i != ito; ++i) { - int t = i->first + pTick; - int te = t + i->second.lenTick(); - - if (t > (to + pTick)) - { - printf("PartCanvas::drawItem t:%d > to:%d + pTick:%d i->first:%d\n", t, to, pTick, i->first); - - break; - } - - if (te < (from + pTick)) - continue; - - if (te > (to + pTick)) - te = to + pTick; - - EventType type = i->second.type(); - if (type == Note) { - int pitch = i->second.pitch(); - int th = int(part->track()->height() * 0.75); // only draw on three quarters - int hoffset = (part->track()->height() - th ) / 2; // offset from bottom - int y = hoffset + (r.y() + th - (pitch * (th) / 127)); - p.drawLine(t, y, te, y); - } - } - } - else if (wp) - drawWavePart(p, rect, wp, r); - } - if (config.canvasShowPartType & 1) { // show names - // draw name - // FN: Set text color depending on part color (black / white) - int part_r, part_g, part_b, brightness; - config.partColors[i].getRgb(&part_r, &part_g, &part_b); - brightness = part_r*29 + part_g*59 + part_b*12; - if (brightness < 12000 || part->selected()) - p.setPen(Qt::white); /* too dark: use white for text color */ - else - p.setPen(Qt::black); /* otherwise use black */ - QRect rr = map(r); - rr.setX(rr.x() + 3); - p.save(); - p.setFont(config.fonts[1]); - p.setWorldMatrixEnabled(false); - p.drawText(rr, Qt::AlignVCenter|Qt::AlignLeft, part->name()); - p.restore(); - } - } - -//--------------------------------------------------------- -// drawMoving -// draws moving items -//--------------------------------------------------------- - -void PartCanvas::drawMoving(QPainter& p, const CItem* item, const QRect&) - { - //if(!item->isMoving()) - // return; - p.setPen( Qt::black); - - //p.setBrush( Qt::NoBrush); - //QColor c(Qt::gray); - Part* part = ((NPart*)item)->part(); - QColor c(config.partColors[part->colorIndex()]); - - ///c.setAlpha(config.globalAlphaBlend); - c.setAlpha(128); // Fix this regardless of global setting. Should be OK. - - p.setBrush(c); - - // NOTE: For one-pixel border use second line. For two-pixel border use first. - //p.drawRect(item->mp().x(), item->mp().y()+1, item->width(), item->height()); - p.drawRect(item->mp().x(), item->mp().y(), item->width(), item->height()); - } - -//--------------------------------------------------------- -// drawWavePart -// bb - bounding box of paint area -// pr - part rectangle -//--------------------------------------------------------- - -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); - - p.save(); - p.resetTransform(); - - int x2 = 1; - int x1 = rr.x() > pr.x() ? rr.x() : pr.x(); - x2 += rr.right() < pr.right() ? rr.right() : pr.right(); - - if (x1 < 0) - x1 = 0; - if (x2 > width()) - x2 = width(); - int hh = pr.height(); - int h = hh/2; - int y = pr.y() + h; - - EventList* el = wp->events(); - for (iEvent e = el->begin(); e != el->end(); ++e) { - int cc = hh % 2 ? 0 : 1; - Event event = e->second; - SndFileR f = event.sndFile(); - if (f.isNull()) - continue; - unsigned channels = f.channels(); - if (channels == 0) { - printf("drawWavePart: channels==0! %s\n", f.name().toLatin1().constData()); - continue; - } - - int xScale; - int pos; - int tickstep = rmapxDev(1); - int postick = tempomap.frame2tick(wp->frame() + event.frame()); - int eventx = mapx(postick); - int drawoffset; - if((x1 - eventx) < 0) - drawoffset = 0; - else - drawoffset = rmapxDev(x1 - eventx); - postick += drawoffset; - pos = event.spos() + tempomap.tick2frame(postick) - wp->frame() - event.frame(); - - int i; - if(x1 < eventx) - i = eventx; - else - i = x1; - int ex = mapx(tempomap.frame2tick(wp->frame() + event.frame() + event.lenFrame())); - if(ex > x2) - ex = x2; - if (h < 20) { - // - // combine multi channels into one waveform - // - //printf("PartCanvas::drawWavePart i:%d ex:%d\n", i, ex); // REMOVE Tim. - - for (; i < ex; i++) { - SampleV sa[channels]; - xScale = tempomap.deltaTick2frame(postick, postick + tickstep); - f.read(sa, xScale, pos); - postick += tickstep; - pos += xScale; - int peak = 0; - int rms = 0; - for (unsigned k = 0; k < channels; ++k) { - if (sa[k].peak > peak) - peak = sa[k].peak; - rms += sa[k].rms; - } - rms /= channels; - peak = (peak * (hh-2)) >> 9; - rms = (rms * (hh-2)) >> 9; - p.setPen(QColor(Qt::darkGray)); - p.drawLine(i, y - peak - cc, i, y + peak); - p.setPen(QColor(Qt::black)); - p.drawLine(i, y - rms - cc, i, y + rms); - } - } - else { - // - // multi channel display - // - int hm = hh / (channels * 2); - int cc = hh % (channels * 2) ? 0 : 1; - for (; i < ex; i++) { - y = pr.y() + hm; - SampleV sa[channels]; - xScale = tempomap.deltaTick2frame(postick, postick + tickstep); - f.read(sa, xScale, pos); - postick += tickstep; - pos += xScale; - for (unsigned k = 0; k < channels; ++k) { - int peak = (sa[k].peak * (hm - 1)) >> 8; - int rms = (sa[k].rms * (hm - 1)) >> 8; - p.setPen(QColor(Qt::darkGray)); - p.drawLine(i, y - peak - cc, i, y + peak); - p.setPen(QColor(Qt::black)); - p.drawLine(i, y - rms - cc, i, y + rms); - - y += 2 * hm; - } - } - } - } - p.restore(); - } -//--------------------------------------------------------- -// cmd -//--------------------------------------------------------- - -void PartCanvas::cmd(int cmd) - { - PartList pl; - for (iCItem i = items.begin(); i != items.end(); ++i) { - if (!i->second->isSelected()) - continue; - NPart* npart = (NPart*)(i->second); - pl.add(npart->part()); - } - 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); - break; - case CMD_COPY_PART: - copy(&pl); - break; - case CMD_PASTE_PART: - paste(false, false); - break; - case CMD_PASTE_CLONE_PART: - paste(true, false); - break; - case CMD_PASTE_PART_TO_TRACK: - paste(); - break; - case CMD_PASTE_CLONE_PART_TO_TRACK: - paste(true); - break; - case CMD_INSERT_PART: - 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); - break; - } - } - -//--------------------------------------------------------- -// copy -// cut copy paste -//--------------------------------------------------------- - -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) - { - if(p->second->track()->isMidiTrack()) - midi = true; - else - if(p->second->track()->type() == Track::WAVE) - wave = true; - if(midi && wave) - break; - } - if(!(midi || wave)) - return; - - //--------------------------------------------------- - // write parts as XML into tmp file - //--------------------------------------------------- - - FILE* tmp = tmpfile(); - if (tmp == 0) { - fprintf(stderr, "PartCanvas::copy() fopen failed: %s\n", - strerror(errno)); - return; - } - Xml xml(tmp); - - // 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(); - if (endTick > tick) - tick = endTick; - } - Pos p(tick, true); - song->setPos(0, p); - - //--------------------------------------------------- - // read tmp file into QTextDrag Object - //--------------------------------------------------- - - fflush(tmp); - struct stat f_stat; - if (fstat(fileno(tmp), &f_stat) == -1) { - fprintf(stderr, "PartCanvas::copy() fstat failed:<%s>\n", - strerror(errno)); - fclose(tmp); - return; - } - int n = f_stat.st_size; - char* fbuf = (char*)mmap(0, n+1, PROT_READ|PROT_WRITE, - MAP_PRIVATE, fileno(tmp), 0); - fbuf[n] = 0; - - QByteArray data(fbuf); - QMimeData* md = new QMimeData(); - - - if(midi && wave) - md->setData("text/x-muse-mixedpartlist", data); // By T356. Support mixed .mpt files. - else - if(midi) - md->setData("text/x-muse-midipartlist", data); - else - if(wave) - md->setData("text/x-muse-wavepartlist", data); - - QApplication::clipboard()->setMimeData(md, QClipboard::Clipboard); - - munmap(fbuf, n); - fclose(tmp); - } - -//--------------------------------------------------------- -// pasteAt -//--------------------------------------------------------- - -int PartCanvas::pasteAt(const QString& pt, Track* track, unsigned int pos, bool clone, bool toTrack) - { - //printf("int PartCanvas::pasteAt(const QString& pt, Track* track, int pos)\n"); - 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(); - switch (token) { - case Xml::Error: - case Xml::End: - 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); - } - */ - - // Read the part. - Part* p = 0; - p = readXmlPart(xml, track, clone, toTrack); - // If it could not be created... - if(!p) - { - // Increment the number of parts not done and break. - ++notDone; - break; - } - - // Increment the number of parts done. - ++done; - - if (firstPart) { - firstPart=false; - posOffset=pos-p->tick(); - } - p->setTick(p->tick()+posOffset); - if (p->tick()+p->lenTick()>finalPos) { - finalPos=p->tick()+p->lenTick(); - } - //pos += p->lenTick(); - audio->msgAddPart(p,false); - } - else - xml.unknown("PartCanvas::pasteAt"); - break; - case Xml::TagEnd: - break; - default: - end = true; - break; - } - if(end) - break; - } - - //song->endUndo(SC_PART_INSERTED); - //return pos; - - if(notDone) - { - int tot = notDone + done; - QMessageBox::critical(this, QString("MusE"), - QString().setNum(notDone) + (tot > 1 ? (tr(" out of ") + QString().setNum(tot)) : QString("")) + - (tot > 1 ? tr(" parts") : tr(" part")) + - tr(" could not be pasted.\nLikely the selected track is the wrong type.")); - } - - return finalPos; - } - -/* -//--------------------------------------------------------- -// 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; - - if (doInsert) // logic depends on keeping track of newly selected tracks - deselectAll(); - - - // If we want to paste to a selected track... - if(toTrack) - { - TrackList* tl = song->tracks(); - for (iTrack i = tl->begin(); i != tl->end(); ++i) { - if ((*i)->selected()) { - if (track) { - QMessageBox::critical(this, QString("MusE"), - tr("Cannot paste: multiple tracks selected")); - return; - } - else - track = *i; - } - } - if (track == 0) { - QMessageBox::critical(this, QString("MusE"), - tr("Cannot paste: no track selected")); - return; - } - } - - QClipboard* cb = QApplication::clipboard(); - const QMimeData* md = cb->mimeData(QClipboard::Clipboard); - - QString pfx("text/"); - QString mdpl("x-muse-midipartlist"); - QString wvpl("x-muse-wavepartlist"); - QString mxpl("x-muse-mixedpartlist"); - QString txt; - - if(md->hasFormat(pfx + mdpl)) - { - // If we want to paste to a selected track... - if(toTrack && !track->isMidiTrack()) - { - QMessageBox::critical(this, QString("MusE"), - tr("Can only paste to midi/drum track")); - return; - } - txt = cb->text(mdpl, QClipboard::Clipboard); - } - else - if(md->hasFormat(pfx + wvpl)) - { - // If we want to paste to a selected track... - if(toTrack && track->type() != Track::WAVE) - { - QMessageBox::critical(this, QString("MusE"), - tr("Can only paste to wave track")); - return; - } - txt = cb->text(wvpl, QClipboard::Clipboard); - } - else - if(md->hasFormat(pfx + mxpl)) - { - // If we want to paste to a selected track... - if(toTrack && !track->isMidiTrack() && track->type() != Track::WAVE) - { - QMessageBox::critical(this, QString("MusE"), - tr("Can only paste to midi or wave track")); - return; - } - txt = cb->text(mxpl, QClipboard::Clipboard); - } - else - { - QMessageBox::critical(this, QString("MusE"), - tr("Cannot paste: wrong data type")); - return; - } - - int endPos=0; - unsigned int startPos=song->vcpos(); - if (!txt.isEmpty()) - { - song->startUndo(); - endPos=pasteAt(txt, track, startPos, clone, toTrack); - Pos p(endPos, true); - song->setPos(0, p); - if (!doInsert) - song->endUndo(SC_PART_INSERTED); - } - - if (doInsert) { - int offset = endPos-startPos; - movePartsTotheRight(startPos, offset); - song->endUndo(SC_PART_INSERTED); - } - } - -//--------------------------------------------------------- -// movePartsToTheRight -//--------------------------------------------------------- -void PartCanvas::movePartsTotheRight(unsigned int startTicks, int length) -{ - // 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); - } - - } - } - } - // perhaps ask if markers should be moved? - MarkerList *markerlist = song->marker(); - for(iMarker i = markerlist->begin(); i != markerlist->end(); ++i) - { - Marker* m = &i->second; - if (m->tick() >= startTicks) { - Marker *oldMarker = new Marker(); - *oldMarker = *m; - m->setTick(m->tick()+length); - song->undoOp(UndoOp::ModifyMarker,oldMarker, m); - } - } -} -//--------------------------------------------------------- -// startDrag -//--------------------------------------------------------- - -void PartCanvas::startDrag(CItem* item, DragType t) - { - //printf("PartCanvas::startDrag(CItem* item, DragType t)\n"); - NPart* p = (NPart*)(item); - Part* part = p->part(); - - //--------------------------------------------------- - // write part as XML into tmp file - //--------------------------------------------------- - - FILE* tmp = tmpfile(); - if (tmp == 0) { - fprintf(stderr, "PartCanvas::startDrag() fopen failed: %s\n", - strerror(errno)); - return; - } - Xml xml(tmp); - int level = 0; - part->write(level, xml); - - //--------------------------------------------------- - // read tmp file into QTextDrag Object - //--------------------------------------------------- - - fflush(tmp); - struct stat f_stat; - if (fstat(fileno(tmp), &f_stat) == -1) { - fprintf(stderr, "PartCanvas::startDrag fstat failed:<%s>\n", - strerror(errno)); - fclose(tmp); - return; - } - int n = f_stat.st_size + 1; - char* fbuf = (char*)mmap(0, n, PROT_READ|PROT_WRITE, - MAP_PRIVATE, fileno(tmp), 0); - fbuf[n] = 0; - - QByteArray data(fbuf); - QMimeData* md = new QMimeData(); - - md->setData("text/x-muse-partlist", data); - - // "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. " - QDrag* drag = new QDrag(this); - drag->setMimeData(md); - - if (t == MOVE_COPY || t == MOVE_CLONE) - drag->exec(Qt::CopyAction); - else - drag->exec(Qt::MoveAction); - - munmap(fbuf, n); - fclose(tmp); - } - -//--------------------------------------------------------- -// dragEnterEvent -//--------------------------------------------------------- - -void PartCanvas::dragEnterEvent(QDragEnterEvent* event) - { - ///event->accept(Q3TextDrag::canDecode(event)); - event->acceptProposedAction(); // TODO CHECK Tim. - } - -//--------------------------------------------------------- -// dragMoveEvent -//--------------------------------------------------------- - -void PartCanvas::dragMoveEvent(QDragMoveEvent*) - { -// printf("drag move %x\n", this); - //event->acceptProposedAction(); - } - -//--------------------------------------------------------- -// dragLeaveEvent -//--------------------------------------------------------- - -void PartCanvas::dragLeaveEvent(QDragLeaveEvent*) - { -// printf("drag leave\n"); - //event->acceptProposedAction(); - } - -//--------------------------------------------------------- -// dropEvent -//--------------------------------------------------------- - -void PartCanvas::viewDropEvent(QDropEvent* event) - { - //printf("void PartCanvas::viewDropEvent(QDropEvent* event)\n"); - if (event->source() == this) { - printf("local DROP\n"); - //event->ignore(); // TODO CHECK Tim. - return; - } - int type = 0; // 0 = unknown, 1 = partlist, 2 = uri-list - QString text; - - if(event->mimeData()->hasFormat("text/partlist")) - type = 1; - else - //if(event->mimeData()->hasFormat("text/uri-list")) - if(event->mimeData()->hasUrls()) - type = 2; - else - { - if(debugMsg && event->mimeData()->formats().size() != 0) - printf("Drop with unknown format. First format:<%s>\n", event->mimeData()->formats()[0].toLatin1().constData()); - //event->ignore(); // TODO CHECK Tim. - return; - } - - // Make a backup of the current clone list, to retain any 'copy' items, - // so that pasting works properly after. - CloneList copyCloneList = cloneList; - // Clear the clone list to prevent any dangerous associations with - // current non-original parts. - cloneList.clear(); - - if (type == 1) - { - text = QString(event->mimeData()->data("text/partlist")); - - int x = AL::sigmap.raster(event->pos().x(), *_raster); - if (x < 0) - x = 0; - unsigned trackNo = y2pitch(event->pos().y()); - Track* track = 0; - if (trackNo < tracks->size()) - track = tracks->index(trackNo); - if (track) { - song->startUndo(); - pasteAt(text, track, x); - song->endUndo(SC_PART_INSERTED); - } - } - else if (type == 2) - { - // Multiple urls not supported here. Grab the first one. - text = event->mimeData()->urls()[0].path(); - - if (text.endsWith(".wav",Qt::CaseInsensitive) || - text.endsWith(".ogg",Qt::CaseInsensitive) || - text.endsWith(".mpt", Qt::CaseInsensitive) ) - { - int x = AL::sigmap.raster(event->pos().x(), *_raster); - if (x < 0) - x = 0; - unsigned trackNo = y2pitch(event->pos().y()); - Track* track = 0; - if (trackNo < tracks->size()) - track = tracks->index(trackNo); - if (track) - { - if (track->type() == Track::WAVE && - (text.endsWith(".wav", Qt::CaseInsensitive) || - (text.endsWith(".ogg", Qt::CaseInsensitive)))) - { - unsigned tick = x; - muse->importWaveToTrack(text, tick, track); - } - // Changed by T356. Support mixed .mpt files. - else if ((track->isMidiTrack() || track->type() == Track::WAVE) && text.endsWith(".mpt", Qt::CaseInsensitive)) - { - unsigned tick = x; - muse->importPartToTrack(text, tick, track); - } - } - } - else if(text.endsWith(".med",Qt::CaseInsensitive)) - { - emit dropSongFile(text); - } - else if(text.endsWith(".mid",Qt::CaseInsensitive)) - { - emit dropMidiFile(text); - } - else - { - printf("dropped... something... no hable...\n"); - } - } - - // Restore backup of the clone list, to retain any 'copy' items, - // so that pasting works properly after. - cloneList.clear(); - cloneList = copyCloneList; - } - -//--------------------------------------------------------- -// drawCanvas -//--------------------------------------------------------- - -void PartCanvas::drawCanvas(QPainter& p, const QRect& rect) -{ - int x = rect.x(); - int y = rect.y(); - int w = rect.width(); - int h = rect.height(); - - ////////// - // GRID // - ////////// - QColor baseColor(config.partCanvasBg.light(104)); - p.setPen(baseColor); - - //-------------------------------- - // vertical lines - //------------------------------- - //printf("raster=%d\n", *_raster); - if (config.canvasShowGrid) { - int bar, beat; - unsigned tick; - - AL::sigmap.tickValues(x, &bar, &beat, &tick); - for (;;) { - int xt = AL::sigmap.bar2tick(bar++, 0, 0); - if (xt >= x + w) - break; - if (!((bar-1) % 4)) - p.setPen(baseColor.dark(115)); - else - p.setPen(baseColor); - p.drawLine(xt, y, xt, y+h); - - // append - int noDivisors=0; - if (*_raster == config.division *2) // 1/2 - noDivisors=2; - else if (*_raster== config.division) // 1/4 - noDivisors=4; - else if (*_raster==config.division/2) // 1/8 - noDivisors=8; - else if (*_raster==config.division/4) // 1/16 - noDivisors=16; - else if (*_raster==config.division/8) // 1/16 - noDivisors=32; - else if (*_raster==config.division/16) // 1/16 - noDivisors=64; - - int r = *_raster; - int rr = rmapx(r); - if (*_raster > 1) { - while (rr < 4) { - r *= 2; - rr = rmapx(r); - noDivisors=noDivisors/2; - } - p.setPen(baseColor); - for (int t=1;t< noDivisors;t++) - p.drawLine(xt+r*t, y, xt+r*t, y+h); - } - } - } - //-------------------------------- - // horizontal lines - //-------------------------------- - - TrackList* tl = song->tracks(); - int yy = 0; - int th; - for (iTrack it = tl->begin(); it != tl->end(); ++it) { - if (yy > y + h) - break; - Track* track = *it; - th = track->height(); - ///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); - } - if (!track->isMidiTrack() && (track->type() != Track::WAVE)) { - QRect r = rect & QRect(x, yy, w, track->height()); - drawAudioTrack(p, r, (AudioTrack*)track); - p.setPen(baseColor); - } - if (!track->isMidiTrack()) { // draw automation - QRect r = rect & QRect(x, yy, w, track->height()); - drawAutomation(p, r, (AudioTrack*)track); - p.setPen(baseColor); - - } - yy += track->height(); - } -} - -//--------------------------------------------------------- -// drawAudioTrack -//--------------------------------------------------------- - -void PartCanvas::drawAudioTrack(QPainter& p, const QRect& r, AudioTrack* /* t */) -{ - // NOTE: For one-pixel border use first line and don't bother with setCosmetic. - // For a two-pixel border use second line and MUST use setCosmetic! Tim. - QPen pen(Qt::black, 0, Qt::SolidLine); - //p.setPen(QPen(Qt::black, 2, Qt::SolidLine)); - //pen.setCosmetic(true); - p.setPen(pen); - //p.setBrush(Qt::gray); - QColor c(Qt::gray); - c.setAlpha(config.globalAlphaBlend); - p.setBrush(c); - - // Factor in pen stroking size: - //QRect rr(r); - //rr.setHeight(rr.height() -1); - - p.drawRect(r); -} - -//--------------------------------------------------------- -// drawAutomation -//--------------------------------------------------------- - -void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t) -{ -// printf("drawAudioTrack %d x %d y %d w %d h %d\n",t, r.x(), r.y(), r.width(), r.height()); - //int v2=r.x()+r.width(); - //printf("v2=%d mapx=%d rmapx=%d mapxdev=%d rmapxdev=%d\n",v2, mapx(v2),rmapx(v2),mapxDev(v2),rmapxDev(v2)); - //return; - -// p.setPen(QPen(Qt::black, 2, Qt::SolidLine)); - int height=r.bottom()-r.top()-4; // limit height - - CtrlListList* cll = t->controller(); -// QColor cols[10]; -// cols[0]=Qt::white; -// cols[1]=Qt::red; -// cols[2]=Qt::yellow; -// cols[3]=Qt::black; -// cols[4]=Qt::blue; - //int colIndex=0; - bool firstRun=true; - for(CtrlListList::iterator icll =cll->begin();icll!=cll->end();++icll) - { - //iCtrlList *icl = icll->second; - CtrlList *cl = icll->second; - if (cl->dontShow()) - continue; - double prevVal; - iCtrl ic=cl->begin(); - if (!cl->isVisible()) - continue; // skip this iteration if this controller isn't in the visible list - p.setPen(QPen(cl->color(),1,Qt::SolidLine)); - - // First check that there ARE automation, ic == cl->end means no automation - if (ic != cl->end()) { - CtrlVal cvFirst = ic->second; - ic++; - int prevPos=cvFirst.frame; - prevVal = cvFirst.val; - - // prepare prevVal - if (cl->id() == AC_VOLUME ) { // use db scale for volume - prevVal = (20.0*log10(cvFirst.val)+60) / 70.0; // represent volume between 0 and 1 - if (prevVal < 0) prevVal = 0.0; - } - else { - // we need to set curVal between 0 and 1 - double min, max; - cl->range(&min,&max); - prevVal = (prevVal- min)/(max-min); - } - - for (; ic !=cl->end(); ++ic) - { - CtrlVal cv = ic->second; - double nextVal = cv.val; // was curVal - if (cl->id() == AC_VOLUME ) { // use db scale for volume - nextVal = (20.0*log10(cv.val)+60) / 70.0; // represent volume between 0 and 1 - if (nextVal < 0) nextVal = 0.0; - } - else { - // we need to set curVal between 0 and 1 - double min, max; - cl->range(&min,&max); - nextVal = (nextVal- min)/(max-min); - } - int leftX=tempomap.frame2tick(prevPos); - if (firstRun && leftX>r.x()) { - leftX=r.x(); - } - - p.drawLine( leftX, - (r.bottom()-2)-prevVal*height, - tempomap.frame2tick(cv.frame), - (r.bottom()-2)-nextVal*height); - firstRun=false; - //printf("draw line: %d %f %d %f\n",tempomap.frame2tick(lastPos),r.bottom()-lastVal*height,tempomap.frame2tick(cv.frame),r.bottom()-curVal*height); - prevPos=cv.frame; - prevVal=nextVal; - } - //printf("outer draw %f\n", cvFirst.val ); - p.drawLine(tempomap.frame2tick(prevPos), - (r.bottom()-2)-prevVal*height, - r.x()+r.width(), - (r.bottom()-2)-prevVal*height); - //printf("draw last line: %d %f %d %f\n",tempomap.frame2tick(prevPos),(r.bottom()-2)-prevVal*height,tempomap.frame2tick(prevPos)+r.width(),(r.bottom()-2)-prevVal*height); - } - } -} - - -void PartCanvas::controllerChanged(Track* /* t */) -{ - redraw(); -} |