diff options
author | Robert Jonsson <spamatica@gmail.com> | 2009-12-27 11:30:35 +0000 |
---|---|---|
committer | Robert Jonsson <spamatica@gmail.com> | 2009-12-27 11:30:35 +0000 |
commit | b703eab295330e6f81564fbb39a10a1a2fdd2f54 (patch) | |
tree | e46b5c9a6bc22fd661c15d1d2123f5bf631cef80 /muse_qt4_evolution/muse/canvas.cpp | |
parent | 5d5fa0fdf913907edbc3d2d29a7548f0cb658c94 (diff) |
moved old qt4 branch
Diffstat (limited to 'muse_qt4_evolution/muse/canvas.cpp')
-rw-r--r-- | muse_qt4_evolution/muse/canvas.cpp | 1187 |
1 files changed, 1187 insertions, 0 deletions
diff --git a/muse_qt4_evolution/muse/canvas.cpp b/muse_qt4_evolution/muse/canvas.cpp new file mode 100644 index 00000000..c445c446 --- /dev/null +++ b/muse_qt4_evolution/muse/canvas.cpp @@ -0,0 +1,1187 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "canvas.h" +#include "al/al.h" +#include "al/sig.h" +#include "gconfig.h" +#include "song.h" +#include "icons.h" +#include "audio.h" +#include "partdrag.h" +#include "muse.h" +#include "midictrl.h" +#include "tlswidget.h" +#include "part.h" +#include "gui.h" + +#include <samplerate.h> + +static const int partLabelHeight = 13; +static const int handleWidth = 5; +static const int partBorderWidth = 2; + +enum { HIT_NOTHING, HIT_TRACK, HIT_PART, HIT_SUBTRACK }; + +//--------------------------------------------------------- +// PartCanvas +//--------------------------------------------------------- + +PartCanvas::PartCanvas() + : TimeCanvas(TIME_CANVAS) + { + setFocusPolicy(Qt::StrongFocus); + state = S_NORMAL; + _drawBackground = true; + lselected = -1; + starty = -1; + setMarkerList(song->marker()); + rubberBand=NULL; + connect(song, SIGNAL(markerChanged(int)), SLOT(markerChanged(int))); + } + +//--------------------------------------------------------- +// markerChanged +//--------------------------------------------------------- + +void PartCanvas::markerChanged(int val) + { + if (val == Song::MARKER_CUR) + updateRuler(); + } + +//--------------------------------------------------------- +// drawWavePart +// y0 - start of track +// th - track height +// from - x pixel coordinate start drawing +// to - x end drawing +// +// redraw area is QRect(from, y0, to-from, th) +//--------------------------------------------------------- + +void PartCanvas::drawWavePart(QPainter& p, Part* wp, int y0, int th, int from, int to) + { + int h = th/2; + int y = y0 + 1 + h; + int cc = th % 2 ? 0 : 1; + + const Pos pos(pix2pos(from)); + EventList* el = wp->events(); + for (iEvent e = el->begin(); e != el->end(); ++e) { + 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.finfo()->fileName().toLatin1().data()); + continue; + } + + int x1 = pos2pix(event.pos() + *wp); + int x2 = pos2pix(event.end() + *wp); + int w = x2 - x1; + if (w == 0) + continue; + + int samples = event.lenFrame(); + int xScale = (samples + w/2)/w; + int frame = pos.frame() - wp->frame() + - event.pos().frame() + event.spos(); + + if (h < 20) { + // + // combine multi channels into one waveform + // + for (int i = from; i < to; i++) { + SampleV sa[channels]; + f.read(sa, xScale, frame); + frame += 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 * (th-2)) >> 9; + rms = (rms * (th-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 + // + h = th / (channels * 2); + int cc = th % (channels * 2) ? 0 : 1; + for (int i = from; i < to; i++) { + y = y0 + 1 + h; + SampleV sa[channels]; + f.read(sa, xScale, frame); + frame += xScale; + for (unsigned k = 0; k < channels; ++k) { + // peak = (sa[k].peak * h) / 256; + int peak = (sa[k].peak * (h - 1)) >> 8; + int rms = (sa[k].rms * (h - 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 * h; + } + } + } + } + } + +//--------------------------------------------------------- +// paint +//--------------------------------------------------------- + +void PartCanvas::paint(QPainter& p, QRect r) + { + //printf("canvas paint %d %d %d %d\n", r.x(), r.y(), r.width(), r.height()); + QFont f = font(); + f.setPointSize(8); + p.setFont(f); + + int from = r.x(); + int to = from + r.width(); + + TrackList* tl = song->tracks(); + ArrangerTrack* at = 0; + for (iTrack i = tl->begin(); i != tl->end(); ++i) { + Track* t = *i; + at = &(t->arrangerTrack); + if (at->tw == 0) + continue; + + int y = at->tw->y(); // - splitWidth/2; + int h = at->tw->height() - 1; + + PartList* pl = t->parts(); + for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { + Part* part = ip->second; + int x1 = pos2pix(*part); + int x2 = pos2pix(part->end()); + int len = x2 - x1; + + if (x2 <= from) + continue; + if (x1 > to) + break; + + QRect pr(x1, y, len, h - partBorderWidth); + bool clone = part->isClone(); + + QPen pen(QColor(100, 100, 100), partBorderWidth, clone ? Qt::DashLine : Qt::SolidLine); + QBrush brush(Qt::SolidPattern); + QLinearGradient lg(0, pr.y() - wpos.y()-r.y(), + 0, pr.y()+ 2*pr.height() -wpos.y()-r.y()); + lg.setColorAt(0, part->selected()?Qt::gray + :config.partColors[part->colorIndex()]); + lg.setColorAt(1, Qt::white); + QBrush brushLG(lg); + if (part->selected()) { + pen.setColor(config.partColors[part->colorIndex()]); + brush.setColor(config.selectPartBg); + p.setBrush(brushLG); + } + else if (part->mute()) { + pen.setColor(Qt::red); + brush.setColor(Qt::gray); + p.setBrush(brush); + } + else { + //brush.setColor(config.partColors[part->colorIndex()]); + p.setBrush(brushLG); + } + p.setPen(pen); + // + // we want to draw the rectangle without transformation + // to get equal border width horizontal and vertical + // + QRect rr(p.matrix().mapRect(pr).adjusted(1, 0, -1, 0)); + p.save(); + p.resetMatrix(); + p.drawRect(rr); + p.restore(); + + int xx1 = x1; + if (xx1 < from) + xx1 = from; + int xx2 = x2; + if (xx2 > to) + xx2 = to; + if (t->isMidiTrack()) + drawMidiPart(p, part, y, h, xx1, xx2); + else if (t->type() == Track::WAVE) + drawWavePart(p, part, y, h, xx1, xx2); + int yy = y + h - partLabelHeight; + p.drawText(x1 + 3, yy, len - 6, + partLabelHeight-1, Qt::AlignVCenter | Qt::AlignLeft, + part->name()); + + // redraw border + p.save(); + p.resetMatrix(); + p.setPen(pen); + p.setBrush(Qt::NoBrush); + p.drawRect(rr); + p.restore(); + } + + if (i != tl->begin()) { + p.setPen(QPen(Qt::lightGray, trackSeparator, Qt::SolidLine)); + p.drawLine(from, y + yTrackOffset, to, y + yTrackOffset); + } + for (iArrangerTrack i = t->subtracks.begin(); i != t->subtracks.end(); ++i) { + at = *i; + if (at->tw == 0) + continue; + TLSWidget* tls = (TLSWidget*)(at->tw); + int y = tls->y(); + // int h = tls->height(); + p.setPen(QPen(Qt::lightGray, trackSeparator, Qt::SolidLine)); + p.drawLine(from, y + yTrackOffset, to, y + yTrackOffset); + y += yTrackOffset + trackSeparator; + QPoint off(0, y); + p.translate(off); + // tls->paint(p, r); + tls->paint(p, QRect(from, 0, to-from, tls->height() - (yTrackOffset + trackSeparator))); + p.translate(-off); + } + } + if (at && at->tw) { + // draw last line + int y = at->tw->y() + at->tw->height() + yTrackOffset; + p.setPen(QPen(Qt::lightGray, trackSeparator, Qt::SolidLine)); + p.drawLine(from, y, to, y); + } + if (state == S_DRAG4 || state == S_DRAG1 || state == S_DRAG2 || state == S_DRAG5) { + p.setBrush(Qt::NoBrush); + p.setPen(QPen(QColor(Qt::red), partBorderWidth)); + p.drawRect(drag); + } + } + +//--------------------------------------------------------- +// drawMidiPart +//--------------------------------------------------------- + +void PartCanvas::drawMidiPart(QPainter& p, Part* mp, int y, int th, int from, int to) + { + p.setPen(Qt::black); + + EventList* events = mp->events(); + // iEvent ito(events->lower_bound(to)); + + iEvent ito = events->end(); +// int pos = pos2pix(*mp); + + if (config.canvasShowPartType & 2) { // show events + 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 = pos2pix(*mp + i->second.pos()); + p.drawLine(t, y + 1, t, y + th - 2); + } + } + } + + else { // show Cakewalk Style + for (iEvent i = events->begin(); i != ito; ++i) { + if (i->second.type() != Note) + continue; + int x1 = pos2pix(*mp + i->second.pos()); + int x2 = pos2pix(*mp + i->second.end()); + + if (x1 > to) + break; + if (x2 < from) + continue; + + if (x2 > to) // clip to drawing area + x2 = to; + if (x1 < from) + x1 = from; + int pitch = i->second.pitch(); + int yy = y + th - (pitch * th / 127); + p.drawLine(x1, yy, x2, yy); + } + } + } + +//--------------------------------------------------------- +// searchPart +//--------------------------------------------------------- + +int PartCanvas::searchPart(const QPoint& pp) + { + Pos tp(pix2pos(pp.x())); + QPoint p(tp.tick(), pp.y() + wpos.y()); + +// printf("searchPart %d %d\n", p.x(), p.y()); + track = 0; + part = 0; + at = 0; + int yp = p.y(); + if (yp < 0) + return HIT_NOTHING; + + TrackList* tl = song->tracks(); + iTrack i; + int y1, y2; + for (i = tl->begin(); i != tl->end(); ++i) { + track = *i; + QWidget* tw = track->arrangerTrack.tw; + if (tw == 0) { + printf(" invisible Track\n"); + continue; + } + y1 = tw->y(); + y2 = y1 + tw->height(); + if (yp >= y1 && yp < y2) { +// printf(" track <%s> %d - %d\n", track->name().toLatin1().data(), y1, y2); + break; + } + for (iArrangerTrack i = track->subtracks.begin(); i != track->subtracks.end(); ++i) { + at = *i; + if (at->tw == 0) { + printf("----empty subtrack?\n"); + break; + } + y1 = at->tw->y(); + y2 = y1 + at->tw->height(); + if (yp >= y1 && yp < y2) { + return HIT_SUBTRACK; + } + } + } + if (i == tl->end()) { + track = 0; + at = 0; + return HIT_NOTHING; + } + + unsigned x = p.x(); + PartList* pl = track->parts(); + for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { + part = ip->second; + if (x >= part->tick() && x < part->endTick()) { + ppos = mapx(part->tick()); + psize = rmapx(part->lenTick()); +// printf(" part\n"); + return HIT_PART; + } + } + part = 0; + return HIT_TRACK; + } + +//--------------------------------------------------------- +// contextMenu +//--------------------------------------------------------- + +void PartCanvas::contextMenu(const QPoint& pos) + { + QMenu* pop = new QMenu(widget()); + QAction* a; + if (part) { + pop->addAction(getAction("cut", this)); + pop->addAction(getAction("copy", this)); + pop->addSeparator(); + a = pop->addAction(tr("Rename")); + a->setData("rename"); + + QMenu* cp = pop->addMenu(tr("Color")); + + // part color selection + for (int i = 0; i < NUM_PARTCOLORS; ++i) { + a = cp->addAction(partColorNames[i]); + a->setData(QString("color%1").arg(i)); + QPixmap pm(20, 20); + QPainter p(&pm); + p.fillRect(0, 0, 20, 20, config.partColors[i]); + a->setIcon(QIcon(pm)); + } + pop->addAction(getAction("delete", this)); + pop->addAction(getAction("scissor", this)); + pop->addAction(getAction("glue", this)); + a = getAction("declone", this); + a->setEnabled(part->isClone()); + pop->addAction(a); + if (track->type() == Track::MIDI) { + a = pop->addAction(tr("AutoFill...")); + a->setData("autofill"); + } + pop->addSeparator(); + if (track->type() == Track::MIDI) { + MidiTrack* track = (MidiTrack*)part->track(); + if (track->useDrumMap()) { + a = pop->addAction(*edit_drummsIcon, tr("drums")); + a->setData("editdrums"); + } + else { + a = pop->addAction(QIcon(":/xpm/piano.xpm"), tr("pianoroll")); + a->setData("editpiano"); + } + a = pop->addAction(*edit_listIcon, tr("miditracker")); + a->setData("miditracker"); + pop->addAction(getAction("listedit", this)); + } + else { + a = pop->addAction(*waveIcon, tr("wave edit")); + a->setData("waveedit"); + } + + a = pop->exec(mapToGlobal(pos)); + if (a) { + QString cmd = a->data().toString(); + if (cmd == "rename") + renamePart(part); + else if (cmd == "delete") + song->cmdRemovePart(part); + else if (cmd == "scissor") + splitPart(part, startDrag); + else if (cmd == "glue") + song->cmdGluePart(part); + else if (cmd == "cut") + cutPart(part); + else if (cmd == "copy") + copyPart(part); + else if (cmd == "editpiano") + emit startEditor(part, 0); + else if (cmd == "miditracker") + emit startEditor(part, 2); + else if (cmd == "listedit") + emit startEditor(part, 1); + else if (cmd == "drumedit") + emit startEditor(part, 3); + else if (cmd == "waveedit") + emit startEditor(part, 4); + else if (cmd == "declone") + declonePart(part); + else if (cmd == "autofill") { + bool ok; + int ticksM = AL::sigmap.ticksMeasure(part->tick()); + int n = QInputDialog::getInteger(this, + tr("MusE: Get auto fill loop len"), + tr("Measures: "), + part->fillLen() / ticksM, + 0, 16, 1, &ok); + if (ok) { + part->setFillLen(n * ticksM); + } + } + else if (cmd.startsWith("color")) { + int idx = cmd.mid(5).toInt(); + part->setColorIndex(idx); + widget()->update(); + } + else { + printf("unknown action <%s>\n", cmd.toLatin1().data()); + } + } + } + else { + for (int i = 0; i < TOOLS; ++i) { + if ((arrangerTools & (1 << i))==0) + continue; + a = getAction(toolList[i], this); + pop->addAction(a); + a->setCheckable(true); + a->setChecked((1 <<i) == (int)_tool); + } + a = pop->exec(mapToGlobal(pos)); + if (a) + muse->setTool(a->data().toString()); + } + } + +//--------------------------------------------------------- +// mousePressEvent +//--------------------------------------------------------- + +void PartCanvas::mousePress(QMouseEvent* me) + { + if (state == S_SUBTRACK) { + ((TLSWidget*)(at->tw))->mouseRelease(); + state = S_NORMAL; + } + + QPoint pos(me->pos().x(), me->pos().y() - rulerHeight); + startDrag = pos; + int hit = searchPart(startDrag); + + if (hit == HIT_SUBTRACK) { + TLSWidget* w = (TLSWidget*)(at->tw); + int y = wpos.y() + pos.y() - w->y(); + w->mousePress(QPoint(pos.x(), y), me); + // propagate drag events to subtrack if left button pressed: + if (me->button() == Qt::LeftButton) + state = S_SUBTRACK; + return; + } + else if ( hit == HIT_NOTHING ) { // nothing here we put up a rubberband + rubberBandStartPos = me->pos(); + if (!rubberBand) + rubberBand = new QRubberBand(QRubberBand::Rectangle, this); + rubberBand->setGeometry(QRect(rubberBandStartPos, QSize())); + rubberBand->show(); + } + + if (button & Qt::RightButton) { + contextMenu(me->pos()); + return; + } + + QRect r1,r2; + QPoint pos2; + int xpos = 0, y = 0, len = 0, h = 0; + + if (hit == HIT_PART) { + h = track->arrangerTrack.tw->height(); + len = rmapx(part->lenTick()); + y = track->arrangerTrack.tw->y() - splitWidth/2; + xpos = mapx(part->tick()); + + r1 = QRect(xpos, y, handleWidth, h); + r2 = QRect(xpos + len - handleWidth, y, handleWidth, h); + pos2 = QPoint(pos.x(), pos.y() + wpos.y()); + } + + switch (_tool) { + case PencilTool: + if (r1.contains(pos2)) + state = S_START_DRAG1; + else if (r2.contains(pos2)) + state = S_START_DRAG2; + else + state = S_START_DRAG5; + ppos = pos2pix(pix2pos(startDrag.x()).downSnaped(raster())); + psize = pos2pix(pix2pos(ppos+1).upSnaped(raster())) - ppos; + startDragTime = QTime::currentTime(); + setCursor(); + break; + case RubberTool: + if (part) + song->cmdRemovePart(part); + break; + case GlueTool: + if (part) + song->cmdGluePart(part); + break; + case CutTool: + if (part) + splitPart(part, pos); + break; + case MuteTool: + if (part) { + part->setMute(!part->mute()); + widget()->update(); + } + break; + default: + if (hit == HIT_PART) { + QRect r3(xpos, y, len, h); + + if (r1.contains(pos2)) { + state = S_START_DRAG1; + } + else if (r2.contains(pos2)) { + state = S_START_DRAG2; + } + else if (r3.contains(pos2)) { + state = S_START_DRAG3; + bool add = keyState & Qt::ShiftModifier; + song->selectPart(part, add); + emit kbdMovementUpdate(track, part); + } + } + if (state == S_NORMAL) { + song->selectPart(0, false); // deselect all parts + emit kbdMovementUpdate(0, 0); // Tell arranger nothing is selected (Keyboard movement) + } + startDragTime = QTime::currentTime(); + setCursor(); + break; + } + } + +//--------------------------------------------------------- +// mouseMove +//--------------------------------------------------------- + +void PartCanvas::mouseMove(QPoint pos) + { + + if(rubberBand) + rubberBand->setGeometry(QRect(rubberBandStartPos, pos).normalized()); + + if (state == S_SUBTRACK) { + TLSWidget* w = (TLSWidget*)(at->tw); + int y = wpos.y() + pos.y() - w->y() - rulerHeight; + w->mouseMove(QPoint(pos.x(), y)); + return; + } + pos -= rCanvasA.topLeft(); + bool update = false; + int x = pos.x(); + int delta = startDrag.x() - x; + int t = startDragTime.msecsTo(QTime::currentTime()); + bool dragActive = (startDrag - pos).manhattanLength() > + QApplication::startDragDistance() + || t > QApplication::startDragTime(); + switch (state) { + case S_START_DRAG1: + if (dragActive) + state = S_DRAG1; + break; + case S_START_DRAG2: + if (dragActive) + state = S_DRAG2; + break; + case S_START_DRAG3: + if (dragActive) + state = S_DRAG3; + break; + case S_START_DRAG5: + if (dragActive) + state = S_DRAG5; + break; + case S_NORMAL: + { + searchPart(pos); + bool found = false; + if (part) { + int h = track->arrangerTrack.tw->height(); + int xpos = mapx(part->tick()); + int len = rmapx(part->lenTick()); + int y = track->arrangerTrack.tw->y(); + QRect r1(xpos, y, handleWidth, h); + QRect r2(xpos + len - handleWidth, y, handleWidth, h); + if (r1.contains(pos) || r2.contains(pos)) + found = true; + } + if (found) { + widget()->setCursor(Qt::SizeHorCursor); + } + else + setCursor(); + } + break; + default: + break; + } + if (!track) + return; + int y = track->arrangerTrack.tw->y(); // - splitWidth/2; + int ph = track->arrangerTrack.tw->height() - 1 - partBorderWidth; + if (state == S_DRAG1) { + // + // drag left edge of part + // + Pos p(pix2pos(ppos - delta)); + p.snap(raster()); + int x1 = pos2pix(p); + int x2 = pos2pix(part->end()); + int size = x2 - x1; + drag.setRect(x1, y, size, ph); + update = true; + } + else if (state == S_DRAG2) { + // + // drag right edge of part + // + int size = psize - delta; + if (size < 10) + size = 10; + int x2 = mapx(AL::sigmap.raster(part->tick() + rmapxDev(size), raster())); + drag.setRect(ppos, y, x2 - ppos, ph); + update = true; + } + else if (state == S_DRAG5) { + // + // draw part with pencil tool + // + int size = psize - delta; + if (size < 10) + size = 10; + int x2 = mapx(AL::sigmap.raster(mapxDev(ppos + size), raster())); + drag.setRect(ppos, y, x2 - ppos, ph); + update = true; + } + else if (state == S_DRAG3) { + // + // drag whole part + // + srcPart = part; + QDrag* d = 0; + if (track->type() == Track::MIDI) + d = new MidiPartDrag(srcPart, this); + else if (track->type() == Track::WAVE) + d = new AudioPartDrag(srcPart, this); + if (d) { + Qt::KeyboardModifiers kb = QApplication::keyboardModifiers(); + Qt::DropActions da = kb ? (Qt::MoveAction | Qt::CopyAction | Qt::LinkAction) : Qt::MoveAction; + song->startUndo(); + _dragOffset = startDrag.x() - rCanvasA.x() - ppos; + if (d->start(da) == Qt::MoveAction) + song->removePart(srcPart); + song->endUndo(0); + update = true; + } + state = S_NORMAL; + } + if (update) + widget()->update(); + } + +//--------------------------------------------------------- +// mouseRelease +//--------------------------------------------------------- + +void PartCanvas::mouseRelease(QMouseEvent* me) + { + + if (rubberBand) + rubberBand->hide(); // TODO robert, nothing more happens for the moment/ + + if (state == S_SUBTRACK) { + ((TLSWidget*)(at->tw))->mouseRelease(); + state = S_NORMAL; + return; + } + + QPoint pos(me->pos()); + int x = pos.x(); + int delta = startDrag.x() - x; + + if (state == S_DRAG1) { + int val = mapxDev(ppos-delta); + int pos = AL::sigmap.raster(val, raster()); + int size = part->tick() + part->lenTick() - pos; + emit partChanged(part, pos, size); + } + else if (state == S_DRAG2) { + int size = psize - delta; + int x1 = part->tick(); + int x2 = AL::sigmap.raster(part->tick() + rmapxDev(size), raster()); + + int step = AL::sigmap.rasterStep(x1, raster()); + if (x2 - x1 < step) + x2 = AL::sigmap.raster(x1 + step, raster()); + emit partChanged(part, x1, x2-x1); + } + else if (state == S_DRAG5) { + if (track && (track->type() == Track::MIDI || track->type() == Track::WAVE)) { + Part* part = track->newPart(); + Pos p1 = pix2pos(drag.x()).snaped(raster()); + Pos p2 = pix2pos(drag.x() + drag.width()).snaped(raster()); + part->setPos(p1); + part->setLenTick(p2.tick() - p1.tick()); + song->cmdAddPart(part); + } + else + widget()->update(); + } + state = S_NORMAL; + setCursor(); + } + +//--------------------------------------------------------- +// mouseDoubleClickEvent +//--------------------------------------------------------- + +void PartCanvas::mouseDoubleClick(QMouseEvent* me) + { + QPoint pos(me->pos().x(), me->pos().y() - rulerHeight); + if (_tool != PointerTool) { +//TD mousePress(pos); + return; + } + bool shift = keyState & Qt::ShiftModifier; + if (searchPart(pos) == HIT_PART) { + if (button == Qt::LeftButton && shift) { + renamePart(part); + } + else if (button == Qt::LeftButton) { + emit doubleClickPart(part); + } + } + // + // double click creates new part between left and + // right mark + + else if (track && track->isMidiTrack()) + emit createLRPart(track); + } + + +//--------------------------------------------------------- +// keyboardNavigate +//--------------------------------------------------------- + +void PartCanvas::keyboardNavigate(QKeyEvent*) + { + printf("nothing here go away\n"); + } + + +//--------------------------------------------------------- +// setCursor +//--------------------------------------------------------- + +void PartCanvas::setCursor() + { + switch(state) { + case S_START_DRAG1: + case S_START_DRAG2: + case S_DRAG1: + case S_DRAG2: + widget()->setCursor(Qt::SizeHorCursor); + return; + default: + break; + } + TimeCanvas::setCursor(); + } + +//--------------------------------------------------------- +// declonePart +//--------------------------------------------------------- + +void PartCanvas::declonePart(Part* oPart) + { + Track* track = oPart->track(); + Part* nPart = track->newPart(oPart, false); + + EventList* se = oPart->events(); + for (iEvent i = se->begin(); i != se->end(); ++i) { + Event oldEvent = i->second; +// Event ev = oldEvent.clone(); + nPart->addEvent(oldEvent); + } + oPart->deref(); + song->cmdChangePart(oPart, nPart); + } + +//--------------------------------------------------------- +// splitPart +//--------------------------------------------------------- + +void PartCanvas::splitPart(Part* part, const QPoint& p) + { + song->cmdSplitPart(part, pix2pos(p.x()).snaped(raster())); + } + +//--------------------------------------------------------- +// renamePart +//--------------------------------------------------------- + +void PartCanvas::renamePart(Part* part) + { + bool ok; + + QString s = QInputDialog::getText(this, + tr("MusE: Change Part Name"), + tr("PartName:"), + QLineEdit::Normal, + part->name(), + &ok + ); + if (ok && s != part->name()) { + song->startUndo(); + Part* newPart = new Part(*part); + newPart->setName(s); + song->cmdChangePart(part, newPart); + widget()->update(); + } + } + +//--------------------------------------------------------- +// cutPart +//--------------------------------------------------------- + +void PartCanvas::cutPart(Part* part) + { + copyPart(part); + song->cmdRemovePart(part); + } + +//--------------------------------------------------------- +// copyPart +//--------------------------------------------------------- + +void PartCanvas::copyPart(Part* part) + { + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + AL::Xml xml(&buffer); + part->write(xml); + buffer.close(); + QMimeData* mimeData = new QMimeData; + mimeData->setData(MidiPartDrag::type, buffer.buffer()); + QApplication::clipboard()->setMimeData(mimeData); + } + +//--------------------------------------------------------- +// dragEnter +//--------------------------------------------------------- + +void PartCanvas::dragEnter(QDragEnterEvent* event) + { +#if 0 + QPoint p(event->pos() - rCanvasA.topLeft()); + searchPart(p); + if (!track) { + event->ignore(); + return; + } + int srcIsMidi = -1; + const QMimeData* md = event->mimeData(); + + if (MidiPartDrag::canDecode(md)) + srcIsMidi = 1; + else if (AudioPartDrag::canDecode(md)) + srcIsMidi = 0; + else if (WavUriDrag::canDecode(md)) + srcIsMidi = 0; + + int dstIsMidi = -1; + if (track->type() == Track::MIDI) + dstIsMidi = 1; + else if (track->type() == Track::WAVE) + dstIsMidi = 0; + + if ((srcIsMidi == -1) || (dstIsMidi != srcIsMidi)) { + event->ignore(); + return; + } + Qt::KeyboardModifiers kb = event->keyboardModifiers(); + if (kb == 0 && (Qt::MoveAction & event->possibleActions())) { + event->setDropAction(Qt::MoveAction); + event->accept(); + } + else +#endif + event->acceptProposedAction(); + } + +//--------------------------------------------------------- +// dragMoveEvent +//--------------------------------------------------------- + +void PartCanvas::dragMove(QDragMoveEvent* event) + { + QPoint p(event->pos() - rCanvasA.topLeft()); + searchPart(p); + if (!track) { + event->acceptProposedAction(); + return; + } + Part* srcPart = 0; + QString filename; + + bool srcIsMidi; + const QMimeData* md = event->mimeData(); + if (MidiPartDrag::canDecode(md)) { + MidiPartDrag::decode(md, srcPart); + srcIsMidi = true; + } + else if (AudioPartDrag::canDecode(md)) { + AudioPartDrag::decode(md, srcPart); + srcIsMidi = false; + } + else if (WavUriDrag::canDecode(md)) { + WavUriDrag::decode(md, &filename); + if (state != S_NORMAL) { + state = S_NORMAL; + widget()->update(); + } + if (track->type() == Track::WAVE) + event->acceptProposedAction(); + else + event->ignore(); + return; + } + else { + state = S_NORMAL; + event->ignore(); + return; + } + + int dstIsMidi = -1; + if (track->type() == Track::MIDI) + dstIsMidi = 1; + else if (track->type() == Track::WAVE) + dstIsMidi = 0; + if ((srcIsMidi == -1) || (dstIsMidi != srcIsMidi)) { + if (state != S_NORMAL) { + state = S_NORMAL; + widget()->update(); + } + event->ignore(); + return; + } + Qt::KeyboardModifiers kb = event->keyboardModifiers(); + if (kb == 0 && (Qt::MoveAction & event->possibleActions())) { + event->setDropAction(Qt::MoveAction); + event->accept(); + } + else + event->acceptProposedAction(); + state = S_DRAG4; + ArrangerTrack* at = &(track->arrangerTrack); + + PartCanvas* cw = (PartCanvas*)event->source(); + QRect updateRect(drag); + + Pos pos; + if (cw) + pos = pix2pos(p.x() - cw->dragOffset()).snaped(raster()); + else + pos = pix2pos(p.x()).snaped(raster()); + drag.setRect( + pos2pix(pos), + at->tw->y(), + rmapx(srcPart->lenTick()), + at->tw->height() - 1 - partBorderWidth + ); + delete srcPart; + updateRect |= drag; + updateRect.adjust(-1, -1 + rCanvasA.y(), 1, 1 + rCanvasA.y()); + widget()->update(updateRect); + } + +//--------------------------------------------------------- +// dropEvent +//--------------------------------------------------------- + +void PartCanvas::drop(QDropEvent* event) + { + state = S_NORMAL; + Part* dstPart = 0; + QString filename; + + QPoint pos(event->pos() - rCanvasA.topLeft()); + const QMimeData* md = event->mimeData(); + if (WavUriDrag::canDecode(md)) { + WavUriDrag::decode(md, &filename); + int tick = AL::sigmap.raster(mapxDev(pos.x()), raster()); + Pos pos(tick); + muse->importWaveToTrack(filename, track, pos); + widget()->update(); + return; + } + + bool isMidi = false; + if (MidiPartDrag::canDecode(md)) { + MidiPartDrag::decode(md, dstPart); + isMidi = true; + } + else if (AudioPartDrag::canDecode(md)) + AudioPartDrag::decode(md, dstPart); + + searchPart(pos); + if (!dstPart) + return; + PartCanvas* cw = (PartCanvas*)event->source(); + bool needEndUndo = false; + if (!track) { + if (isMidi) + track = new MidiTrack(); + else + track = new WaveTrack(); + track->setDefaultName(); + if (cw) + song->insertTrack(track, -1); + else { + song->startUndo(); + song->insertTrack(track, -1); + needEndUndo = true; + } + } + else if (isMidi != track->isMidiTrack()) + return; + + dstPart->setTrack(track); + + // + // cw == 0 means that we are dropping to + // another application + + unsigned tick; + if (cw) + tick = AL::sigmap.raster(mapxDev(pos.x() - cw->dragOffset()), raster()); + else + tick = AL::sigmap.raster(mapxDev(pos.x()), raster()); + + dstPart->setTick(tick); + + Qt::DropAction da = event->proposedAction(); + Qt::KeyboardModifiers kb = event->keyboardModifiers(); + if (kb == 0 && (Qt::MoveAction & event->possibleActions())) + da = Qt::MoveAction; + + if ((da == Qt::LinkAction) && (cw == this)) { + delete dstPart->events(); + dstPart->clone(srcPart->events()); + event->setDropAction(Qt::LinkAction); + } + else if (da == Qt::MoveAction) + event->setDropAction(Qt::MoveAction); + else + event->setDropAction(Qt::CopyAction); + event->accept(); + if (cw || needEndUndo) + song->addPart(dstPart); + else + song->cmdAddPart(dstPart); + if (needEndUndo) + song->endUndo(0); + widget()->update(); + } + +//--------------------------------------------------------- +// dragLeave +//--------------------------------------------------------- + +void PartCanvas::dragLeave(QDragLeaveEvent*) + { + if (state == S_DRAG4) { + state = S_NORMAL; + widget()->update(); + } + } + |