1
//=========================================================
5
// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
7
// Based on WaveView.cpp and PianoCanvas.cpp
8
// (C) Copyright 2000 Werner Schweer (ws@seh.de)
11
// This program is free software; you can redistribute it and/or
12
// modify it under the terms of the GNU General Public License
13
// as published by the Free Software Foundation; version 2 of
14
// the License, or (at your option) any later version.
16
// This program is distributed in the hope that it will be useful,
17
// but WITHOUT ANY WARRANTY; without even the implied warranty of
18
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
// GNU General Public License for more details.
21
// You should have received a copy of the GNU General Public License
22
// along with this program; if not, write to the Free Software
23
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25
//=========================================================
28
#include <QApplication>
32
#include <QDragLeaveEvent>
33
#include <QDragEnterEvent>
34
#include <QDragMoveEvent>
37
#include <QInputDialog>
38
#include <QMouseEvent>
41
#include <QMessageBox>
55
#include "wavecanvas.h"
61
#include "functions.h"
63
#include "shortcuts.h"
70
#include "copy_on_write.h"
74
//---------------------------------------------------------
76
//---------------------------------------------------------
78
WEvent::WEvent(MusECore::Event& e, MusECore::Part* p, int height) : MusEGui::CItem(e, p)
80
unsigned frame = e.frame() + p->frame();
81
setPos(QPoint(frame, 0));
82
unsigned len = e.lenFrame();
83
if(e.frame() + e.lenFrame() >= p->lenFrame())
84
len = p->lenFrame() - e.frame();
85
setBBox(QRect(frame, 0, len, height));
88
//---------------------------------------------------------
90
//---------------------------------------------------------
92
CItem* WaveCanvas::addItem(MusECore::Part* part, MusECore::Event& event)
94
if (signed(event.frame())<0) {
95
printf("ERROR: trying to add event before current part!\n");
99
WEvent* ev = new WEvent(event, part, height());
102
int diff = event.frame()-part->lenFrame();
103
if (diff > 0) {// too short part? extend it
104
part->setLenFrame(part->lenFrame()+diff);
110
//---------------------------------------------------------
112
//---------------------------------------------------------
114
WaveCanvas::WaveCanvas(MidiEditor* pr, QWidget* parent, int sx, int sy)
115
: EventCanvas(pr, parent, sx, 1)
125
pos[0] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->cpos());
126
pos[1] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->lpos());
127
pos[2] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->rpos());
134
songChanged(SC_TRACK_INSERTED);
137
WaveCanvas::~WaveCanvas()
142
//---------------------------------------------------------
144
//---------------------------------------------------------
146
void WaveCanvas::songChanged(MusECore::SongChangedFlags_t flags)
148
// Is it simply a midi controller value adjustment? Forget it.
149
if(flags == SC_MIDI_CONTROLLER)
152
if (flags & ~SC_SELECTION) {
153
// TODO FIXME: don't we actually only want SC_PART_*, and maybe SC_TRACK_DELETED?
154
// (same in waveview.cpp)
155
bool curItemNeedsRestore=false;
156
MusECore::Event storedEvent;
160
curItemNeedsRestore=true;
161
storedEvent=curItem->event();
162
partSn=curItem->part()->sn();
167
startSample = INT_MAX;
170
for (MusECore::iPart p = editor->parts()->begin(); p != editor->parts()->end(); ++p) {
171
MusECore::WavePart* part = (MusECore::WavePart*)(p->second);
172
if (part->sn() == curPartId)
174
unsigned ssample = part->frame();
175
unsigned len = part->lenFrame();
176
unsigned esample = ssample + len;
177
if (ssample < startSample)
178
startSample = ssample;
179
if (esample > endSample)
182
MusECore::EventList* el = part->events();
183
for (MusECore::iEvent i = el->begin(); i != el->end(); ++i) {
184
MusECore::Event e = i->second;
185
// Do not add events which are past the end of the part.
189
if (e.type() == MusECore::Wave) {
190
CItem* temp = addItem(part, e);
192
if (temp && curItemNeedsRestore && e==storedEvent && part->sn()==partSn)
195
printf("THIS SHOULD NEVER HAPPEN: curItemNeedsRestore=true, event fits, but there was already a fitting event!?\n");
204
MusECore::Event event;
205
MusECore::WavePart* part = 0;
209
int n = 0; // count selections
210
for (iCItem k = items.begin(); k != items.end(); ++k) {
211
MusECore::Event ev = k->second->event();
212
bool selected = ev.selected();
214
k->second->setSelected(true);
218
MusECore::Event mi = nevent->event();
223
if (flags & SC_CLIP_MODIFIED) {
224
redraw(); // Boring, but the only thing possible to do
226
if (flags & SC_TEMPO) {
227
setPos(0, MusEGlobal::song->cpos(), false);
228
setPos(1, MusEGlobal::song->lpos(), false);
229
setPos(2, MusEGlobal::song->rpos(), false);
235
event = nevent->event();
236
part = (MusECore::WavePart*)nevent->part();
237
if (_setCurPartIfOnlyOneEventIsSelected && n == 1 && curPart != part) {
239
curPartId = curPart->sn();
244
bool f1 = flags & (SC_EVENT_INSERTED | SC_EVENT_MODIFIED | SC_EVENT_REMOVED |
245
SC_PART_INSERTED | SC_PART_MODIFIED | SC_PART_REMOVED |
246
SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED |
247
SC_SIG | SC_TEMPO | SC_KEY | SC_MASTER | SC_CONFIG | SC_DRUMMAP);
248
bool f2 = flags & SC_SELECTION;
249
if(f1 || f2) // Try to avoid all unnecessary emissions.
250
emit selectionChanged(x, event, part, !f1);
253
curPart = (MusECore::WavePart*)(editor->parts()->begin()->second);
257
//---------------------------------------------------------
259
//---------------------------------------------------------
261
void WaveCanvas::selectAtTick(unsigned int tick)
263
selectAtFrame(MusEGlobal::tempomap.tick2frame(tick));
266
//---------------------------------------------------------
268
//---------------------------------------------------------
270
void WaveCanvas::selectAtFrame(unsigned int frame)
272
//Select event nearest frame, if none selected and there are any
273
if (!items.empty() && selectionSize() == 0) {
274
iCItem i = items.begin();
275
CItem* nearest = i->second;
277
while (i != items.end()) {
278
CItem* cur=i->second;
279
unsigned int curf=abs(cur->x() + cur->part()->frame() - frame);
280
unsigned int nearf=abs(nearest->x() + nearest->part()->frame() - frame);
289
if (!nearest->isSelected()) {
290
selectItem(nearest, true);
291
songChanged(SC_SELECTION);
296
//---------------------------------------------------------
298
//---------------------------------------------------------
300
QString WaveCanvas::getCaption() const
304
AL::sigmap.tickValues(curPart->tick(), &bar1, &xx, &x);
305
AL::sigmap.tickValues(curPart->tick() + curPart->lenTick(), &bar2, &xx, &x);
307
return QString("MusE: Part <") + curPart->name()
308
+ QString("> %1-%2").arg(bar1+1).arg(bar2+1);
311
//---------------------------------------------------------
313
//---------------------------------------------------------
315
MusECore::WaveTrack* WaveCanvas::track() const
317
return ((MusECore::WavePart*)curPart)->track();
321
//---------------------------------------------------------
323
//---------------------------------------------------------
325
void WaveCanvas::keyPress(QKeyEvent* event)
327
int key = event->key();
328
if (((QInputEvent*)event)->modifiers() & Qt::ShiftModifier)
330
if (((QInputEvent*)event)->modifiers() & Qt::AltModifier)
332
if (((QInputEvent*)event)->modifiers() & Qt::ControlModifier)
335
// TODO: New WaveCanvas: Convert these to frames, and remove unneeded functions.
338
// Shortcut for DrumEditor & PianoRoll
339
// Sets locators to selected events
341
if (key == shortcuts[SHRT_LOCATORS_TO_SELECTION].key) {
343
int tick_min = INT_MAX;
346
for (iCItem i= items.begin(); i != items.end(); i++) {
347
if (!i->second->isSelected())
350
int tick = i->second->x();
351
int len = i->second->event().lenTick();
353
if (tick + len > tick_max)
354
tick_max = tick + len;
359
MusECore::Pos p1(tick_min, true);
360
MusECore::Pos p2(tick_max, true);
361
MusEGlobal::song->setPos(1, p1);
362
MusEGlobal::song->setPos(2, p2);
365
// Select items by key (PianoRoll & DrumEditor)
366
else if (key == shortcuts[SHRT_SEL_RIGHT].key || key == shortcuts[SHRT_SEL_RIGHT_ADD].key) {
371
for (i = items.rbegin(); i != items.rend(); ++i)
372
if (i->second->isSelected())
375
if(i == items.rend())
378
if(i != items.rbegin())
382
if (key != shortcuts[SHRT_SEL_RIGHT_ADD].key)
384
CItem* sel = i->second;
385
sel->setSelected(true);
387
if (sel->x() + sel->width() > mapxDev(width()))
389
int mx = rmapx(sel->x());
390
int newx = mx + rmapx(sel->width()) - width();
391
// Leave a bit of room for the specially-drawn drum notes. But good for piano too.
392
emit horizontalScroll( (newx > mx ? mx - 10: newx + 10) - rmapx(xorg) );
396
//Select items by key: (PianoRoll & DrumEditor)
397
else if (key == shortcuts[SHRT_SEL_LEFT].key || key == shortcuts[SHRT_SEL_LEFT_ADD].key) {
401
for (i = items.begin(); i != items.end(); ++i)
402
if (i->second->isSelected())
408
if(i != items.begin())
412
if (key != shortcuts[SHRT_SEL_LEFT_ADD].key)
414
CItem* sel = i->second;
415
sel->setSelected(true);
417
if (sel->x() <= mapxDev(0))
418
emit horizontalScroll(rmapx(sel->x() - xorg) - 10); // Leave a bit of room.
421
//else if (key == shortcuts[SHRT_INC_PITCH].key) {
422
// modifySelected(NoteInfo::VAL_PITCH, 1);
424
//else if (key == shortcuts[SHRT_DEC_PITCH].key) {
425
// modifySelected(NoteInfo::VAL_PITCH, -1);
427
else if (key == shortcuts[SHRT_INC_POS].key) {
428
// TODO: Check boundaries
429
modifySelected(NoteInfo::VAL_TIME, editor->raster());
431
else if (key == shortcuts[SHRT_DEC_POS].key) {
432
// TODO: Check boundaries
433
modifySelected(NoteInfo::VAL_TIME, 0 - editor->raster());
436
else if (key == shortcuts[SHRT_INCREASE_LEN].key) {
437
// TODO: Check boundaries
438
modifySelected(NoteInfo::VAL_LEN, editor->raster());
440
else if (key == shortcuts[SHRT_DECREASE_LEN].key) {
441
// TODO: Check boundaries
442
modifySelected(NoteInfo::VAL_LEN, 0 - editor->raster());
450
//---------------------------------------------------------
452
// set one of three markers
453
// idx - 0-cpos 1-lpos 2-rpos
454
// flag - emit followEvent()
455
//---------------------------------------------------------
457
void WaveCanvas::setPos(int idx, unsigned val, bool adjustScrollbar)
459
val = MusEGlobal::tempomap.tick2frame(val);
462
int opos = mapx(pos[idx]);
463
int npos = mapx(val);
465
if (adjustScrollbar && idx == 0) {
466
switch (MusEGlobal::song->follow()) {
467
case MusECore::Song::NO:
469
case MusECore::Song::JUMP:
470
if (npos >= width()) {
471
int ppos = val - xorg - rmapxDev(width()/4);
474
emit followEvent(ppos);
475
opos = mapx(pos[idx]);
479
int ppos = val - xorg - rmapxDev(width()*3/4);
482
emit followEvent(ppos);
483
opos = mapx(pos[idx]);
487
case MusECore::Song::CONTINUOUS:
488
if (npos > (width()*5)/8) {
489
int ppos = pos[idx] - xorg - rmapxDev(width()*5/8);
492
emit followEvent(ppos);
493
opos = mapx(pos[idx]);
496
else if (npos < (width()*3)/8) {
497
int ppos = pos[idx] - xorg - rmapxDev(width()*3/8);
500
emit followEvent(ppos);
501
opos = mapx(pos[idx]);
519
//redraw(QRect(x, 0, w, height()));
520
redraw(QRect(x-1, 0, w+2, height())); // From Canvas::draw (is otherwise identical). Fix for corruption. (TEST: New WaveCanvas: Still true?)
523
//---------------------------------------------------------
525
//---------------------------------------------------------
527
void WaveCanvas::setYScale(int val)
533
// TODO: Overridden because markers need tick2frame.
534
// After BBT/frame mode is added to Canvas, remove this override and let Canvas::draw do it.
535
// Also add the drawParts calls to Canvas::draw, and add a dummy Canvas::drawParts { }.
536
//---------------------------------------------------------
538
//---------------------------------------------------------
540
void WaveCanvas::draw(QPainter& p, const QRect& r)
542
int x = r.x() < 0 ? 0 : r.x();
543
int y = r.y() < 0 ? 0 : r.y();
548
std::vector<CItem*> list1;
549
std::vector<CItem*> list2;
550
//std::vector<CItem*> list3;
551
std::vector<CItem*> list4;
555
//---------------------------------------------------
557
//---------------------------------------------------
559
iCItem to(items.lower_bound(x2));
561
for(iCItem i = items.begin(); i != to; ++i)
563
CItem* ci = i->second;
564
// NOTE Optimization: For each item call this once now, then use cached results later via cachedHasHiddenEvents().
565
// Not required for now.
566
//ci->part()->hasHiddenEvents();
568
// Draw items from other parts behind all others. Only for items with events (not arranger parts).
569
if(!ci->event().empty() && ci->part() != curPart)
571
else if(!ci->isMoving() && (ci->event().empty() || ci->part() == curPart))
573
// Draw selected parts in front of all others.
576
// Draw clone parts, and parts with hidden events, in front of others all except selected.
577
//else if(ci->event().empty() && (ci->part()->events()->arefCount() > 1 || ci->part()->cachedHasHiddenEvents()))
578
// Draw clone parts in front of others all except selected.
579
//else if(ci->event().empty() && (ci->part()->events()->arefCount() > 1))
580
// list3.push_back(ci);
582
// Draw unselected parts.
587
// Draw non-current part backgrounds behind all others:
588
drawParts(p, r, false);
591
int sz = list1.size();
592
for(i = 0; i != sz; ++i)
593
drawItem(p, list1[i], r);
595
// Draw current part background in front of all others:
596
drawParts(p, r, true);
599
for(i = 0; i != sz; ++i)
600
drawItem(p, list2[i], r);
603
//for(i = 0; i != sz; ++i)
604
// drawItem(p, list3[i], rect);
607
for(i = 0; i != sz; ++i)
608
drawItem(p, list4[i], r);
610
to = moving.lower_bound(x2);
611
for (iCItem i = moving.begin(); i != to; ++i)
613
drawItem(p, i->second, r);
619
//---------------------------------------------------
621
//---------------------------------------------------
623
bool wmtxen = p.worldMatrixEnabled();
624
p.setWorldMatrixEnabled(false);
627
int my2 = mapy(y + h);
629
MusECore::MarkerList* marker = MusEGlobal::song->marker();
630
for (MusECore::iMarker m = marker->begin(); m != marker->end(); ++m) {
631
int xp = MusEGlobal::tempomap.tick2frame(m->second.tick());
632
if (xp >= x && xp < x2) {
634
p.drawLine(mapx(xp), my, mapx(xp), my2);
638
//---------------------------------------------------
639
// draw location marker
640
//---------------------------------------------------
642
// Tip: These positions are already in units of frames.
645
if (pos[1] >= unsigned(x) && pos[1] < unsigned(x2)) {
647
p.drawLine(mx, my, mx, my2);
649
if (pos[2] >= unsigned(x) && pos[2] < unsigned(x2)) {
651
p.drawLine(mx, my, mx, my2);
654
if (pos[0] >= unsigned(x) && pos[0] < unsigned(x2)) {
656
p.drawLine(mx, my, mx, my2);
660
//p.setWorldMatrixEnabled(true);
661
p.setWorldMatrixEnabled(wmtxen);
663
//---------------------------------------------------
665
//---------------------------------------------------
667
if (drag == DRAG_LASSO) {
669
p.setBrush(Qt::NoBrush);
673
//---------------------------------------------------
675
//---------------------------------------------------
677
for(iCItem i = moving.begin(); i != moving.end(); ++i)
678
drawMoving(p, i->second, r);
682
//---------------------------------------------------------
684
//---------------------------------------------------------
686
void WaveCanvas::drawParts(QPainter& p, const QRect& r, bool do_cur_part)
688
//QRect rr = p.transform().mapRect(r); // Gives inconsistent positions. Source shows wrong operation for our needs.
689
QRect rr = map(r); // Use our own map instead.
691
bool wmtxen = p.worldMatrixEnabled();
692
p.setWorldMatrixEnabled(false);
696
// Draw current part:
699
QRect mwpr = map(QRect(curPart->frame(), 0, curPart->lenFrame(), height()));
700
QRect mpbgr = rr & mwpr;
708
c = MusEGlobal::config.partColors[curPart->colorIndex()];
714
c.setAlpha(MusEGlobal::config.globalAlphaBlend);
715
QBrush part_bg_brush(MusECore::gGradientFromQColor(c, mwpr.topLeft(), mwpr.bottomLeft()));
716
p.fillRect(mpbgr, part_bg_brush);
722
// Draw non-current parts:
723
for (MusECore::iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip)
725
MusECore::WavePart* wp = (MusECore::WavePart*)(ip->second);
729
QRect mwpr = map(QRect(wp->frame(), 0, wp->lenFrame(), height()));
730
QRect mpbgr = rr & mwpr;
733
//int cidx = wp->colorIndex();
734
//QColor c(MusEGlobal::config.partColors[cidx]);
735
QColor c(Qt::darkGray);
736
c.setAlpha(MusEGlobal::config.globalAlphaBlend);
737
QBrush part_bg_brush(MusECore::gGradientFromQColor(c, mwpr.topLeft(), mwpr.bottomLeft()));
738
p.fillRect(mpbgr, part_bg_brush);
743
p.setWorldMatrixEnabled(wmtxen);
746
// TODO: Overridden because we're in units of frames.
747
// After BBT/frame mode is added to Canvas, remove this override and let View or Canvas do it.
748
//---------------------------------------------------------
750
//---------------------------------------------------------
752
void WaveCanvas::drawTickRaster(QPainter& p, int x, int y, int w, int h, int raster)
754
// Changed to draw in device coordinate space instead of virtual, transformed space. Tim.
758
//int mw = mapx(x + w) - mx;
759
//int mw = mapx(x + w) - mx - 1;
760
//int mh = mapy(y + h) - my;
761
//int mh = mapy(y + h) - my - 1;
764
bool wmtxen = p.worldMatrixEnabled();
765
p.setWorldMatrixEnabled(false);
767
int xx,bar1, bar2, beat;
769
// AL::sigmap.tickValues(x, &bar1, &beat, &tick);
770
// AL::sigmap.tickValues(x+w, &bar2, &beat, &tick);
771
AL::sigmap.tickValues(MusEGlobal::tempomap.frame2tick(x), &bar1, &beat, &tick);
772
AL::sigmap.tickValues(MusEGlobal::tempomap.frame2tick(x+w), &bar2, &beat, &tick);
776
int y2 = mapy(y + h) - 1;
777
//printf("View::drawTickRaster x:%d y:%d w:%d h:%d mx:%d my:%d mw:%d mh:%d y2:%d bar1:%d bar2:%d\n", x, y, w, h, mx, my, mw, mh, y2, bar1, bar2);
778
//printf("View::drawTickRaster x:%d y:%d w:%d h:%d my:%d mh:%d y2:%d bar1:%d bar2:%d\n", x, y, w, h, my, mh, y2, bar1, bar2);
779
for (int bar = bar1; bar < bar2; ++bar) {
781
// unsigned xb = AL::sigmap.bar2tick(bar, 0, 0);
782
unsigned xb = AL::sigmap.bar2tick(bar, 0, 0);
783
int xt = mapx(MusEGlobal::tempomap.tick2frame(xb));
785
p.drawLine(xt, my, xt, y2);
788
AL::sigmap.timesig(xb, z, n);
790
if (rmapx(raster) < 8) // grid too dense
792
p.setPen(Qt::lightGray);
795
int xxx = MusEGlobal::tempomap.tick2frame(AL::sigmap.bar2tick(bar, z, 0));
796
//while (MusEGlobal::tempomap.tick2frame(xx) <= xxx) {
798
int xxf = MusEGlobal::tempomap.tick2frame(xx);
801
//int x = mapx(MusEGlobal::tempomap.tick2frame(xx));
803
p.drawLine(x, my, x, y2);
808
for (int beat = 1; beat < z; beat++) {
809
xx = mapx(MusEGlobal::tempomap.tick2frame(AL::sigmap.bar2tick(bar, beat, 0)));
810
//printf(" bar:%d z:%d beat:%d xx:%d\n", bar, z, beat, xx);
811
p.drawLine(xx, my, xx, y2);
815
p.setWorldMatrixEnabled(wmtxen);
818
// TODO: Overridden because we're in units of frames.
819
// After BBT/frame mode is added to Canvas, remove this override and let Canvas do it.
820
//---------------------------------------------------------
822
//---------------------------------------------------------
824
QPoint WaveCanvas::raster(const QPoint& p) const
829
//x = editor->rasterVal(x);
830
x = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(x)));
831
int pitch = y2pitch(p.y());
832
int y = pitch2y(pitch);
836
#define WHEEL_STEPSIZE 40
837
#define WHEEL_DELTA 120
838
//---------------------------------------------------------
840
//---------------------------------------------------------
841
void WaveCanvas::wheelEvent(QWheelEvent* ev)
843
int keyState = ev->modifiers();
845
bool shift = keyState & Qt::ShiftModifier;
846
bool ctrl = keyState & Qt::ControlModifier;
848
if (shift) { // scroll vertically
849
int delta = -ev->delta() / WHEEL_DELTA;
850
int xpixelscale = 5*MusECore::fast_log10(rmapxDev(1));
853
if (xpixelscale <= 0)
856
int scrollstep = WHEEL_STEPSIZE * (delta);
857
///if (ev->state() == Qt::ShiftModifier)
858
// if (((QInputEvent*)ev)->modifiers() == Qt::ShiftModifier)
859
scrollstep = scrollstep / 10;
861
int newXpos = xpos + xpixelscale * scrollstep;
867
emit horizontalScroll((unsigned)newXpos);
870
} else if (ctrl) { // zoom horizontally
872
emit horizontalZoomIn();
874
emit horizontalZoomOut();
876
} else { // scroll horizontally
877
emit mouseWheelMoved(ev->delta() / 10);
882
//---------------------------------------------------------
883
// viewMousePressEvent
884
//---------------------------------------------------------
886
bool WaveCanvas::mousePress(QMouseEvent* event)
888
if (event->modifiers() & Qt::ControlModifier) {
891
button = event->button();
892
QPoint pt = event->pos();
893
//CItem* item = items.find(pt);
894
unsigned x = event->x();
902
if (mode == NORMAL) {
904
if (selectionStart != selectionStop) {
905
selectionStart = selectionStop = 0;
910
selectionStart = selectionStop = x;
911
drag = DRAG_LASSO_START;
918
case Qt::RightButton:
928
//---------------------------------------------------------
929
// viewMouseReleaseEvent
930
//---------------------------------------------------------
932
void WaveCanvas::mouseRelease(const QPoint&)
934
button = Qt::NoButton;
940
//---------------------------------------------------------
942
//---------------------------------------------------------
944
void WaveCanvas::mouseMove(QMouseEvent* event)
950
//emit timeChanged(editor->rasterVal(x));
951
//emit timeChanged(AL::sigmap.raster(x, *_raster));
957
int mstart = mapx(selectionStart);
958
int mstop = mapx(selectionStop);
959
//int mdstart = mapx(dragstartx);
960
QRect r(0, 0, 0, height());
962
if (x < dragstartx) {
963
if(x < selectionStart)
966
r.setWidth((selectionStop >= dragstartx ? mstop : mstart) - mx);
971
r.setWidth(mx - mstart);
974
selectionStop = dragstartx;
977
if(x >= selectionStop)
979
r.setLeft(selectionStart < dragstartx ? mstart : mstop);
980
r.setWidth(mx - (selectionStart < dragstartx ? mstart : mstop));
985
r.setWidth(mstop - mx);
987
selectionStart = dragstartx;
995
case Qt::RightButton:
1002
//---------------------------------------------------------
1004
//---------------------------------------------------------
1006
int WaveCanvas::pitch2y(int) const
1011
//---------------------------------------------------------
1013
//---------------------------------------------------------
1015
int WaveCanvas::y2pitch(int) const
1020
//---------------------------------------------------------
1023
//---------------------------------------------------------
1025
void WaveCanvas::drawItem(QPainter& p, const MusEGui::CItem* item, const QRect& rect)
1027
MusECore::WavePart* wp = (MusECore::WavePart*)(item->part());
1028
if(!wp || !wp->track())
1031
//QRect rr = p.transform().mapRect(rect); // Gives inconsistent positions. Source shows wrong operation for our needs.
1032
QRect rr = map(rect); // Use our own map instead.
1034
QRect mwpr = map(QRect(wp->frame(), 0, wp->lenFrame(), height()));
1036
QRect r = item->bbox();
1038
QRect mr = rr & mer & mwpr;
1042
MusECore::Event event = item->event();
1047
int x2 = mr.right() + 1;
1060
//int t_channels = wp->track()->channels();
1061
int px = wp->frame();
1063
bool wmtxen = p.worldMatrixEnabled();
1064
p.setWorldMatrixEnabled(false);
1068
sx = event.frame() + px + xScale/2;
1069
ex = sx + event.lenFrame();
1070
sx = sx / xScale - xpos;
1071
ex = ex / xScale - xpos;
1078
int pos = (xpos + sx) * xScale + event.spos() - event.frame() - px;
1080
//printf("pos=%d xpos=%d sx=%d ex=%d xScale=%d event.spos=%d event.frame=%d px=%d\n",
1081
// pos, xpos, sx, ex, xScale, event.spos(), event.frame(), px);
1085
if (item->isMoving())
1088
c.setAlpha(MusEGlobal::config.globalAlphaBlend);
1089
QLinearGradient gradient(r.topLeft(), r.bottomLeft());
1090
gradient.setColorAt(0, c);
1091
gradient.setColorAt(1, c.darker());
1092
brush = QBrush(gradient);
1093
p.fillRect(sx, 0, ex - sx, hh, brush);
1096
if (item->isSelected())
1098
QColor c(Qt::black);
1099
c.setAlpha(MusEGlobal::config.globalAlphaBlend);
1100
QLinearGradient gradient(r.topLeft(), r.bottomLeft());
1101
// Use a colour only about 20% lighter than black, rather than the 50% we use in MusECore::gGradientFromQColor
1102
// and is used in darker()/lighter(), so that it is distinguished a bit better from grey non-part tracks.
1103
//c.setRgba(64, 64, 64, c.alpha());
1104
gradient.setColorAt(0, QColor(51, 51, 51, MusEGlobal::config.globalAlphaBlend));
1105
gradient.setColorAt(1, c);
1106
brush = QBrush(gradient);
1107
p.fillRect(sx, 0, ex - sx, hh, brush);
1111
QPen pen(Qt::DashLine);
1112
pen.setColor(Qt::black);
1113
pen.setCosmetic(true);
1115
p.drawRect(sx, 0, ex - sx, hh);
1117
//p.fillRect(sx, 0, ex - sx, hh, brush);
1118
//p.drawRect(sx, 0, ex - sx, hh, brush);
1120
MusECore::SndFileR f = event.sndFile();
1123
p.setWorldMatrixEnabled(wmtxen);
1127
int ev_channels = f.channels();
1128
if (ev_channels == 0) {
1129
p.setWorldMatrixEnabled(wmtxen);
1130
printf("WaveCnvas::drawItem: ev_channels==0! %s\n", f.name().toLatin1().constData());
1134
h = hh / (ev_channels * 2);
1135
int cc = hh % (ev_channels * 2) ? 0 : 1;
1137
unsigned peoffset = px + event.frame() - event.spos();
1139
for (int i = sx; i < ex; i++) {
1141
MusECore::SampleV sa[f.channels()];
1142
f.read(sa, xScale, pos);
1144
if (pos < event.spos())
1147
int selectionStartPos = selectionStart - peoffset; // Offset transformed to event coords
1148
int selectionStopPos = selectionStop - peoffset;
1150
for (int k = 0; k < ev_channels; ++k) {
1151
int kk = k % f.channels();
1152
int peak = (sa[kk].peak * (h - 1)) / yScale;
1153
int rms = (sa[kk].rms * (h - 1)) / yScale;
1158
QColor peak_color = QColor(Qt::darkGray);
1159
QColor rms_color = QColor(Qt::black);
1161
// Changed by T356. Reduces (but not eliminates) drawing artifacts. (TODO Cause of artifacts gone, correct this now.)
1162
//if (pos > selectionStartPos && pos < selectionStopPos) {
1163
if (pos > selectionStartPos && pos <= selectionStopPos) {
1165
peak_color = QColor(Qt::lightGray);
1166
rms_color = QColor(Qt::white);
1168
p.setPen(QColor(Qt::black));
1169
p.drawLine(i, y - h + cc, i, y + h - cc );
1171
p.setPen(peak_color);
1172
p.drawLine(i, y - peak - cc, i, y + peak);
1173
p.setPen(rms_color);
1174
p.drawLine(i, y - rms - cc, i, y + rms);
1180
int hn = hh / ev_channels;
1182
for (int i = 0; i < ev_channels; ++i) {
1184
int center = hhn + h2;
1185
p.setPen(QColor(i & i ? Qt::red : Qt::blue));
1186
p.drawLine(sx, center, ex, center);
1187
p.setPen(QColor(Qt::black));
1188
p.drawLine(sx, h2, ex, h2);
1191
p.setWorldMatrixEnabled(wmtxen);
1194
//---------------------------------------------------------
1196
//---------------------------------------------------------
1197
void WaveCanvas::drawTopItem(QPainter& , const QRect&)
1200
//---------------------------------------------------------
1202
// draws moving items
1203
//---------------------------------------------------------
1205
void WaveCanvas::drawMoving(QPainter& p, const MusEGui::CItem* item, const QRect& rect)
1207
QRect mr = QRect(item->mp().x(), item->mp().y(), item->width(), item->height());
1208
mr = mr.intersected(rect);
1211
p.setPen(Qt::black);
1212
p.setBrush(QColor(0, 128, 0, 128)); // TODO: Pick a better colour, or use part colours, or grey?
1216
//---------------------------------------------------------
1217
// viewMouseDoubleClickEvent
1218
//---------------------------------------------------------
1220
void WaveCanvas::viewMouseDoubleClickEvent(QMouseEvent* event)
1222
if ((_tool != MusEGui::PointerTool) && (event->button() != Qt::LeftButton)) {
1228
//---------------------------------------------------------
1230
//---------------------------------------------------------
1232
MusECore::Undo WaveCanvas::moveCanvasItems(MusEGui::CItemList& items, int /*dp*/, int dx, DragType dtype)
1234
if(editor->parts()->empty())
1235
return MusECore::Undo(); //return empty list
1237
MusECore::PartsToChangeMap parts2change;
1238
MusECore::Undo operations;
1240
for(MusECore::iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip)
1242
MusECore::Part* part = ip->second;
1246
int npartoffset = 0;
1247
for(MusEGui::iCItem ici = items.begin(); ici != items.end(); ++ici)
1249
MusEGui::CItem* ci = ici->second;
1250
if(ci->part() != part)
1253
int x = ci->pos().x() + dx;
1254
//int y = pitch2y(y2pitch(ci->pos().y()) + dp);
1256
QPoint newpos = raster(QPoint(x, y));
1258
// Test moving the item...
1259
WEvent* wevent = (WEvent*) ci;
1260
MusECore::Event event = wevent->event();
1264
int nframe = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(x))) - part->frame();
1267
int diff = nframe + event.lenFrame() - part->lenFrame();
1269
// If moving the item would require a new part size...
1270
if(diff > npartoffset)
1276
MusECore::iPartToChange ip2c = parts2change.find(part);
1277
if(ip2c == parts2change.end())
1279
MusECore::PartToChange p2c = {0, npartoffset};
1280
parts2change.insert(std::pair<MusECore::Part*, MusECore::PartToChange> (part, p2c));
1283
ip2c->second.xdiff = npartoffset;
1287
bool forbidden=false;
1288
for(MusECore::iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c)
1290
MusECore::Part* opart = ip2c->first;
1291
if (opart->hasHiddenEvents())
1301
std::vector< MusEGui::CItem* > doneList;
1302
typedef std::vector< MusEGui::CItem* >::iterator iDoneList;
1304
for(MusEGui::iCItem ici = items.begin(); ici != items.end(); ++ici)
1306
MusEGui::CItem* ci = ici->second;
1308
int x = ci->pos().x();
1309
//int y = ci->pos().y();
1311
//int ny = pitch2y(y2pitch(y) + dp);
1313
QPoint newpos = raster(QPoint(nx, ny));
1314
selectItem(ci, true);
1317
for(idl = doneList.begin(); idl != doneList.end(); ++idl)
1318
// This compares EventBase pointers to see if they're the same...
1319
if((*idl)->event() == ci->event())
1322
// Do not process if the event has already been processed (meaning it's an event in a clone part)...
1323
if (idl == doneList.end())
1325
moveItem(operations, ci, newpos, dtype); // always returns true. if not, change is necessary here!
1326
doneList.push_back(ci);
1330
if(moving.size() == 1)
1331
itemReleased(curItem, newpos);
1333
if(dtype == MOVE_COPY || dtype == MOVE_CLONE)
1334
selectItem(ci, false);
1337
for(MusECore::iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c)
1339
MusECore::Part* opart = ip2c->first;
1340
int diff = ip2c->second.xdiff;
1342
//schedule_resize_all_same_len_clone_parts(opart, opart->lenTick() + diff, operations);
1343
schedule_resize_all_same_len_clone_parts(opart, opart->lenFrame() + diff, operations);
1350
return MusECore::Undo(); //return empty list
1354
//---------------------------------------------------------
1356
// called after moving an object
1357
//---------------------------------------------------------
1359
bool WaveCanvas::moveItem(MusECore::Undo& operations, MusEGui::CItem* item, const QPoint& pos, DragType dtype)
1361
WEvent* wevent = (WEvent*) item;
1362
MusECore::Event event = wevent->event();
1363
//int npitch = y2pitch(pos.y());
1364
MusECore::Event newEvent = event.clone();
1369
MusECore::Part* part = wevent->part();
1370
int nframe = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(x))) - part->frame();
1373
newEvent.setFrame(nframe);
1374
newEvent.setLenFrame(event.lenFrame());
1376
// don't check, whether the new event is within the part
1377
// at this place. with operation groups, the part isn't
1378
// resized yet. (flo93)
1380
if (dtype == MOVE_COPY || dtype == MOVE_CLONE)
1381
operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddEvent, newEvent, part, false, false));
1383
operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false));
1388
//---------------------------------------------------------
1389
// newItem(p, state)
1390
//---------------------------------------------------------
1392
MusEGui::CItem* WaveCanvas::newItem(const QPoint& p, int)
1394
int frame = MusEGlobal::tempomap.tick2frame(editor->rasterVal1(MusEGlobal::tempomap.frame2tick(p.x())));
1395
int len = p.x() - frame;
1396
frame -= curPart->frame();
1399
MusECore::Event e = MusECore::Event(MusECore::Wave);
1402
WEvent* we = new WEvent(e, curPart, height());
1406
void WaveCanvas::newItem(MusEGui::CItem* item, bool noSnap)
1408
WEvent* wevent = (WEvent*) item;
1409
MusECore::Event event = wevent->event();
1413
int w = item->width();
1416
//x = editor->rasterVal1(x); //round down
1417
x = MusEGlobal::tempomap.tick2frame(editor->rasterVal1(MusEGlobal::tempomap.frame2tick(x))); //round down
1418
//w = editor->rasterVal(x + w) - x;
1419
w = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(x + w))) - x;
1421
//w = editor->raster();
1422
w = MusEGlobal::tempomap.tick2frame(editor->raster());
1424
MusECore::Part* part = wevent->part();
1425
event.setFrame(x - part->frame());
1426
event.setLenFrame(w);
1428
MusECore::Undo operations;
1429
int diff = event.endFrame() - part->lenFrame();
1431
if (! ((diff > 0) && part->hasHiddenEvents()) ) //operation is allowed
1433
operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddEvent,event, part, false, false));
1435
if (diff > 0)// part must be extended?
1437
//schedule_resize_all_same_len_clone_parts(part, event.endTick(), operations);
1438
schedule_resize_all_same_len_clone_parts(part, event.endFrame(), operations);
1439
printf("newItem: extending\n");
1442
MusEGlobal::song->applyOperationGroup(operations);
1444
else // forbid action by not applying it
1445
songChanged(SC_EVENT_INSERTED); //this forces an update of the itemlist, which is neccessary
1446
//to remove "forbidden" events from the list again
1449
//---------------------------------------------------------
1451
//---------------------------------------------------------
1453
void WaveCanvas::resizeItem(MusEGui::CItem* item, bool noSnap, bool) // experimental changes to try dynamically extending parts
1455
WEvent* wevent = (WEvent*) item;
1456
MusECore::Event event = wevent->event();
1457
MusECore::Event newEvent = event.clone();
1460
MusECore::Part* part = wevent->part();
1463
len = wevent->width();
1465
unsigned frame = event.frame() + part->frame();
1466
//len = editor->rasterVal(tick + wevent->width()) - tick;
1467
len = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(frame + wevent->width()))) - frame;
1469
//len = editor->raster();
1470
len = MusEGlobal::tempomap.tick2frame(editor->raster());
1473
MusECore::Undo operations;
1474
//int diff = event.tick()+len-part->lenTick();
1475
int diff = event.frame() + len - part->lenFrame();
1477
if (! ((diff > 0) && part->hasHiddenEvents()) ) //operation is allowed
1479
//newEvent.setLenTick(len);
1480
newEvent.setLenFrame(len);
1481
operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent,newEvent, event, wevent->part(), false, false));
1483
if (diff > 0)// part must be extended?
1485
//schedule_resize_all_same_len_clone_parts(part, event.tick()+len, operations);
1486
schedule_resize_all_same_len_clone_parts(part, event.frame() + len, operations);
1487
printf("resizeItem: extending\n");
1490
//else forbid action by not performing it
1491
MusEGlobal::song->applyOperationGroup(operations);
1492
songChanged(SC_EVENT_MODIFIED); //this forces an update of the itemlist, which is neccessary
1493
//to remove "forbidden" events from the list again
1496
//---------------------------------------------------------
1498
//---------------------------------------------------------
1500
bool WaveCanvas::deleteItem(MusEGui::CItem* item)
1502
WEvent* wevent = (WEvent*) item;
1503
if (wevent->part() == curPart) {
1504
MusECore::Event ev = wevent->event();
1505
// Indicate do undo, and do not do port controller values and clone parts.
1506
MusEGlobal::audio->msgDeleteEvent(ev, curPart, true, false, false);
1512
//---------------------------------------------------------
1514
//---------------------------------------------------------
1516
void WaveCanvas::adjustWaveOffset()
1518
bool have_selected = false;
1519
int init_offset = 0;
1521
for (MusEGui::iCItem k = items.begin(); k != items.end(); ++k)
1523
if (k->second->isSelected())
1525
have_selected = true;
1526
init_offset = k->second->event().spos();
1533
QMessageBox::information(this,
1535
QWidget::tr("No wave events selected."));
1540
int offset = QInputDialog::getInt(this,
1541
tr("Adjust Wave Offset"),
1542
tr("Wave offset (frames)"),
1549
MusECore::Undo operations;
1551
// FIXME: Respect clones! If operating on two selected clones of the same part, an extra event is created!
1552
// Check - Is it really this code's problem? Seems so, other operations like moving an event seem OK.
1553
for(MusEGui::iCItem ici = items.begin(); ici != items.end(); ++ici)
1555
if(ici->second->isSelected())
1557
MusECore::Event oldEvent = ici->second->event();
1558
if(oldEvent.spos() != offset)
1560
MusECore::Part* part = ici->second->part();
1561
MusECore::Event newEvent = oldEvent.clone();
1562
newEvent.setSpos(offset);
1563
// Do not do port controller values and clone parts.
1564
operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, oldEvent, part, false, false));
1569
MusEGlobal::song->applyOperationGroup(operations);
1574
//---------------------------------------------------------
1576
//---------------------------------------------------------
1578
void WaveCanvas::drawCanvas(QPainter& p, const QRect& rect)
1582
int w = rect.width();
1583
int h = rect.height();
1585
//---------------------------------------------------
1587
//---------------------------------------------------
1589
drawTickRaster(p, x, y, w, h, editor->raster());
1592
//---------------------------------------------------------
1594
//---------------------------------------------------------
1596
void WaveCanvas::waveCmd(int cmd)
1598
// TODO: New WaveCanvas: Convert this routine to frames.
1605
spos -= 1; // Nudge by -1, then snap down with raster1.
1606
spos = AL::sigmap.raster1(spos, editor->rasterStep(pos[0]));
1610
MusECore::Pos p(spos,true);
1611
MusEGlobal::song->setPos(0, p, true, true, true);
1616
int spos = AL::sigmap.raster2(pos[0] + 1, editor->rasterStep(pos[0])); // Nudge by +1, then snap up with raster2.
1617
MusECore::Pos p(spos,true);
1618
MusEGlobal::song->setPos(0, p, true, true, true);
1621
case CMD_LEFT_NOSNAP:
1623
int spos = pos[0] - editor->rasterStep(pos[0]);
1626
MusECore::Pos p(spos,true);
1627
MusEGlobal::song->setPos(0, p, true, true, true); //CDW
1630
case CMD_RIGHT_NOSNAP:
1632
MusECore::Pos p(pos[0] + editor->rasterStep(pos[0]), true);
1633
MusEGlobal::song->setPos(0, p, true, true, true); //CDW
1638
if (pos[0] < start() || pos[0] >= end())
1640
MusECore::MidiPart* part = (MusECore::MidiPart*)curPart;
1645
MusECore::EventList* el = part->events();
1646
MusECore::Undo operations;
1648
std::list <MusECore::Event> elist;
1649
for (MusECore::iEvent e = el->lower_bound(pos[0] - part->tick()); e != el->end(); ++e)
1650
elist.push_back((MusECore::Event)e->second);
1651
for (std::list<MusECore::Event>::iterator i = elist.begin(); i != elist.end(); ++i) {
1652
MusECore::Event event = *i;
1653
MusECore::Event newEvent = event.clone();
1654
newEvent.setTick(event.tick() + editor->raster());// - part->tick()); DELETETHIS
1655
// Do not do port controller values and clone parts.
1656
operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false));
1658
MusEGlobal::song->applyOperationGroup(operations);
1660
MusECore::Pos p(editor->rasterVal(pos[0] + editor->rasterStep(pos[0])), true);
1661
MusEGlobal::song->setPos(0, p, true, false, true);
1665
if (pos[0] < start() || pos[0] >= end())
1668
MusECore::MidiPart* part = (MusECore::MidiPart*)curPart;
1672
MusECore::Undo operations;
1673
MusECore::EventList* el = part->events();
1675
std::list<MusECore::Event> elist;
1676
for (MusECore::iEvent e = el->lower_bound(pos[0]); e != el->end(); ++e)
1677
elist.push_back((MusECore::Event)e->second);
1678
for (std::list<MusECore::Event>::iterator i = elist.begin(); i != elist.end(); ++i) {
1679
MusECore::Event event = *i;
1680
MusECore::Event newEvent = event.clone();
1681
newEvent.setTick(event.tick() - editor->raster() - part->tick());
1682
// Do not do port controller values and clone parts.
1683
operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false));
1685
MusEGlobal::song->applyOperationGroup(operations);
1686
MusECore::Pos p(editor->rasterVal(pos[0] - editor->rasterStep(pos[0])), true);
1687
MusEGlobal::song->setPos(0, p, true, false, true);
1693
//---------------------------------------------------------
1695
// pulldown menu commands
1696
//---------------------------------------------------------
1698
void WaveCanvas::cmd(int cmd)
1700
int modifyoperation = -1;
1701
double paramA = 0.0;
1703
case CMD_SELECT_ALL: // select all
1704
if (tool() == MusEGui::CursorTool)
1706
if (!editor->parts()->empty()) {
1707
MusECore::iPart iBeg = editor->parts()->begin();
1708
MusECore::iPart iEnd = editor->parts()->end();
1710
MusECore::WavePart* beg = (MusECore::WavePart*) iBeg->second;
1711
MusECore::WavePart* end = (MusECore::WavePart*) iEnd->second;
1712
selectionStart = beg->frame();
1713
selectionStop = end->frame() + end->lenFrame();
1717
for (MusEGui::iCItem k = items.begin(); k != items.end(); ++k) {
1718
if (!k->second->isSelected())
1719
selectItem(k->second, true);
1722
case CMD_SELECT_NONE: // select none
1723
selectionStart = selectionStop = 0;
1726
case CMD_SELECT_INVERT: // invert selection
1727
for (MusEGui::iCItem k = items.begin(); k != items.end(); ++k) {
1728
selectItem(k->second, !k->second->isSelected());
1731
case CMD_SELECT_ILOOP: // select inside loop
1732
for (MusEGui::iCItem k = items.begin(); k != items.end(); ++k) {
1733
WEvent* wevent = (WEvent*)(k->second);
1734
MusECore::Part* part = wevent->part();
1735
MusECore::Event event = wevent->event();
1736
unsigned tick = event.tick() + part->tick();
1737
if (tick < MusEGlobal::song->lpos() || tick >= MusEGlobal::song->rpos())
1738
selectItem(k->second, false);
1740
selectItem(k->second, true);
1743
case CMD_SELECT_OLOOP: // select outside loop
1744
for (MusEGui::iCItem k = items.begin(); k != items.end(); ++k) {
1745
WEvent* wevent = (WEvent*)(k->second);
1746
MusECore::Part* part = wevent->part();
1747
MusECore::Event event = wevent->event();
1748
unsigned tick = event.tick() + part->tick();
1749
if (tick < MusEGlobal::song->lpos() || tick >= MusEGlobal::song->rpos())
1750
selectItem(k->second, true);
1752
selectItem(k->second, false);
1755
case CMD_SELECT_PREV_PART: // select previous part
1757
MusECore::Part* pt = editor->curCanvasPart();
1758
MusECore::Part* newpt = pt;
1759
MusECore::PartList* pl = editor->parts();
1760
for(MusECore::iPart ip = pl->begin(); ip != pl->end(); ++ip)
1761
if(ip->second == pt)
1763
if(ip == pl->begin())
1770
editor->setCurCanvasPart(newpt);
1773
case CMD_SELECT_NEXT_PART: // select next part
1775
MusECore::Part* pt = editor->curCanvasPart();
1776
MusECore::Part* newpt = pt;
1777
MusECore::PartList* pl = editor->parts();
1778
for(MusECore::iPart ip = pl->begin(); ip != pl->end(); ++ip)
1779
if(ip->second == pt)
1788
editor->setCurCanvasPart(newpt);
1792
case CMD_ADJUST_WAVE_OFFSET:
1796
case CMD_EDIT_EXTERNAL:
1797
modifyoperation = EDIT_EXTERNAL;
1801
modifyoperation = COPY;
1804
modifyoperation = CUT;
1806
case CMD_EDIT_PASTE:
1807
modifyoperation = PASTE;
1811
modifyoperation = MUTE;
1815
modifyoperation = NORMALIZE;
1819
modifyoperation = FADE_IN;
1823
modifyoperation = FADE_OUT;
1827
modifyoperation = REVERSE;
1830
case CMD_GAIN_FREE: {
1831
EditGain* editGain = new EditGain(this, lastGainvalue);
1832
if (editGain->exec() == QDialog::Accepted) {
1833
lastGainvalue = editGain->getGain();
1834
modifyoperation = GAIN;
1835
paramA = (double)lastGainvalue / 100.0;
1842
modifyoperation = GAIN;
1847
modifyoperation = GAIN;
1852
modifyoperation = GAIN;
1857
modifyoperation = GAIN;
1862
modifyoperation = GAIN;
1866
case CMD_CREATE_PART_REGION:
1868
// create a new part and put in the copy buffer
1869
MusECore::Part* pt = editor->curCanvasPart();
1870
if (pt == 0 || pt->track()->type() != MusECore::Track::WAVE)
1872
MusECore::WavePart *origPart = (MusECore::WavePart*)pt;
1873
if (MusEGlobal::song->lpos() < origPart->tick() || MusEGlobal::song->rpos() > origPart->endTick())
1875
QMessageBox::warning(this, tr("Part creation failed"),
1876
tr("Left and right position markers must be placed inside the current part."),
1877
QMessageBox::Ok, QMessageBox::Ok);
1880
MusECore::WavePart *tempPart = new MusECore::WavePart(origPart->track());
1881
unsigned origFrame = origPart->frame();
1882
unsigned frameDistance = MusEGlobal::song->lPos().frame() - origFrame;
1883
tempPart->setPos(MusEGlobal::song->lpos());
1884
tempPart->setLenTick(MusEGlobal::song->rpos() - MusEGlobal::song->lpos());
1885
// loop through the events and set them accordingly
1886
for (MusECore::iEvent iWaveEvent = origPart->events()->begin(); iWaveEvent != origPart->events()->end(); iWaveEvent++)
1888
// TODO: handle multiple events correctly,
1889
// the math for subsequent events isn't correct
1890
MusECore::Event &ev = iWaveEvent->second;
1891
MusECore::Event *newEvent = new MusECore::Event(ev.clone());
1892
newEvent->setSpos(ev.spos() + frameDistance);
1893
newEvent->setLenTick(MusEGlobal::song->rpos() - MusEGlobal::song->lpos());
1894
tempPart->addEvent(*newEvent);
1896
std::set<MusECore::Part*> partList;
1897
partList.insert(tempPart);
1899
QMimeData *mimeData = MusECore::parts_to_mime(partList);
1900
QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
1901
QMessageBox::information(this, tr("Part created"),
1902
tr("The selected region has been copied to the clipboard and can be pasted in the arranger."),
1903
QMessageBox::Ok, QMessageBox::Ok);
1906
case CMD_ERASE_MEASURE:
1907
case CMD_DELETE_MEASURE:
1908
case CMD_CREATE_MEASURE:
1911
// printf("unknown ecanvas cmd %d\n", cmd);
1915
if (modifyoperation != -1) {
1916
if (selectionStart == selectionStop && modifyoperation!=PASTE) {
1917
printf("No selection. Ignoring\n"); //@!TODO: Disable menu options when no selection
1918
QMessageBox::information(this,
1920
QWidget::tr("No selection. Ignoring"));
1925
//if(!modifyWarnedYet)
1927
// modifyWarnedYet = true;
1928
// if(QMessageBox::warning(this, QString("Muse"),
1929
// tr("Warning! Muse currently operates directly on the sound file.\n"
1930
// "Undo is supported, but NOT after exit, WITH OR WITHOUT A SAVE!"), tr("&Ok"), tr("&Cancel"),
1931
// QString::null, 0, 1 ) != 0)
1934
modifySelection(modifyoperation, selectionStart, selectionStop, paramA);
1941
//---------------------------------------------------------
1943
//---------------------------------------------------------
1944
MusECore::WaveSelectionList WaveCanvas::getSelection(unsigned startpos, unsigned stoppos)
1946
MusECore::WaveSelectionList selection;
1948
for (MusECore::iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) {
1949
MusECore::WavePart* wp = (MusECore::WavePart*)(ip->second);
1950
unsigned part_offset = wp->frame();
1952
MusECore::EventList* el = wp->events();
1953
//printf("eventlist length=%d\n",el->size());
1955
for (MusECore::iEvent e = el->begin(); e != el->end(); ++e) {
1956
MusECore::Event event = e->second;
1959
MusECore::SndFileR file = event.sndFile();
1963
// Respect part end: Don't modify stuff outside of part boundary.
1964
unsigned elen = event.lenFrame();
1965
if(event.frame() + event.lenFrame() >= wp->lenFrame())
1967
// Adjust apparent operation length:
1968
if(event.frame() > wp->lenFrame())
1971
elen = wp->lenFrame() - event.frame();
1974
unsigned event_offset = event.frame() + part_offset;
1975
unsigned event_startpos = event.spos();
1976
unsigned event_length = elen + event.spos();
1977
unsigned event_end = event_offset + event_length;
1978
//printf("startpos=%d stoppos=%d part_offset=%d event_offset=%d event_startpos=%d event_length=%d event_end=%d\n", startpos, stoppos, part_offset, event_offset, event_startpos, event_length, event_end);
1980
if (!(event_end <= startpos || event_offset > stoppos)) {
1981
int tmp_sx = startpos - event_offset + event_startpos;
1982
int tmp_ex = stoppos - event_offset + event_startpos;
1986
tmp_sx < (int)event_startpos ? sx = event_startpos : sx = tmp_sx;
1987
tmp_ex > (int)event_length ? ex = event_length : ex = tmp_ex;
1989
//printf("Event data affected: %d->%d filename:%s\n", sx, ex, file.name().toLatin1().constData());
1990
MusECore::WaveEventSelection s;
1994
//printf("sx=%d ex=%d\n",sx,ex);
1995
selection.push_back(s);
2003
//---------------------------------------------------------
2005
//---------------------------------------------------------
2006
void WaveCanvas::modifySelection(int operation, unsigned startpos, unsigned stoppos, double paramA)
2008
if (operation == PASTE) {
2009
// we need to redefine startpos and stoppos
2010
if (copiedPart =="")
2012
MusECore::SndFile pasteFile(copiedPart);
2013
pasteFile.openRead();
2015
stoppos = startpos+ pasteFile.samples(); // possibly this is wrong if there are tempo changes
2021
// Copy on Write: Check if some files need to be copied, either because they are not
2022
// writable, or more than one independent (non-clone) wave event shares a wave file.
2025
MusECore::WaveSelectionList selection = getSelection(startpos, stoppos);
2026
std::vector<MusECore::SndFileR> copy_files_proj_dir;
2027
for(MusECore::iWaveSelection i = selection.begin(); i != selection.end(); i++)
2029
MusECore::WaveEventSelection w = *i;
2030
MusECore::SndFileR file = w.event.sndFile();
2031
if(file.checkCopyOnWrite())
2033
std::vector<MusECore::SndFileR>::iterator i = copy_files_proj_dir.begin();
2034
for( ; i != copy_files_proj_dir.end(); ++i)
2036
if(i->canonicalPath() == file.canonicalPath())
2039
if(i == copy_files_proj_dir.end())
2040
copy_files_proj_dir.push_back(file);
2043
if(!copy_files_proj_dir.empty())
2045
CopyOnWriteDialog* dlg = new CopyOnWriteDialog();
2046
for(std::vector<MusECore::SndFileR>::iterator i = copy_files_proj_dir.begin(); i != copy_files_proj_dir.end(); ++i)
2048
qint64 sz = QFile(i->canonicalPath()).size();
2051
s += QString::number(sz / 1048576) + "MB ";
2054
s += QString::number(sz / 1024) + "KB ";
2056
s += QString::number(sz) + "B ";
2057
s += i->canonicalPath();
2058
dlg->addProjDirFile(s);
2060
int rv = dlg->exec();
2062
if(rv != QDialog::Accepted)
2064
// Has a project been created yet?
2065
if(MusEGlobal::museProject == MusEGlobal::museProjectInitPath) // && MusEGlobal::config.useProjectSaveDialog
2067
// No project, we need to create one.
2068
if(!MusEGlobal::muse->saveAs())
2069
return; // No project, don't want to copy without one.
2070
//setFocus(); // For some reason focus is given away to Arranger
2072
for(MusECore::iWaveSelection i = selection.begin(); i != selection.end(); i++)
2074
MusECore::WaveEventSelection w = *i;
2075
MusECore::SndFileR file = w.event.sndFile();
2076
if(!file.checkCopyOnWrite()) // Make sure to re-check
2078
QString filePath = MusEGlobal::museProject + QString("/") + file.name();
2079
QString newFilePath;
2080
if(MusECore::getUniqueFileName(filePath, newFilePath))
2083
QFile qf(file.canonicalPath());
2084
if(!qf.copy(newFilePath)) // Copy the file
2086
printf("MusE Error: Could not copy to new sound file (file exists?): %s\n", newFilePath.toLatin1().constData());
2087
continue; // Let's not overwrite an existing file
2090
QFile nqf(newFilePath);
2091
// Need to make sure some permissions are set...
2092
QFile::Permissions pm = nqf.permissions();
2093
if(!(pm & QFile::ReadOwner))
2095
pm |= QFile::ReadOwner;
2096
if(!nqf.setPermissions(pm))
2098
printf("MusE Error: Could not set read owner permissions on new sound file: %s\n", newFilePath.toLatin1().constData());
2102
if(!(pm & QFile::WriteOwner))
2104
pm |= QFile::WriteOwner;
2105
if(!nqf.setPermissions(pm))
2107
printf("MusE Error: Could not set write owner permissions on new sound file: %s\n", newFilePath.toLatin1().constData());
2111
if(!(pm & QFile::ReadUser))
2113
pm |= QFile::ReadUser;
2114
if(!nqf.setPermissions(pm))
2116
printf("MusE Error: Could not set read user permissions on new sound file: %s\n", newFilePath.toLatin1().constData());
2120
if(!(pm & QFile::WriteUser))
2122
pm |= QFile::WriteUser;
2123
if(!nqf.setPermissions(pm))
2125
printf("MusE Error: Could not set write user permissions on new sound file: %s\n", newFilePath.toLatin1().constData());
2129
MusECore::SndFile* newSF = new MusECore::SndFile(newFilePath);
2130
MusECore::SndFileR newSFR(newSF); // Create a sndFileR for the new file
2131
if(newSFR.openRead())
2133
printf("MusE Error: Could not open new sound file: %s\n", newSFR.canonicalPath().toLatin1().constData());
2134
continue; // newSF will be deleted when newSFR goes out of scope and is deleted
2136
MusEGlobal::audio->msgIdle(true);
2137
w.event.sndFile().close(); // Close the old file.
2138
// NOTE: For now, don't bother providing undo for this. Reason: If the user undoes
2139
// and then modifies again, it will prompt to create new copies each time. There is
2140
// no mechanism ("touched"?) to tell if an existing copy would be suitable to just 'drop in'.
2141
// It would help if we deleted the wave file copies upon undo, but not too crazy about that.
2142
// So since the copy has already been created and "there it is", we might as well use it.
2143
// It means that events and even undo items BEFORE this operation will point to this
2144
// NEW wave file (as if they always did). It also means the user CANNOT change back
2145
// to the old file... Oh well, this IS Copy On Write.
2146
// FIXME: Find a conceptual way to make undo work with or without deleting the copies.
2147
w.event.setSndFile(newSFR); // Set the new file.
2148
MusEGlobal::audio->msgIdle(false);
2153
MusEGlobal::song->startUndo();
2154
for (MusECore::iWaveSelection i = selection.begin(); i != selection.end(); i++) {
2155
MusECore::WaveEventSelection w = *i;
2156
MusECore::SndFileR file = w.event.sndFile();
2157
unsigned sx = w.startframe;
2158
unsigned ex = w.endframe;
2159
unsigned file_channels = file.channels();
2161
QString tmpWavFile = QString::null;
2162
if (!MusEGlobal::getUniqueTmpfileName("tmp_musewav",".wav", tmpWavFile)) {
2166
MusEGlobal::audio->msgIdle(true); // Not good with playback during operations
2167
MusECore::SndFile tmpFile(tmpWavFile);
2168
tmpFile.setFormat(file.format(), file_channels, file.samplerate());
2169
if (tmpFile.openWrite()) {
2170
MusEGlobal::audio->msgIdle(false);
2171
printf("Could not open temporary file...\n");
2176
// Write out data that will be changed to temp file
2178
unsigned tmpdatalen = ex - sx;
2179
off_t tmpdataoffset = sx;
2180
float* tmpdata[file_channels];
2182
for (unsigned i=0; i<file_channels; i++) {
2183
tmpdata[i] = new float[tmpdatalen];
2185
file.seek(tmpdataoffset, 0);
2186
file.readWithHeap(file_channels, tmpdata, tmpdatalen);
2188
tmpFile.write(file_channels, tmpdata, tmpdatalen);
2194
muteSelection(file_channels, tmpdata, tmpdatalen);
2198
normalizeSelection(file_channels, tmpdata, tmpdatalen);
2202
fadeInSelection(file_channels, tmpdata, tmpdatalen);
2206
fadeOutSelection(file_channels, tmpdata, tmpdatalen);
2210
reverseSelection(file_channels, tmpdata, tmpdatalen);
2214
applyGain(file_channels, tmpdata, tmpdatalen, paramA);
2217
copySelection(file_channels, tmpdata, tmpdatalen, true, file.format(), file.samplerate());
2220
copySelection(file_channels, tmpdata, tmpdatalen, false, file.format(), file.samplerate());
2224
MusECore::SndFile pasteFile(copiedPart);
2225
pasteFile.openRead();
2226
pasteFile.seek(tmpdataoffset, 0);
2227
pasteFile.readWithHeap(file_channels, tmpdata, tmpdatalen);
2232
editExternal(file.format(), file.samplerate(), file_channels, tmpdata, tmpdatalen);
2236
printf("Error: Default state reached in modifySelection\n");
2242
file.seek(tmpdataoffset, 0);
2243
file.write(file_channels, tmpdata, tmpdatalen);
2248
for (unsigned i=0; i<file_channels; i++) {
2249
delete[] tmpdata[i];
2253
MusEGlobal::song->cmdChangeWave(file.dirPath() + "/" + file.name(), tmpWavFile, sx, ex);
2254
MusEGlobal::audio->msgIdle(false); // Not good with playback during operations
2256
MusEGlobal::song->endUndo(SC_CLIP_MODIFIED);
2260
//---------------------------------------------------------
2262
//---------------------------------------------------------
2263
void WaveCanvas::copySelection(unsigned file_channels, float** tmpdata, unsigned length, bool blankData, unsigned format, unsigned sampleRate)
2265
if (copiedPart!="") {
2266
QFile::remove(copiedPart);
2268
if (!MusEGlobal::getUniqueTmpfileName("tmp_musewav",".wav", copiedPart)) {
2272
MusECore::SndFile tmpFile(copiedPart);
2273
tmpFile.setFormat(format, file_channels, sampleRate);
2274
tmpFile.openWrite();
2275
tmpFile.write(file_channels, tmpdata, length);
2279
// Set everything to 0!
2280
for (unsigned i=0; i<file_channels; i++) {
2281
for (unsigned j=0; j<length; j++) {
2288
//---------------------------------------------------------
2290
//---------------------------------------------------------
2291
void WaveCanvas::muteSelection(unsigned channels, float** data, unsigned length)
2293
// Set everything to 0!
2294
for (unsigned i=0; i<channels; i++) {
2295
for (unsigned j=0; j<length; j++) {
2301
//---------------------------------------------------------
2302
// normalizeSelection
2303
//---------------------------------------------------------
2304
void WaveCanvas::normalizeSelection(unsigned channels, float** data, unsigned length)
2306
float loudest = 0.0;
2308
for (unsigned i=0; i<channels; i++) {
2309
for (unsigned j=0; j<length; j++) {
2310
if (data[i][j] > loudest)
2311
loudest = data[i][j];
2315
double scale = 0.99 / (double)loudest;
2317
for (unsigned i=0; i<channels; i++) {
2318
for (unsigned j=0; j<length; j++) {
2319
data[i][j] = (float) ((double)data[i][j] * scale);
2324
//---------------------------------------------------------
2326
//---------------------------------------------------------
2327
void WaveCanvas::fadeInSelection(unsigned channels, float** data, unsigned length)
2329
for (unsigned i=0; i<channels; i++) {
2330
for (unsigned j=0; j<length; j++) {
2331
double scale = (double) j / (double)length ;
2332
data[i][j] = (float) ((double)data[i][j] * scale);
2337
//---------------------------------------------------------
2339
//---------------------------------------------------------
2340
void WaveCanvas::fadeOutSelection(unsigned channels, float** data, unsigned length)
2342
for (unsigned i=0; i<channels; i++) {
2343
for (unsigned j=0; j<length; j++) {
2344
double scale = (double) (length - j) / (double)length ;
2345
data[i][j] = (float) ((double)data[i][j] * scale);
2350
//---------------------------------------------------------
2352
//---------------------------------------------------------
2353
void WaveCanvas::reverseSelection(unsigned channels, float** data, unsigned length)
2357
for (unsigned i=0; i<channels; i++) {
2358
for (unsigned j=0; j<length/2; j++) {
2359
float tmpl = data[i][j];
2360
float tmpr = data[i][length - j - 1];
2362
data[i][length - j - 1] = tmpl;
2366
//---------------------------------------------------------
2368
//---------------------------------------------------------
2369
void WaveCanvas::applyGain(unsigned channels, float** data, unsigned length, double gain)
2371
for (unsigned i=0; i<channels; i++) {
2372
for (unsigned j=0; j<length; j++) {
2373
data[i][j] = (float) ((double)data[i][j] * gain);
2378
//---------------------------------------------------------
2380
//---------------------------------------------------------
2381
void WaveCanvas::editExternal(unsigned file_format, unsigned file_samplerate, unsigned file_channels, float** tmpdata, unsigned tmpdatalen)
2383
// Create yet another tmp-file
2384
QString exttmpFileName;
2385
if (!MusEGlobal::getUniqueTmpfileName("tmp_musewav",".wav", exttmpFileName)) {
2386
printf("Could not create temp file - aborting...\n");
2390
MusECore::SndFile exttmpFile(exttmpFileName);
2391
exttmpFile.setFormat(file_format, file_channels, file_samplerate);
2392
if (exttmpFile.openWrite()) {
2393
printf("Could not open temporary file...\n");
2396
// Write out change-data to this file:
2397
exttmpFile.write(file_channels, tmpdata, tmpdatalen);
2403
if (execlp(MusEGlobal::config.externalWavEditor.toLatin1().constData(), MusEGlobal::config.externalWavEditor.toLatin1().constData(), exttmpFileName.toLatin1().constData(), NULL) == -1) {
2404
perror("Failed to launch external editor");
2408
// cannot report error through gui, we are in another fork!
2409
//@!TODO: Handle unsuccessful attempts
2414
else if (pid == -1) {
2415
perror("fork failed");
2419
waitpid(pid, &status, 0);
2420
//printf ("status=%d\n",status);
2421
if( WEXITSTATUS(status) != 0 ){
2422
QMessageBox::warning(this, tr("MusE - external editor failed"),
2423
tr("MusE was unable to launch the external editor\ncheck if the editor setting in:\n"
2424
"Global Settings->Audio:External Waveditor\nis set to a valid editor."));
2427
if (exttmpFile.openRead()) {
2428
printf("Could not reopen temporary file!\n");
2431
// Re-read file again
2432
exttmpFile.seek(0, 0);
2433
size_t sz = exttmpFile.readWithHeap(file_channels, tmpdata, tmpdatalen);
2434
if (sz != tmpdatalen) {
2435
// File must have been shrunken - not good. Alert user.
2436
QMessageBox::critical(this, tr("MusE - file size changed"),
2437
tr("When editing in external editor - you should not change the filesize\nsince it must fit the selected region.\n\nMissing data is muted"));
2438
for (unsigned i=0; i<file_channels; i++) {
2439
for (unsigned j=sz; j<tmpdatalen; j++) {
2445
QDir dir = exttmpFile.dirPath();
2446
dir.remove(exttmpFileName);
2447
dir.remove(exttmpFile.basename() + ".wca");
2453
//---------------------------------------------------------
2455
//---------------------------------------------------------
2457
void WaveCanvas::startDrag(MusEGui::CItem* /* item*/, bool copymode)
2459
QMimeData* md = MusECore::selected_events_to_mime(MusECore::partlist_to_set(editor->parts()), 1);
2462
// "Note that setMimeData() assigns ownership of the QMimeData object to the QDrag object.
2463
// The QDrag must be constructed on the heap with a parent QWidget to ensure that Qt can
2464
// clean up after the drag and drop operation has been completed. "
2465
QDrag* drag = new QDrag(this);
2466
drag->setMimeData(md);
2469
drag->exec(Qt::CopyAction);
2471
drag->exec(Qt::MoveAction);
2475
//---------------------------------------------------------
2477
//---------------------------------------------------------
2479
void WaveCanvas::dragEnterEvent(QDragEnterEvent* event)
2481
//event->accept(Q3TextDrag::canDecode(event));
2482
event->acceptProposedAction(); // TODO CHECK Tim.
2485
//---------------------------------------------------------
2487
//---------------------------------------------------------
2489
void WaveCanvas::dragMoveEvent(QDragMoveEvent*)
2491
//printf("drag move %x\n", this); DELETETHIS (whole function?)
2492
//event->acceptProposedAction();
2495
//---------------------------------------------------------
2497
//---------------------------------------------------------
2499
void WaveCanvas::dragLeaveEvent(QDragLeaveEvent*)
2501
//printf("drag leave\n"); DELETETHIS (whole function?)
2502
//event->acceptProposedAction();
2505
//---------------------------------------------------------
2507
//---------------------------------------------------------
2509
void WaveCanvas::itemPressed(const MusEGui::CItem*)
2513
//---------------------------------------------------------
2515
//---------------------------------------------------------
2517
void WaveCanvas::itemReleased(const MusEGui::CItem*, const QPoint&)
2521
//---------------------------------------------------------
2523
//---------------------------------------------------------
2525
void WaveCanvas::itemMoved(const MusEGui::CItem*, const QPoint&)
2529
//---------------------------------------------------------
2531
//---------------------------------------------------------
2533
void WaveCanvas::curPartChanged()
2535
EventCanvas::curPartChanged();
2536
editor->setWindowTitle(getCaption());
2539
//---------------------------------------------------------
2541
//---------------------------------------------------------
2543
void WaveCanvas::modifySelected(MusEGui::NoteInfo::ValType type, int val, bool delta_mode)
2545
// TODO: New WaveCanvas: Convert this routine to frames and remove unneeded operations.
2546
QList< QPair<MusECore::EventList*,MusECore::Event> > already_done;
2547
MusEGlobal::audio->msgIdle(true);
2548
MusEGlobal::song->startUndo();
2549
for (MusEGui::iCItem i = items.begin(); i != items.end(); ++i) {
2550
if (!(i->second->isSelected()))
2552
WEvent* e = (WEvent*)(i->second);
2553
MusECore::Event event = e->event();
2554
if (event.type() != MusECore::Note)
2557
MusECore::WavePart* part = (MusECore::WavePart*)(e->part());
2559
if (already_done.contains(QPair<MusECore::EventList*,MusECore::Event>(part->events(), event)))
2562
MusECore::Event newEvent = event.clone();
2565
case MusEGui::NoteInfo::VAL_TIME:
2569
newTime += event.tick();
2571
newTime -= part->tick();
2574
newEvent.setTick(newTime);
2577
case MusEGui::NoteInfo::VAL_LEN:
2581
len += event.lenTick();
2584
newEvent.setLenTick(len);
2587
case MusEGui::NoteInfo::VAL_VELON:
2591
velo += event.velo();
2596
newEvent.setVelo(velo);
2599
case MusEGui::NoteInfo::VAL_VELOFF:
2603
velo += event.veloOff();
2608
newEvent.setVeloOff(velo);
2611
case MusEGui::NoteInfo::VAL_PITCH:
2615
pitch += event.pitch();
2620
newEvent.setPitch(pitch);
2625
MusEGlobal::song->changeEvent(event, newEvent, part);
2626
// Indicate do not do port controller values and clone parts.
2627
MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false));
2629
already_done.append(QPair<MusECore::EventList*,MusECore::Event>(part->events(), event));
2631
MusEGlobal::song->endUndo(SC_EVENT_MODIFIED);
2632
MusEGlobal::audio->msgIdle(false);
2635
//---------------------------------------------------------
2637
//---------------------------------------------------------
2639
void WaveCanvas::resizeEvent(QResizeEvent* ev)
2641
// Readjust all wave canvas item heights
2642
bool do_redraw = false;
2643
for (iCItem k = items.begin(); k != items.end(); ++k)
2645
if(k->second->height() != ev->size().height())
2647
k->second->setHeight(ev->size().height());
2652
if (ev->size().width() != ev->oldSize().width())
2653
emit newWidth(ev->size().width());
2654
EventCanvas::resizeEvent(ev);
2660
} // namespace MusEGui