From 3dae7373e3325e5abe8263488913faef1c63c86b Mon Sep 17 00:00:00 2001 From: "Tim E. Real" Date: Thu, 23 Dec 2010 03:52:08 +0000 Subject: Fixed *some* gui drawing speed issues. --- muse2/ChangeLog | 5 + muse2/muse/arranger/arranger.cpp | 2 +- muse2/muse/arranger/pcanvas.cpp | 42 ++++---- muse2/muse/arranger/tlist.cpp | 7 ++ muse2/muse/mixer/meter.cpp | 7 ++ muse2/muse/widgets/scrollscale.cpp | 2 +- muse2/muse/widgets/view.cpp | 216 ++++++++++++++++++++++++++++++++++--- muse2/muse/widgets/view.h | 3 + 8 files changed, 248 insertions(+), 36 deletions(-) diff --git a/muse2/ChangeLog b/muse2/ChangeLog index 0ff13419..427d840e 100644 --- a/muse2/ChangeLog +++ b/muse2/ChangeLog @@ -3,6 +3,11 @@ - Added some comments in app.cpp that I've been willing to include for a while. (Orcan) - Added a line to CMakeLists to install the splash image. Commented out for now. (Orcan) - added new-user help dialog for Input button on midi track-info (rj) + - Fixed *some* gui drawing speed issues. (Tim) + Use Qt::WA_OpaquePaintEvent for windows we fully draw on, like part canvas, track list, meter. + In PartCanvas::drawItem(), ignore null intersect of item bbox + rect. + TODO: Other windows like Slider and Knob could probably use this. And with many parts, + drawing is still slow (esp waves), possibly because of alpha blending. 21.12.2010: - Moved all the config files "~/.musePrj, ~/.MusE, ~/.deicsonze.dco" into ~/.config/MusE/ and renamed them as "projects, MusE.cfg, deicsonze.dco", respectively. (Orcan) diff --git a/muse2/muse/arranger/arranger.cpp b/muse2/muse/arranger/arranger.cpp index 5272ee75..2173e6c7 100644 --- a/muse2/muse/arranger/arranger.cpp +++ b/muse2/muse/arranger/arranger.cpp @@ -379,7 +379,7 @@ Arranger::Arranger(QMainWindow* parent, const char* name) connect(hscroll, SIGNAL(scrollChanged(int)), canvas, SLOT(setXPos(int))); connect(hscroll, SIGNAL(scaleChanged(int)), canvas, SLOT(setXMag(int))); connect(vscroll, SIGNAL(valueChanged(int)), list, SLOT(setYPos(int))); - connect(hscroll, SIGNAL(scrollChanged(int)), time, SLOT(setXPos(int))); + connect(hscroll, SIGNAL(scrollChanged(int)), time, SLOT(setXPos(int))); // connect(hscroll, SIGNAL(scaleChanged(int)), time, SLOT(setXMag(int))); connect(canvas, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned))); connect(canvas, SIGNAL(verticalScroll(unsigned)),SLOT(verticalScrollSetYpos(unsigned))); diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp index d9c3880e..e6c30f0e 100644 --- a/muse2/muse/arranger/pcanvas.cpp +++ b/muse2/muse/arranger/pcanvas.cpp @@ -106,7 +106,7 @@ NPart::NPart(Part* e) : CItem(Event(), e) { int th = track()->height(); int y = track()->y(); - //printf("NPart::NPart track name:%s, y:%d h:%d\n", track()->name().toLatin1().constData(), y, th); // REMOVE Tim. + //printf("NPart::NPart track name:%s, y:%d h:%d\n", track()->name().toLatin1().constData(), y, th); ///setPos(QPoint(e->tick(), y + 1)); setPos(QPoint(e->tick(), y)); @@ -1417,26 +1417,23 @@ void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect) if((unsigned int)to > part->lenTick()) to = part->lenTick(); + // Item bounding box x is in tick coordinates, same as rectangle. + if(item->bbox().intersect(rect).isNull()) + { + //printf("PartCanvas::drawItem rectangle is null\n"); + return; + } + QRect r = item->bbox(); - //QRect r = item->bbox().intersect(rect); - int i = part->colorIndex(); - - //printf("part start tick %d part start pixel %d\n", part->tick(), r.x()); - - //printf("PartCanvas::drawItem %s evRefs:%d pTick:%d pLen:%d bb.x:%d bb.w:%d rect.x:%d rect.w:%d r.x:%d r.w:%d\n", part->name().toLatin1().constData(), part->events()->arefCount(), pTick, part->lenTick(), item->bbox().x(), item->bbox().width(), rect.x(), rect.width(), r.x(), r.width()); + + //printf("PartCanvas::drawItem %s evRefs:%d pTick:%d pLen:%d\nbb.x:%d bb.y:%d bb.w:%d bb.h:%d\n" + // "rect.x:%d rect.y:%d rect.w:%d rect.h:%d\nr.x:%d r.y:%d r.w:%d r.h:%d\n", + // part->name().toLatin1().constData(), part->events()->arefCount(), pTick, part->lenTick(), + // bb.x(), bb.y(), bb.width(), bb.height(), + // rect.x(), rect.y(), rect.width(), rect.height(), + // r.x(), r.y(), r.width(), r.height()); - // THIS WAS IN MUSE-1: - // Must be reasonable about very low negative x values! With long songs > 15min - // and with high horizontal magnification, 'ghost' drawings appeared, - // apparently the result of truncation later (xp = -65006 caused ghosting - // at bar 245 with magnification at max.), even with correct clipping region - // applied to painter in View::paint(). Tim. Apr 5 2009 - // Quote: "Warning: Note that QPainter does not attempt to work around - // coordinate limitations in the underlying window system. Some platforms may - // behave incorrectly with coordinates as small as +/-4000." - //if(r.isEmpty()) - // return; - + int i = part->colorIndex(); p.setPen(Qt::black); if (part->mute()) { QColor c(Qt::white); @@ -1626,6 +1623,9 @@ void PartCanvas::drawMoving(QPainter& p, const CItem* item, const QRect&) void PartCanvas::drawWavePart(QPainter& p, const QRect& bb, WavePart* wp, const QRect& _pr) { + //printf("PartCanvas::drawWavePart bb.x:%d bb.y:%d bb.w:%d bb.h:%d pr.x:%d pr.y:%d pr.w:%d pr.h:%d\n", + // bb.x(), bb.y(), bb.width(), bb.height(), _pr.x(), _pr.y(), _pr.width(), _pr.height()); + QRect rr = p.worldMatrix().mapRect(bb); QRect pr = p.worldMatrix().mapRect(_pr); @@ -2620,7 +2620,7 @@ void PartCanvas::viewDropEvent(QDropEvent* event) { //printf("void PartCanvas::viewDropEvent(QDropEvent* event)\n"); if (event->source() == this) { - printf("local DROP\n"); // REMOVE Tim + printf("local DROP\n"); //event->ignore(); // TODO CHECK Tim. return; } @@ -2798,7 +2798,7 @@ void PartCanvas::drawCanvas(QPainter& p, const QRect& rect) ///if (/*config.canvasShowGrid ||*/ !track->isMidiTrack()) { if (config.canvasShowGrid && (track->isMidiTrack() || track->type() == Track::WAVE)) // Tim. { - //printf("PartCanvas::drawCanvas track name:%s, y:%d h:%d\n", track->name().toLatin1().constData(), yy, th); // REMOVE Tim. + //printf("PartCanvas::drawCanvas track name:%s, y:%d h:%d\n", track->name().toLatin1().constData(), yy, th); p.setPen(baseColor.dark(130)); ///p.drawLine(x, yy, x + w, yy); p.drawLine(x, yy + th, x + w, yy + th); // Tim. diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp index f0ef8f94..1eda506e 100644 --- a/muse2/muse/arranger/tlist.cpp +++ b/muse2/muse/arranger/tlist.cpp @@ -59,6 +59,13 @@ static const int WHEEL_DELTA = 120; TList::TList(Header* hdr, QWidget* parent, const char* name) : QWidget(parent) // Qt::WNoAutoErase | Qt::WResizeNoErase are no longer needed according to Qt4 doc { + setBackgroundRole(QPalette::NoRole); + setAttribute(Qt::WA_NoSystemBackground); + setAttribute(Qt::WA_StaticContents); + // This is absolutely required for speed! Otherwise painfully slow because we get + // full rect paint events even on small scrolls! See help on QPainter::scroll(). + setAttribute(Qt::WA_OpaquePaintEvent); + setObjectName(name); ypos = 0; editMode = false; diff --git a/muse2/muse/mixer/meter.cpp b/muse2/muse/mixer/meter.cpp index f50aa261..eb214e77 100644 --- a/muse2/muse/mixer/meter.cpp +++ b/muse2/muse/mixer/meter.cpp @@ -24,6 +24,13 @@ Meter::Meter(QWidget* parent, MeterType type) : QFrame(parent) //Qt::WNoAutoErase { + setBackgroundRole(QPalette::NoRole); + setAttribute(Qt::WA_NoSystemBackground); + setAttribute(Qt::WA_StaticContents); + // This is absolutely required for speed! Otherwise painfully slow because we get + // full rect paint events even on small scrolls! See help on QPainter::scroll(). + setAttribute(Qt::WA_OpaquePaintEvent); + mtype = type; overflow = false; val = 0.0; diff --git a/muse2/muse/widgets/scrollscale.cpp b/muse2/muse/widgets/scrollscale.cpp index dbced279..f279e6ce 100644 --- a/muse2/muse/widgets/scrollscale.cpp +++ b/muse2/muse/widgets/scrollscale.cpp @@ -265,7 +265,7 @@ ScrollScale::ScrollScale ( int s1, int s2, int cs, int max_, Qt::Orientation o, box->addWidget ( scale, 5 ); setLayout(box); connect ( scale, SIGNAL ( valueChanged ( int ) ), SLOT ( setScale ( int ) ) ); - connect ( scale, SIGNAL ( valueChanged ( int ) ), SIGNAL ( lscaleChanged ( int ) ) ); + ///connect ( scale, SIGNAL ( valueChanged ( int ) ), SIGNAL ( lscaleChanged ( int ) ) ); // ?? connect ( scroll, SIGNAL ( valueChanged ( int ) ), SIGNAL ( scrollChanged ( int ) ) ); } diff --git a/muse2/muse/widgets/view.cpp b/muse2/muse/widgets/view.cpp index be2fb592..5bf63dc8 100644 --- a/muse2/muse/widgets/view.cpp +++ b/muse2/muse/widgets/view.cpp @@ -16,6 +16,12 @@ #include #include +// Don't use this, it was just for debugging. +// It's much slower than muse-1 no matter how hard I tried. +// The left/right pixmap shifters in seXPos setYPos +// just ate up all the time no matter what I tried. +//#defines VIEW_USE_DOUBLE_BUFFERING 1 + //--------------------------------------------------------- // View::View // double xMag = (xmag < 0) ? 1.0/-xmag : double(xmag) @@ -24,6 +30,12 @@ View::View(QWidget* w, int xm, int ym, const char* name) : QWidget(w) { + setAttribute(Qt::WA_NoSystemBackground); + setAttribute(Qt::WA_StaticContents); + // This is absolutely required for speed! Otherwise painfully slow because we get + // full rect paint events even on small scrolls! See help on QPainter::scroll(). + setAttribute(Qt::WA_OpaquePaintEvent); + setObjectName(QString(name)); xmag = xm; ymag = ym; @@ -35,6 +47,9 @@ View::View(QWidget* w, int xm, int ym, const char* name) setBackgroundRole(QPalette::NoRole); brush.setStyle(Qt::SolidPattern); brush.setColor(Qt::lightGray); + #ifdef VIEW_USE_DOUBLE_BUFFERING + pmValid = false; + #endif } //--------------------------------------------------------- @@ -78,12 +93,55 @@ void View::setXPos(int x) int delta = xpos - x; // - -> shift left xpos = x; - //int w = width(); - //int h = height(); + #ifdef VIEW_USE_DOUBLE_BUFFERING + if (pm.isNull()) + return; + if (!pmValid) { + //printf("View::setXPos !pmValid x:%d width:%d delta:%d\n", x, width(), delta); + redraw(); + return; + } + + int w = width(); + int h = height(); + + QRect r; + if (delta >= w || delta <= -w) + r = QRect(0, 0, w, h); + else if (delta < 0) { // shift left + //bitBlt(&pm, 0, 0, &pm, -delta, 0, w + delta, h, CopyROP, true); + QPainter p(&pm); + p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing, false); + //printf("View::setXPos x:%d w:%d delta:%d r.x:%d r.w:%d\n", + // x, w, delta, r.x(), r.width()); + p.drawPixmap(0, 0, pm, -delta, 0, w + delta, h); + r = QRect(w + delta, 0, -delta, h); + } + else { // shift right + //bitBlt(&pm, delta, 0, &pm, 0, 0, w-delta, h, CopyROP, true); + QPainter p(&pm); + p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing, false); + //printf("View::setXPos x:%d w:%d delta:%d r.x:%d r.w:%d\n", + // x, w, delta, r.x(), r.width()); + p.drawPixmap(delta, 0, pm, 0, 0, w-delta, h); + r = QRect(0, 0, delta, h); + } + QRect olr = overlayRect(); + QRect olr1(olr); + olr1.translate(delta, 0); - scroll(delta, 0); + r |= olr; + r |= olr1; - //update(); + //printf("View::setXPos x:%d w:%d delta:%d r.x:%d r.w:%d\n", x, w, delta, r.x(), r.width()); + //printf("View::setXPos paint delta:%d r.x:%d r.y:%d r.w:%d r.h:%d\n", delta, r.x(), r.y(), r.width(), r.height()); + + paint(r); + update(); + + #else + scroll(delta, 0); + #endif } //--------------------------------------------------------- @@ -95,21 +153,71 @@ void View::setYPos(int y) int delta = ypos - y; // - -> shift up ypos = y; - //int w = width(); - //int h = height(); + #ifdef VIEW_USE_DOUBLE_BUFFERING + if (pm.isNull()) + return; + if (!pmValid) { + //printf("View::setYPos !pmValid y:%d height:%d delta:%d\n", y, height(), delta); + + redraw(); + return; + } - scroll(0, delta); + int w = width(); + int h = height(); + + QRect r; + if (delta >= h || delta <= -h) + r = QRect(0, 0, w, h); + else if (delta < 0) { // shift up + //bitBlt(&pm, 0, 0, &pm, 0, -delta, w, h + delta, CopyROP, true); + QPainter p(&pm); + p.drawPixmap(0, 0, pm, 0, -delta, w, h + delta); + r = QRect(0, h + delta, w, -delta); + } + else { // shift down + //bitBlt(&pm, 0, delta, &pm, 0, 0, w, h-delta, CopyROP, true); + QPainter p(&pm); + p.drawPixmap(0, delta, pm, 0, 0, w, h-delta); + r = QRect(0, 0, w, delta); + } + QRect olr = overlayRect(); + QRect olr1(olr); + olr1.translate(0, delta); + + r |= olr; + r |= olr1; - //update(); + //printf("View::setYPos paint delta:%d r.x:%d r.y:%d r.w:%d r.h:%d\n", delta, r.x(), r.y(), r.width(), r.height()); + + paint(r); + update(); + + #else + scroll(0, delta); + #endif } //--------------------------------------------------------- // resizeEvent //--------------------------------------------------------- -void View::resizeEvent(QResizeEvent* /*ev*/) +void View::resizeEvent(QResizeEvent* ev) { + #ifdef VIEW_USE_DOUBLE_BUFFERING + //pm.resize(ev->size()); + //printf("View::resizeEvent width:%d height:%d\n", + // ev->size().width(), ev->size().height()); + if(pm.isNull()) + { + //printf("View::resizeEvent pixmap is null\n"); + pm = QPixmap(ev->size().width(), ev->size().height()); + } + else + pm = pm.copy(QRect(QPoint(0, 0), ev->size())); + pmValid = false; + #endif } //--------------------------------------------------------- @@ -121,7 +229,18 @@ void View::paintEvent(QPaintEvent* ev) //printf("View::paintEvent x:%d width:%d y:%d height:%d\n", // ev->rect().x(), ev->rect().width(), ev->rect().y(), ev->rect().height()); + #ifdef VIEW_USE_DOUBLE_BUFFERING + if (!pmValid) + paint(ev->rect()); + + //bitBlt(this, ev->rect().topLeft(), &pm, ev->rect(), CopyROP, true); + QPainter p(this); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.drawPixmap(ev->rect().topLeft(), pm, ev->rect()); + + #else paint(ev->rect()); + #endif } //--------------------------------------------------------- @@ -130,7 +249,13 @@ void View::paintEvent(QPaintEvent* ev) void View::redraw() { - //printf("View::redraw()\n"); // REMOVE Tim. + //printf("View::redraw()\n"); + + #ifdef VIEW_USE_DOUBLE_BUFFERING + QRect r(0, 0, pm.width(), pm.height()); + //printf("View::redraw() r.x:%d r.w:%d\n", r.x(), r.width()); + paint(r); + #endif update(); } @@ -141,7 +266,12 @@ void View::redraw() void View::redraw(const QRect& r) { - //printf("View::redraw(QRect& r) r.x:%d r.w:%d\n", r.x(), r.width()); + //printf("View::redraw(QRect& r) r.x:%d r.w:%d\n", r.x(), r.width()); + + #ifdef VIEW_USE_DOUBLE_BUFFERING + paint(r); + #endif + update(r); } @@ -152,17 +282,36 @@ void View::redraw(const QRect& r) void View::paint(const QRect& r) { + #ifdef VIEW_USE_DOUBLE_BUFFERING + if (pm.isNull()) + return; + #endif + QRect rr(r); - //printf("View::paint x:%d width:%d y:%d height:%d\n", r.x(), r.width(), r.y(), r.height()); + //printf("View::paint x:%d width:%d y:%d height:%d\n", r.x(), r.width(), r.y(), r.height()); + + #ifdef VIEW_USE_DOUBLE_BUFFERING + if (!pmValid) { + pmValid = true; + rr = QRect(0, 0, pm.width(), pm.height()); + } + QPainter p(&pm); + #else QPainter p(this); + #endif + + p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing, false); + if (bgPixmap.isNull()) p.fillRect(rr, brush); else p.drawTiledPixmap(rr, bgPixmap, QPoint(xpos + rmapx(xorg) + rr.x(), ypos + rmapy(yorg) + rr.y())); + p.setClipRegion(rr); + //printf("View::paint r.x:%d w:%d\n", rr.x(), rr.width()); pdraw(p, rr); // draw into pixmap @@ -267,7 +416,7 @@ void View::setBg(const QPixmap& bgpm) void View::pdraw(QPainter& p, const QRect& r) { - //printf("View::pdraw x:%d width:%d y:%d height:%d\n", r.x(), r.width(), r.y(), r.height()); + //printf("View::pdraw virt:%d x:%d width:%d y:%d height:%d\n", virt(), r.x(), r.width(), r.y(), r.height()); if (virt()) { setPainter(p); @@ -304,6 +453,7 @@ void View::pdraw(QPainter& p, const QRect& r) x = 0; if (y < 0) y = 0; + draw(p, QRect(x, y, w, h)); } else @@ -447,3 +597,43 @@ int View::rmapyDev(int y) const return (y + ymag/2) / ymag; } +/* +QRect View::devToVirt(const QRect& r) +{ + int x = r.x(); + int y = r.y(); + int w = r.width(); + int h = r.height(); + if (xmag <= 0) { + x -= 1; + w += 2; + x = (x + xpos + rmapx(xorg)) * (-xmag); + w = w * (-xmag); + } + else { + x = (x + xpos + rmapx(xorg)) / xmag; + w = (w + xmag - 1) / xmag; + x -= 1; + w += 2; + } + if (ymag <= 0) { + y -= 1; + h += 2; + y = (y + ypos + rmapy(yorg)) * (-ymag); + h = h * (-ymag); + } + else { + y = (y + ypos + rmapy(yorg)) / ymag; + h = (h + ymag - 1) / ymag; + y -= 1; + h += 2; + } + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + return QRect(x, y, w, h); +} +*/ \ No newline at end of file diff --git a/muse2/muse/widgets/view.h b/muse2/muse/widgets/view.h index 782a3c81..f8b0c90f 100644 --- a/muse2/muse/widgets/view.h +++ b/muse2/muse/widgets/view.h @@ -24,6 +24,8 @@ class QResizeEvent; //--------------------------------------------------------- class View : public QWidget { + QPixmap pm; // for double buffering + bool pmValid; QPixmap bgPixmap; // background Pixmap QBrush brush; bool _virt; @@ -72,6 +74,7 @@ class View : public QWidget { int mapxDev(int x) const; int rmapy(int y) const; int rmapyDev(int y) const; + //QRect devToVirt(const QRect&); void setPainter(QPainter& p); -- cgit v1.2.3