summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Jonsson <spamatica@gmail.com>2011-01-21 22:36:42 +0000
committerRobert Jonsson <spamatica@gmail.com>2011-01-21 22:36:42 +0000
commitcbee698e6b2c7e6043909fb672ee4f9868475841 (patch)
treee55da95565a0c118467a73e29dc0c96e2ae61274
parent5b205da5d042feb64161e24b61c50271c31d2292 (diff)
graphical editing of automation 1st drop
-rw-r--r--muse2/muse/arranger/pcanvas.cpp286
-rw-r--r--muse2/muse/arranger/pcanvas.h14
-rw-r--r--muse2/muse/audiotrack.cpp13
-rw-r--r--muse2/muse/ctrl.cpp17
-rw-r--r--muse2/muse/ctrl.h6
-rw-r--r--muse2/muse/midiedit/ecanvas.cpp6
-rw-r--r--muse2/muse/midiedit/ecanvas.h2
-rw-r--r--muse2/muse/widgets/canvas.cpp6
-rw-r--r--muse2/muse/widgets/canvas.h2
-rw-r--r--muse2/muse/widgets/tools.cpp2
-rw-r--r--muse2/muse/widgets/tools.h4
11 files changed, 308 insertions, 50 deletions
diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp
index 3e6919a7..95ceebd5 100644
--- a/muse2/muse/arranger/pcanvas.cpp
+++ b/muse2/muse/arranger/pcanvas.cpp
@@ -141,6 +141,8 @@ PartCanvas::PartCanvas(int* r, QWidget* parent, int sx, int sy)
setMouseTracking(true);
drag = DRAG_OFF;
curColorIndex = 0;
+ automation.currentCtrl = 0;
+ moveController = 0;
partsChanged();
}
@@ -1002,7 +1004,7 @@ void PartCanvas::mousePress(QMouseEvent* event)
}
QPoint pt = event->pos();
CItem* item = items.find(pt);
- if (item == 0)
+ if (item == 0 && _tool!=AutomationTool)
return;
switch (_tool) {
default:
@@ -1022,6 +1024,10 @@ void PartCanvas::mousePress(QMouseEvent* event)
redraw();
break;
}
+ case AutomationTool:
+ if (automation.currentCtrl || (automation.currentCtrlList && event->modifiers() & Qt::ControlModifier))
+ moveController=true;
+ break;
}
}
@@ -1031,17 +1037,24 @@ void PartCanvas::mousePress(QMouseEvent* event)
void PartCanvas::mouseRelease(const QPoint&)
{
+ moveController=false;
+ automation.currentCtrl=0;
+ automation.currentTrack=0;
+ automation.currentCtrlList=0;
}
//---------------------------------------------------------
-// viewMouseMoveEvent
+// viewMousevent
//---------------------------------------------------------
-void PartCanvas::mouseMove(const QPoint& pos)
+void PartCanvas::mouseMove(QMouseEvent* event)
{
- int x = pos.x();
+ int x = event->pos().x();
if (x < 0)
x = 0;
+
+ processAutomationMovements(event);
+
emit timeChanged(AL::sigmap.raster(x, *_raster));
}
@@ -2628,7 +2641,7 @@ void PartCanvas::dragEnterEvent(QDragEnterEvent* event)
}
//---------------------------------------------------------
-// dragMoveEvent
+// dragvent
//---------------------------------------------------------
void PartCanvas::dragMoveEvent(QDragMoveEvent*)
@@ -2884,22 +2897,14 @@ void PartCanvas::drawAudioTrack(QPainter& p, const QRect& r, AudioTrack* /* t */
void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t)
{
-// printf("drawAudioTrack %d x %d y %d w %d h %d\n",t, r.x(), r.y(), r.width(), r.height());
- //int v2=r.x()+r.width();
- //printf("v2=%d mapx=%d rmapx=%d mapxdev=%d rmapxdev=%d\n",v2, mapx(v2),rmapx(v2),mapxDev(v2),rmapxDev(v2));
- //return;
+ QRect rr = p.worldMatrix().mapRect(r);
-// p.setPen(QPen(Qt::black, 2, Qt::SolidLine));
- int height=r.bottom()-r.top()-4; // limit height
+ p.save();
+ p.resetTransform();
+
+ int height=rr.bottom()-rr.top()-4; // limit height
CtrlListList* cll = t->controller();
-// QColor cols[10];
-// cols[0]=Qt::white;
-// cols[1]=Qt::red;
-// cols[2]=Qt::yellow;
-// cols[3]=Qt::black;
-// cols[4]=Qt::blue;
- //int colIndex=0;
bool firstRun=true;
for(CtrlListList::iterator icll =cll->begin();icll!=cll->end();++icll)
{
@@ -2917,7 +2922,7 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t)
if (ic != cl->end()) {
CtrlVal cvFirst = ic->second;
ic++;
- int prevPos=cvFirst.frame;
+ int prevPosFrame=cvFirst.frame;
prevVal = cvFirst.val;
// prepare prevVal
@@ -2932,6 +2937,9 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t)
prevVal = (prevVal- min)/(max-min);
}
+ // draw a square around the point
+ p.drawRect(mapx(tempomap.frame2tick(prevPosFrame))-1, (rr.bottom()-2)-prevVal*height-1, 3, 3);
+
for (; ic !=cl->end(); ++ic)
{
CtrlVal cv = ic->second;
@@ -2946,32 +2954,244 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t)
cl->range(&min,&max);
nextVal = (nextVal- min)/(max-min);
}
- int leftX=tempomap.frame2tick(prevPos);
- if (firstRun && leftX>r.x()) {
- leftX=r.x();
+ int leftX=mapx(tempomap.frame2tick(prevPosFrame));
+ if (firstRun && leftX>rr.x()) {
+ leftX=rr.x();
}
-
+ int currentPixel = mapx(tempomap.frame2tick(cv.frame));
p.drawLine( leftX,
- (r.bottom()-2)-prevVal*height,
- tempomap.frame2tick(cv.frame),
- (r.bottom()-2)-nextVal*height);
+ (rr.bottom()-2)-prevVal*height,
+ currentPixel,
+ (rr.bottom()-2)-nextVal*height);
firstRun=false;
- //printf("draw line: %d %f %d %f\n",tempomap.frame2tick(lastPos),r.bottom()-lastVal*height,tempomap.frame2tick(cv.frame),r.bottom()-curVal*height);
- prevPos=cv.frame;
+ //printf("draw line: %d %f %d %f\n",tempomap.frame2tick(lastPos),rr.bottom()-lastVal*height,tempomap.frame2tick(cv.frame),rr.bottom()-curVal*height);
+ prevPosFrame=cv.frame;
prevVal=nextVal;
+ if (currentPixel > rr.x()+ rr.width())
+ goto quitDrawing;
+
+ // draw a square around the point
+ p.drawRect(mapx(tempomap.frame2tick(prevPosFrame))-1, (rr.bottom()-2)-prevVal*height-1, 3, 3);
}
//printf("outer draw %f\n", cvFirst.val );
- p.drawLine(tempomap.frame2tick(prevPos),
- (r.bottom()-2)-prevVal*height,
- r.x()+r.width(),
- (r.bottom()-2)-prevVal*height);
- //printf("draw last line: %d %f %d %f\n",tempomap.frame2tick(prevPos),(r.bottom()-2)-prevVal*height,tempomap.frame2tick(prevPos)+r.width(),(r.bottom()-2)-prevVal*height);
+ p.drawLine(mapx(tempomap.frame2tick(prevPosFrame)),
+ (rr.bottom()-2)-prevVal*height,
+ rr.x()+rr.width(),
+ (rr.bottom()-2)-prevVal*height);
+ //printf("draw last line: %d %f %d %f\n",tempomap.frame2tick(prevPosFrame),(rr.bottom()-2)-prevVal*height,tempomap.frame2tick(prevPosFrame)+rr.width(),(rr.bottom()-2)-prevVal*height);
}
}
+quitDrawing:
+ p.restore();
}
+void PartCanvas::checkAutomation(Track * t, const QPoint &pointer, bool addNewCtrl)
+{
+ int circumference = 4;
+ if (t->isMidiTrack())
+ return;
+ //printf("checkAutomation p.x()=%d p.y()=%d\n", mapx(pointer.x()), mapx(pointer.y()));
+
+ int currX = mapx(pointer.x());
+ int currY = mapy(pointer.y());
+
+ CtrlListList* cll = ((AudioTrack*) t)->controller();
+ for(CtrlListList::iterator icll =cll->begin();icll!=cll->end();++icll)
+ {
+ //iCtrlList *icl = icll->second;
+ CtrlList *cl = icll->second;
+ if (cl->dontShow() || !cl->isVisible()) {
+ continue;
+ }
+ iCtrl ic=cl->begin();
+
+ int oldX=-1;
+ int oldY=-1;
+ int ypixel;
+ int xpixel;
+ // First check that there ARE automation, ic == cl->end means no automation
+ if (ic != cl->end()) {
+ for (; ic !=cl->end(); ic++)
+ {
+ CtrlVal &cv = ic->second;
+ double y;
+ if (cl->id() == AC_VOLUME ) { // use db scale for volume
+ y = (20.0*log10(cv.val)+60) / 70.0; // represent volume between 0 and 1
+ if (y < 0) y = 0;
+ }
+ else {
+ // we need to set curVal between 0 and 1
+ double min, max;
+ cl->range(&min,&max);
+ y = ( cv.val - min)/(max-min);
+ }
+
+ TrackList* tl = song->tracks();
+ int yy = 0;
+ for (iTrack it = tl->begin(); it != tl->end(); ++it) {
+ Track* track = *it;
+ yy += track->height();
+ if (track == t)
+ break;
+ }
+
+ ypixel = mapy(yy-2-y*t->height());
+ xpixel = mapx(tempomap.frame2tick(cv.frame));
+
+ if (oldX==-1) oldX = xpixel;
+ if (oldY==-1) oldY = ypixel;
+
+ bool foundIt=false;
+ if (addNewCtrl) {
+ // check if we are reasonably close to a line
+ //printf("xpixel=%d oldX=%d\n", xpixel, oldX);
+ if ( xpixel == oldX && abs(currX-xpixel) < circumference)
+ foundIt=true;
+
+ }
+
+ //printf("point at x=%d xdiff=%d y=%d ydiff=%d\n", mapx(tempomap.frame2tick(cv.frame)), x1, mapx(ypixel), y1);
+ oldX = xpixel;
+ oldY = ypixel;
+
+ int x1 = abs(currX - xpixel) ;
+ int y1 = abs(currY - ypixel);
+ if (!addNewCtrl && x1 < circumference && y1 < circumference && pointer.x() > 0 && pointer.y() > 0) {
+ foundIt=true;
+ }
+
+ if (foundIt) {
+ QWidget::setCursor(Qt::CrossCursor);
+ if (addNewCtrl)
+ automation.currentCtrl = 0; // the logic relies on this to be zero if a new controller is to be added
+ else
+ automation.currentCtrl=&cv;
+ automation.currentCtrlList = cl;
+ automation.currentTrack = t;
+ return;
+ }
+ }
+ } // if
+
+ if (addNewCtrl) {
+ // check if we are reasonably close to a line, we only need to check Y as this is the line is straight after the last controller
+ //printf("LAST ypixel=%d oldY=%d currY=%d\n", ypixel, oldY, currY);
+ bool foundIt=false;
+ if ( ypixel == oldY && abs(currY-ypixel) < circumference) {
+ //printf("found it!\n");
+ foundIt=true;
+ }
+
+ if (foundIt) {
+ QWidget::setCursor(Qt::CrossCursor);
+ automation.currentCtrlList = cl;
+ automation.currentTrack = t;
+ automation.currentCtrl = 0;
+ return;
+ }
+
+
+ }
+
+ }
+ automation.currentCtrl = 0;
+ automation.currentCtrlList = 0;
+ automation.currentTrack = 0;
+ //
+ setCursor();
+}
void PartCanvas::controllerChanged(Track* /* t */)
{
redraw();
}
+
+void PartCanvas::processAutomationMovements(QMouseEvent *event)
+{
+
+ if (_tool == AutomationTool) {
+ bool addNewPoints=false;
+ if (event->modifiers() & Qt::ControlModifier) {
+ addNewPoints=true;
+ }
+ if (moveController) {
+ //printf("update automation for controller=%d\n", automation.currentCtrl);
+ // update currentController to this position
+
+ int prevFrame = 0;
+ int nextFrame = -1;
+
+ if (addNewPoints && automation.currentCtrl == 0) // we don't have a controller, create one!
+ {
+ //printf("adding a new ctrler!\n");
+ int frame = tempomap.tick2frame(event->pos().x());
+ automation.currentCtrlList->add( frame, 1.0 /*dummy value */);
+
+ iCtrl ic=automation.currentCtrlList->begin();
+ for (; ic !=automation.currentCtrlList->end(); ic++) {
+ CtrlVal &cv = ic->second;
+ if (cv.frame == frame) {
+ automation.currentCtrl = &cv;
+ break;
+ }
+ }
+
+ }
+
+ // get previous and next frame position to give x bounds for this event.
+ iCtrl ic=automation.currentCtrlList->begin();
+ for (; ic !=automation.currentCtrlList->end(); ic++)
+ {
+ CtrlVal &cv = ic->second;
+ if (&cv == automation.currentCtrl)
+ break;
+ prevFrame = cv.frame;
+ }
+ if ( ++ic != automation.currentCtrlList->end()) {
+ CtrlVal &cv = ic->second;
+ nextFrame = cv.frame;
+ }
+ int currFrame = tempomap.tick2frame(event->pos().x());
+ if (currFrame < prevFrame) currFrame=prevFrame+1;
+ if (nextFrame!=-1 && currFrame > nextFrame) currFrame=nextFrame-1;
+ automation.currentCtrl->frame = currFrame;
+
+ int mouseY = automation.currentTrack->height() - (mapy(event->pos().y()) - automation.currentTrack->y())-2;
+ double yfraction = ((double)mouseY)/automation.currentTrack->height();
+
+ if (automation.currentCtrlList->id() == AC_VOLUME ) { // use db scale for volume
+ //y = (20.0*log10(cv.val)+60) / 70.0; // represent volume between 0 and 1
+
+ double cvval = exp10((yfraction*70.0-60)/20.0);
+ //printf("calc yfraction = %f v=%f ",yfraction,cvval);
+ double min, max;
+ automation.currentCtrlList->range(&min,&max);
+ if (cvval< min) cvval=min;
+ if (cvval>max) cvval=max;
+ automation.currentCtrl->val=cvval;
+
+ }
+ else {
+ // we need to set curVal between 0 and 1
+ double min, max;
+ automation.currentCtrlList->range(&min,&max);
+ double cvval = yfraction * (max-min) + min;
+
+ if (cvval< min) cvval=min;
+ if (cvval>max) cvval=max;
+ automation.currentCtrl->val = cvval;
+ //printf("calc cvval=%f yfraction=%f ", cvval, yfraction);
+ }
+ //printf("mouseY=%d\n", mouseY);
+ controllerChanged(automation.currentTrack);
+
+ } else {
+
+ Track * t = y2Track(event->pos().y());
+ if (t) {
+ checkAutomation(t, event->pos(), addNewPoints);
+ }
+ }
+ }
+
+}
diff --git a/muse2/muse/arranger/pcanvas.h b/muse2/muse/arranger/pcanvas.h
index 103b3d02..6afe1dca 100644
--- a/muse2/muse/arranger/pcanvas.h
+++ b/muse2/muse/arranger/pcanvas.h
@@ -37,10 +37,17 @@ class NPart : public CItem {
Track* track() const { return part()->track(); }
};
+struct AutomationObject {
+ CtrlVal *currentCtrl;
+ CtrlList *currentCtrlList;
+ Track *currentTrack;
+};
+
class QLineEdit;
class MidiEditor;
class QMenu;
class Xml;
+class CtrlVal;
//---------------------------------------------------------
// PartCanvas
@@ -56,11 +63,14 @@ class PartCanvas : public Canvas {
int curColorIndex;
bool editMode;
+ AutomationObject automation;
+ bool moveController;
+
std::vector<TrackAutomationView*> automationViews;
Q_OBJECT
virtual void keyPress(QKeyEvent*);
virtual void mousePress(QMouseEvent*);
- virtual void mouseMove(const QPoint&);
+ virtual void mouseMove(QMouseEvent* event);
virtual void mouseRelease(const QPoint&);
virtual void viewMouseDoubleClickEvent(QMouseEvent*);
virtual void leaveEvent(QEvent*e);
@@ -103,6 +113,8 @@ class PartCanvas : public Canvas {
Track* y2Track(int) const;
void drawAudioTrack(QPainter& p, const QRect& r, AudioTrack* track);
void drawAutomation(QPainter& p, const QRect& r, AudioTrack* track);
+ void checkAutomation(Track * t, const QPoint& pointer, bool addNewCtrl);
+ void processAutomationMovements(QMouseEvent *event);
protected:
diff --git a/muse2/muse/audiotrack.cpp b/muse2/muse/audiotrack.cpp
index eb70c51e..4be1a1a9 100644
--- a/muse2/muse/audiotrack.cpp
+++ b/muse2/muse/audiotrack.cpp
@@ -871,8 +871,10 @@ void AudioTrack::writeProperties(int level, Xml& xml) const
}
for (ciCtrlList icl = _controller.begin(); icl != _controller.end(); ++icl) {
const CtrlList* cl = icl->second;
- QString s("controller id=\"%1\" cur=\"%2\"");
- xml.tag(level++, s.arg(cl->id()).arg(cl->curVal()).toAscii().constData());
+
+ QString s= QString("controller id=\"%1\" cur=\"%2\"").arg(cl->id()).arg(cl->curVal()).toAscii().constData();
+ s += QString(" color=\"%1\" visible=\"%2\"").arg(cl->color().name()).arg(cl->isVisible());
+ xml.tag(level++, s.toAscii().constData());
int i = 0;
for (ciCtrl ic = cl->begin(); ic != cl->end(); ++ic) {
QString s("%1 %2, ");
@@ -967,7 +969,7 @@ bool AudioTrack::readProperties(Xml& xml, const QString& tag)
else if (tag == "controller") {
CtrlList* l = new CtrlList();
l->read(xml);
-
+
// Since (until now) muse wrote a 'zero' for plugin controller current value
// in the XML file, we can't use that value, now that plugin automation is added.
// We must take the value from the plugin control value.
@@ -995,8 +997,9 @@ bool AudioTrack::readProperties(Xml& xml, const QString& tag)
d->insert(std::pair<const int, CtrlVal> (i->first, i->second));
if(!ctlfound)
- d->setCurVal(l->curVal());
-
+ d->setCurVal(l->curVal());
+ d->setColor(l->color());
+ d->setVisible(l->isVisible());
d->setDefault(l->getDefault());
delete l;
l = d;
diff --git a/muse2/muse/ctrl.cpp b/muse2/muse/ctrl.cpp
index 2a6f7cb0..e5da5f2b 100644
--- a/muse2/muse/ctrl.cpp
+++ b/muse2/muse/ctrl.cpp
@@ -197,6 +197,23 @@ void CtrlList::read(Xml& xml)
if(!ok)
printf("CtrlList::read failed reading _curVal string: %s\n", xml.s2().toLatin1().constData());
}
+ else if (tag == "visible")
+ {
+ _visible = loc.toInt(xml.s2(), &ok);
+ if(!ok)
+ printf("CtrlList::read failed reading _visible string: %s\n", xml.s2().toLatin1().constData());
+ }
+ else if (tag == "color")
+ {
+#if QT_VERSION >= 0x040700
+ ok = _displayColor.isValidColor(xml.s2());
+ if (!ok) {
+ printf("CtrlList::read failed reading color string: %s\n", xml.s2().toLatin1().constData());
+ break;
+ }
+#endif
+ _displayColor.setNamedColor(xml.s2());
+ }
else
printf("unknown tag %s\n", tag.toLatin1().constData());
break;
diff --git a/muse2/muse/ctrl.h b/muse2/muse/ctrl.h
index c845bb1e..307a3783 100644
--- a/muse2/muse/ctrl.h
+++ b/muse2/muse/ctrl.h
@@ -124,10 +124,10 @@ class CtrlList : public std::map<int, CtrlVal, std::less<int> > {
void read(Xml& xml);
void setColor( QColor c ) { _displayColor = c;}
- QColor color() { return _displayColor; }
+ QColor color() const { return _displayColor; }
void setVisible(bool v) { _visible = v; }
- bool isVisible() { return _visible; }
- bool dontShow() { return _dontShow; }
+ bool isVisible() const { return _visible; }
+ bool dontShow() const { return _dontShow; }
};
//---------------------------------------------------------
diff --git a/muse2/muse/midiedit/ecanvas.cpp b/muse2/muse/midiedit/ecanvas.cpp
index 68819adf..889657aa 100644
--- a/muse2/muse/midiedit/ecanvas.cpp
+++ b/muse2/muse/midiedit/ecanvas.cpp
@@ -123,10 +123,10 @@ void EventCanvas::endUndo(DragType dtype, int flags)
// mouseMove
//---------------------------------------------------------
-void EventCanvas::mouseMove(const QPoint& pos)
+void EventCanvas::mouseMove(QMouseEvent* event)
{
- emit pitchChanged(y2pitch(pos.y()));
- int x = pos.x();
+ emit pitchChanged(y2pitch(event->pos().y()));
+ int x = event->pos().x();
emit timeChanged(editor->rasterVal(x));
}
diff --git a/muse2/muse/midiedit/ecanvas.h b/muse2/muse/midiedit/ecanvas.h
index 461a717a..86e1c200 100644
--- a/muse2/muse/midiedit/ecanvas.h
+++ b/muse2/muse/midiedit/ecanvas.h
@@ -44,7 +44,7 @@ class EventCanvas : public Canvas {
virtual void startUndo(DragType);
virtual void endUndo(DragType, int flags = 0);
- virtual void mouseMove(const QPoint&);
+ virtual void mouseMove(QMouseEvent* event);
protected:
bool _playEvents;
diff --git a/muse2/muse/widgets/canvas.cpp b/muse2/muse/widgets/canvas.cpp
index 20b92e8d..5b6dc453 100644
--- a/muse2/muse/widgets/canvas.cpp
+++ b/muse2/muse/widgets/canvas.cpp
@@ -1040,7 +1040,7 @@ void Canvas::viewMouseMoveEvent(QMouseEvent* event)
break;
}
- mouseMove(ev_pos);
+ mouseMove(event);
}
//---------------------------------------------------------
@@ -1141,6 +1141,7 @@ void Canvas::viewMouseReleaseEvent(QMouseEvent* event)
if (redrawFlag)
redraw();
setCursor();
+ mouseRelease(pos);
}
//---------------------------------------------------------
@@ -1348,6 +1349,9 @@ void Canvas::setCursor()
case MuteTool:
QWidget::setCursor(QCursor(*editmuteIcon, 4, 15));
break;
+ case AutomationTool:
+ QWidget::setCursor(QCursor(Qt::PointingHandCursor));
+ break;
default:
QWidget::setCursor(QCursor(Qt::ArrowCursor));
break;
diff --git a/muse2/muse/widgets/canvas.h b/muse2/muse/widgets/canvas.h
index 595fe04e..2f9a3907 100644
--- a/muse2/muse/widgets/canvas.h
+++ b/muse2/muse/widgets/canvas.h
@@ -88,7 +88,7 @@ class Canvas : public View {
virtual void mousePress(QMouseEvent*) {}
virtual void keyPress(QKeyEvent*);
- virtual void mouseMove(const QPoint&) = 0;
+ virtual void mouseMove(QMouseEvent* event) = 0;
virtual void mouseRelease(const QPoint&) {}
virtual void drawCanvas(QPainter&, const QRect&) = 0;
virtual void drawItem(QPainter&, const CItem*, const QRect&) = 0;
diff --git a/muse2/muse/widgets/tools.cpp b/muse2/muse/widgets/tools.cpp
index 32f42ad9..268a03d5 100644
--- a/muse2/muse/widgets/tools.cpp
+++ b/muse2/muse/widgets/tools.cpp
@@ -34,6 +34,7 @@ const char* infoQuant = QT_TRANSLATE_NOOP("@default", "select Quantize Tool:\n"
const char* infoDraw = QT_TRANSLATE_NOOP("@default", "select Drawing Tool");
const char* infoMute = QT_TRANSLATE_NOOP("@default", "select Muting Tool:\n"
"click on part to mute/unmute");
+const char* infoAutomation = QT_TRANSLATE_NOOP("@default", "Manipulate automation");
ToolB toolList[] = {
{&pointerIcon, QT_TRANSLATE_NOOP("@default", "pointer"), infoPointer },
@@ -45,6 +46,7 @@ ToolB toolList[] = {
{&quantIcon, QT_TRANSLATE_NOOP("@default", "quantize"), infoQuant },
{&drawIcon, QT_TRANSLATE_NOOP("@default", "draw"), infoDraw },
{&editmuteIcon, QT_TRANSLATE_NOOP("@default", "mute parts"), infoMute },
+ {&drawIcon, QT_TRANSLATE_NOOP("@default", "edit automation"), infoAutomation},
};
//---------------------------------------------------------
diff --git a/muse2/muse/widgets/tools.h b/muse2/muse/widgets/tools.h
index 7cc5e62c..43d1ebaf 100644
--- a/muse2/muse/widgets/tools.h
+++ b/muse2/muse/widgets/tools.h
@@ -17,9 +17,9 @@ class QPixmap;
class QWidget;
enum Tool { PointerTool=1, PencilTool=2, RubberTool=4, CutTool=8,
- ScoreTool=16, GlueTool=32, QuantTool=64, DrawTool=128, MuteTool=256};
+ ScoreTool=16, GlueTool=32, QuantTool=64, DrawTool=128, MuteTool=256, AutomationTool=512};
-const int arrangerTools = PointerTool | PencilTool | RubberTool | CutTool | GlueTool | MuteTool;
+const int arrangerTools = PointerTool | PencilTool | RubberTool | CutTool | GlueTool | MuteTool | AutomationTool;
struct ToolB {
QPixmap** icon;