diff options
Diffstat (limited to 'muse2')
36 files changed, 2027 insertions, 459 deletions
diff --git a/muse2/ChangeLog b/muse2/ChangeLog index 625ab3f4..d5dd93ce 100644 --- a/muse2/ChangeLog +++ b/muse2/ChangeLog @@ -1,3 +1,22 @@ +17.08.2011: + - Convert some Qt3 style coding in ComboBox to Qt4 in terms of menu entry handling. (Orcan) + - Add mouse wheel support to ComboBox. (Orcan) + - Fix AutoType indicator coloring. (Orcan) +16.08.2011: + - More drawing fixes, improved accuracy (grids, timescales, edges, markers guaranteed to align now). (Tim p4.0.30) + Much drawing changed to device (pixel) space instead of virtual space, for accuracy. + - Fixed display of audio automation graphs. (But not editing). (Tim) + - Fixed unreadable Master Edit tempo scale (on left side), and added toolbar saving and restoring. (Tim p4.0.31) +15.08.2011: + - Remodel the Meter and the VerticalMeter (Orcan) +13.08.2011: + - Make the shininess of the Knob ring a little smarter (Orcan) +05.08.2011: + - Parts having hidden events now drawn using 'jagged' ends and special white edges. (Tim p4.0.29) + - Improved border drawing guaranteed to show L/R touching part borders. TODO: Top and bottom borders. (Tim) + - Muted parts now show names and events. Filled with a special brush pattern for easy recognition. (Tim) + - Huge changes to PartCanvas::drawItem(). And to all View::XmapXXX methods for better accuracy. (Tim) + - Changed bool Part::hasHiddenNotes() to int Part::hasHiddenEvents(). Added int Part::cachedHasHiddenEvents(). (Tim) 02.08.2011: - Changed behaviour of part clones (flo93) diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp index e48425d7..8f059c73 100644 --- a/muse2/muse/app.cpp +++ b/muse2/muse/app.cpp @@ -1422,7 +1422,7 @@ void MusE::closeEvent(QCloseEvent* event) n = QMessageBox::warning(this, appName, tr("The current Project contains unsaved data\n" "Save Current Project?"), - tr("&Save"), tr("&Skip"), tr("&Cancel"), 0, 2); + tr("&Save"), tr("S&kip"), tr("&Cancel"), 0, 2); if (n == 0) { if (!save()) // dont quit if save failed { @@ -2601,7 +2601,7 @@ bool MusE::clearSong(bool clear_all) tr("The current Project contains unsaved data\n" "Load overwrites current Project:\n" "Save Current Project?"), - tr("&Save"), tr("&Skip"), tr("&Abort"), 0, 2); + tr("&Save"), tr("S&kip"), tr("&Abort"), 0, 2); switch (n) { case 0: if (!save()) // abort if save failed diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp index d223321b..cf376042 100644 --- a/muse2/muse/arranger/pcanvas.cpp +++ b/muse2/muse/arranger/pcanvas.cpp @@ -3,6 +3,7 @@ // Linux Music Editor // $Id: pcanvas.cpp,v 1.48.2.26 2009/11/22 11:08:33 spamatica Exp $ // (C) Copyright 1999 Werner Schweer (ws@seh.de) +// Additions, modifications (C) Copyright 2011 Tim E. Real (terminator356 on users DOT sourceforge DOT net) //========================================================= #include <stdio.h> @@ -45,7 +46,6 @@ #include "midictrl.h" #include "utils.h" - //--------------------------------------------------------- // colorRect // paints a rectangular icon with a given color @@ -69,17 +69,12 @@ QIcon colorRect(const QColor& color, int width, int height) { NPart::NPart(Part* e) : CItem(Event(), e) { - int th = track()->height(); - int y = track()->y(); + leftBorderTouches = false; + rightBorderTouches = false; - ///setPos(QPoint(e->tick(), y + 1)); + int y = track()->y(); setPos(QPoint(e->tick(), y)); - - ///setBBox(QRect(e->tick(), y + 1, e->lenTick(), th)); - // NOTE: For adjustable border size: If using a two-pixel border width while drawing, use second line. - // If one-pixel width, use first line. Tim. - //setBBox(QRect(e->tick(), y, e->lenTick(), th)); - setBBox(QRect(e->tick(), y + 1, e->lenTick(), th)); + setBBox(QRect(e->tick(), y, e->lenTick(), track()->height())); } //--------------------------------------------------------- @@ -418,17 +413,31 @@ QPoint PartCanvas::raster(const QPoint& p) const void PartCanvas::partsChanged() { items.clear(); - int idx = 0; for (iTrack t = tracks->begin(); t != tracks->end(); ++t) { PartList* pl = (*t)->parts(); for (iPart i = pl->begin(); i != pl->end(); ++i) { - NPart* np = new NPart(i->second); + Part* part = i->second; + NPart* np = new NPart(part); items.add(np); if (i->second->selected()) { selectItem(np, true); } - } - ++idx; + + // Check for touching borders. p4.0.29 + Part* pp; + for(ciPart ii = pl->begin(); ii != pl->end(); ++ii) + { + pp = ii->second; + if(pp == part) // Ignore this part + continue; + if(pp->tick() > part->endTick()) + break; + if(pp->endTick() == part->tick()) + np->leftBorderTouches = true; + if(pp->tick() == part->endTick()) + np->rightBorderTouches = true; + } + } } redraw(); } @@ -1275,6 +1284,7 @@ void PartCanvas::keyPress(QKeyEvent* event) // draws a part //--------------------------------------------------------- +#if 0 void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect) { int from = rect.x(); @@ -1298,84 +1308,215 @@ void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect) } QRect r = item->bbox(); + bool clone = part->events()->arefCount() > 1; + QBrush brush; - int i = part->colorIndex(); - p.setPen(Qt::black); - if (part->mute()) { - QColor c(Qt::white); + //QRect rr = map(r); + //QRect rr = p.transform().mapRect(r); + //printf("PartCanvas::drawItem called map rx:%d rw:%d rrx:%d rrw:%d\n", r.x(), r.width(), rr.x(), rr.width()); + //printf("PartCanvas::drawItem called map rx:%d rw:%d\n", r.x(), r.width()); + //p.save(); + //p.setWorldMatrixEnabled(false); + + // NOTE: Optimization: For each item, hasHiddenEvents() is called once in Canvas::draw(), and we use cachedHasHiddenEvents(). + // Not used for now. + //int het = part->cachedHasHiddenEvents(); + int het = part->hasHiddenEvents(); + + int y_1 = rmapyDev(1); // Hack, try to replace. + double xs_0 = r.x(); + double xe_0 = xs_0 + r.width(); + double xs_m0 = rmapx_f(xs_0); + double xe_m0 = rmapx_f(xe_0); + double xs_1 = rmapxDev_f(xs_m0 + 1.0); + if(xs_1 > xe_0) + xs_1 = xe_0; + double xs_2 = rmapxDev_f(xs_m0 + 2.0); + if(xs_2 > xe_0) + xs_2 = xe_0; + double xs_6 = rmapxDev_f(xs_m0 + 6.0); + if(xs_6 > xe_0) + xs_6 = xe_0; + + double xe_1 = rmapxDev_f(xe_m0 - 1.0); + if(xe_1 < xs_0) + xe_1 = xs_0; + double xe_2 = rmapxDev_f(xe_m0 - 2.0); + if(xe_2 < xs_0) + xe_2 = xs_0; + double xe_6 = rmapxDev_f(xe_m0 - 6.0); + if(xe_6 < xs_0) + xe_6 = xs_0; + + double ys_0 = r.y(); + double ye_0 = ys_0 + r.height(); + double ys_m0 = rmapy_f(ys_0); + double ye_m0 = rmapy_f(ye_0); + double ys_1 = rmapyDev_f(ys_m0 + 1.0); + if(ys_1 > ye_0) + ys_1 = ye_0; + double ys_2 = rmapyDev_f(ys_m0 + 2.0); + if(ys_2 > ye_0) + ys_2 = ye_0; + + double ye_1 = rmapyDev_f(ye_m0 - 1.0); + if(ye_1 < ys_0) + ye_1 = ys_0; + double ye_2 = rmapyDev_f(ye_m0 - 2.0); + if(ye_2 < ys_0) + ye_2 = ys_0; + + int cidx = part->colorIndex(); + if (item->isMoving()) + { + QColor c(Qt::gray); c.setAlpha(config.globalAlphaBlend); QLinearGradient gradient(r.topLeft(), r.bottomLeft()); gradient.setColorAt(0, c); gradient.setColorAt(1, c.darker()); - QBrush cc(gradient); - p.setBrush(cc); - - // NOTE: For one-pixel border use first line For two-pixel border use second. - p.drawRect(QRect(r.x(), r.y()-1, r.width(), r.height())); - - return; - } - if (item->isMoving()) { - QColor c(Qt::gray); + brush = QBrush(gradient); + } + else + if (part->selected()) + { + QColor c(Qt::black); + c.setAlpha(config.globalAlphaBlend); + QLinearGradient gradient(r.topLeft(), r.bottomLeft()); + // Use a colour only about 20% lighter than black, rather than the 50% we use in gGradientFromQColor + // and is used in darker()/lighter(), so that it is distinguished a bit better from grey non-part tracks. + //c.setRgba(64, 64, 64, c.alpha()); + gradient.setColorAt(0, QColor(51, 51, 51, config.globalAlphaBlend)); + gradient.setColorAt(1, c); + brush = QBrush(gradient); + } + else + if (part->mute()) + { + QColor c(Qt::white); c.setAlpha(config.globalAlphaBlend); QLinearGradient gradient(r.topLeft(), r.bottomLeft()); gradient.setColorAt(0, c); gradient.setColorAt(1, c.darker()); - QBrush cc(gradient); - p.setBrush(cc); - - // NOTE: For one-pixel border use first line. For two-pixel border use second. - p.drawRect(QRect(r.x(), r.y()-1, r.width(), r.height())); - } - else if (part->selected()) { - bool clone = part->events()->arefCount() > 1; - - // NOTE: For one-pixel border use first line and don't bother with setCosmetic. - // For a two-pixel border use second line and MUST use setCosmetic! Tim. - //p.setPen(QPen(config.partColors[i], 0, clone ? Qt::DashLine : Qt::SolidLine)); - QPen pen(config.partColors[i], 2, clone ? Qt::DashLine : Qt::SolidLine); - pen.setCosmetic(true); + brush = QBrush(gradient); - p.setPen(pen); - // Hm, put some kind of lower limit? If so do that globally to the adjustment. - QColor c(Qt::black); - c.setAlpha(config.globalAlphaBlend); - - QLinearGradient gradient(r.topLeft(), r.bottomLeft()); - //gradient.setColorAt(0, c); - //gradient.setColorAt(1, c.darker()); - // Use a colour only about 20% lighter than black, rather than the 50% we use in gGradientFromQColor - // and is used in darker()/lighter(), so that it is distinguished a bit better from grey non-part tracks. - //c.setRgba(64, 64, 64, c.alpha()); - gradient.setColorAt(0, QColor(51, 51, 51, config.globalAlphaBlend)); - gradient.setColorAt(1, c); - QBrush cc(gradient); - //QBrush cc(gGradientFromQColor(c, r.topLeft(), r.bottomLeft())); - - p.setBrush(cc); - p.drawRect(r); - } - else { - bool clone = part->events()->arefCount() > 1; - - // NOTE: Pixel width: See above note. - //p.setPen(QPen(Qt::black, 0, clone ? Qt::DashLine : Qt::SolidLine)); - QPen pen(Qt::black, 2, clone ? Qt::DashLine : Qt::SolidLine); - pen.setCosmetic(true); - - p.setPen(pen); - QColor c(config.partColors[i]); + // Not good. Aliasing missing lines happening at different mags. + // And it's too much. If notes + automation is displayed (by removing 'return' below), cross hatch interferes. + // TODO: Maybe try to draw a nice gradient SINGLE cross (or STAR) from corner to corner instead. + // Then remove the 'return' below and let it draw the name and notes. + //brush.setStyle(Qt::DiagCrossPattern); + //p.fillRect(rf, brush); + } + else + { + QColor c(config.partColors[cidx]); c.setAlpha(config.globalAlphaBlend); - //QLinearGradient gradient(r.topLeft(), r.bottomLeft()); - //gradient.setColorAt(0, c); - //gradient.setColorAt(1, c.darker()); - //QBrush cc(gradient); - QBrush cc(gGradientFromQColor(c, r.topLeft(), r.bottomLeft())); - p.setBrush(cc); - - p.drawRect(r); - } + brush = QBrush(gGradientFromQColor(c, r.topLeft(), r.bottomLeft())); + } + + double h = r.height(); + double s = h / 4.0; + double y0 = r.y(); + double y1 = y0 + s; + double y2 = y0 + s * 2.0; + double y3 = y0 + s * 3.0; + double y4 = y0 + h; + QPointF points[16]; + int pts; + + // + // Fill the part rectangles, accounting for hidden events by using 'jagged' edges... + // + + p.setBrush(brush); + p.setPen(Qt::NoPen); + if(het) + { + pts = 0; + if(het == (Part::LeftEventsHidden | Part::RightEventsHidden)) + { + points[pts++] = QPointF(xs_0, y0); + points[pts++] = QPointF(xe_0, y0); + points[pts++] = QPointF(xe_6, y1); + points[pts++] = QPointF(xe_0, y2); + points[pts++] = QPointF(xe_6, y3); + points[pts++] = QPointF(xe_0, y4); + points[pts++] = QPointF(xs_0, y4); + points[pts++] = QPointF(xs_6, y3); + points[pts++] = QPointF(xs_0, y2); + points[pts++] = QPointF(xs_6, y1); + p.drawConvexPolygon(points, pts); // Help says may be faster on some platforms (X11). + } + else + if(het == Part::LeftEventsHidden) + { + points[pts++] = QPointF(xs_0, y0); + points[pts++] = QPointF(xe_0, y0); + points[pts++] = QPointF(xe_0, y4); + points[pts++] = QPointF(xs_0, y4); + points[pts++] = QPointF(xs_6, y3); + points[pts++] = QPointF(xs_0, y2); + points[pts++] = QPointF(xs_6, y1); + p.drawConvexPolygon(points, pts); + } + else + if(het == Part::RightEventsHidden) + { + points[pts++] = QPointF(xs_0, y0); + points[pts++] = QPointF(xe_0, y0); + + points[pts++] = QPointF(xe_6, y1); + points[pts++] = QPointF(xe_0, y2); + points[pts++] = QPointF(xe_6, y3); + points[pts++] = QPointF(xe_0, y4); + points[pts++] = QPointF(xs_0, y4); + p.drawConvexPolygon(points, pts); + } + + // + // Draw remaining 'hidden events' decorations with 'jagged' edges... + // + + int part_r, part_g, part_b, brightness, color_brightness; + config.partColors[cidx].getRgb(&part_r, &part_g, &part_b); + brightness = part_r*29 + part_g*59 + part_b*12; + //if ((brightness < 12000 || part->selected()) && !part->mute() && !item->isMoving()) + // color_brightness=223; // too dark: use lighter color + //else + // color_brightness=32; // otherwise use dark color + if ((brightness >= 12000 && !part->selected())) + color_brightness=32; // too light: use dark color + else + color_brightness=223; // too dark: use lighter color + QColor c(color_brightness,color_brightness,color_brightness, config.globalAlphaBlend); + p.setBrush(QBrush(gGradientFromQColor(c, r.topLeft(), r.bottomLeft()))); + //p.setBrush(QBrush(c)); + if(het & Part::RightEventsHidden) + { + pts = 0; + points[pts++] = QPointF(xe_0, y0); + points[pts++] = QPointF(xe_0, y4); + points[pts++] = QPointF(xe_6, y3); + points[pts++] = QPointF(xe_0, y2); + points[pts++] = QPointF(xe_6, y1); + p.drawConvexPolygon(points, pts); + } + if(het & Part::LeftEventsHidden) + { + pts = 0; + points[pts++] = QPointF(xs_0, y0); + points[pts++] = QPointF(xs_6, y1); + points[pts++] = QPointF(xs_0, y2); + points[pts++] = QPointF(xs_6, y3); + points[pts++] = QPointF(xs_0, y4); + p.drawConvexPolygon(points, pts); + } + } + else + { + p.fillRect(r, brush); + } + MidiPart* mp = 0; WavePart* wp = 0; Track::TrackType type = part->track()->type(); @@ -1393,40 +1534,640 @@ void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect) drawMidiPart(p, rect, mp->events(), (MidiTrack*)part->track(), mp, r, mp->tick(), from, to); } + #if 0 + // + // Now draw the borders... + // Works great but requires clones be drawn with the highest priority on top of all other parts, in Canvas::draw. + // + + QPen pen(part->selected() ? config.partColors[i] : Qt::black, 2.0, clone ? Qt::DotLine : Qt::SolidLine); + pen.setCosmetic(true); + p.setPen(pen); + p.setBrush(Qt::NoBrush); + p.drawRect(r); + + #else + // + // Now draw the borders, using custom segments... + // + + // FIXME NOTE: For 1-pixel wide lines, setting pen style to anything other than solid didn't work out well. + // Much too screwy - the single-width lines kept getting shifted one pixel over intermittently. + // I tried EVERYTHING to make sure x is proper but the painter keeps shifting them over. + // Meanwhile the fills are correct. Seems painter doesn't like line patterns, whether stock or custom. + // Therefore I was forced to manually draw the left and right segments. + // It works. Which seems to be more proof that painter is handling line patterns and pen widths badly... + // DO NOT ERASE COMMENTED CODE BELOW for now, in case it can be fixed. Tim. p4.0.29 + + p.setBrush(Qt::NoBrush); + + QColor pc((part->mute() || item->isMoving())? Qt::white : config.partColors[cidx]); + QPen penSelect1H(pc); + QPen penSelect2H(pc, 2.0); + QPen penSelect1V(pc); + QPen penSelect2V(pc, 2.0); + penSelect1H.setCosmetic(true); + penSelect2H.setCosmetic(true); + penSelect1V.setCosmetic(true); + penSelect2V.setCosmetic(true); + + pc = Qt::black; + QPen penNormal1H(pc); + QPen penNormal2H(pc, 2.0); + QPen penNormal1V(pc); + QPen penNormal2V(pc, 2.0); + penNormal1H.setCosmetic(true); + penNormal2H.setCosmetic(true); + penNormal1V.setCosmetic(true); + penNormal2V.setCosmetic(true); + + QVector<qreal> customDashPattern; + if(clone) + { + customDashPattern << 4.0 << 8.0; + penSelect1H.setDashPattern(customDashPattern); + penNormal1H.setDashPattern(customDashPattern); + //penSelect1V.setDashPattern(customDashPattern); + //penNormal1V.setDashPattern(customDashPattern); + customDashPattern.clear(); + customDashPattern << 2.0 << 4.0; + penSelect2H.setDashPattern(customDashPattern); + penNormal2H.setDashPattern(customDashPattern); + //penSelect2V.setDashPattern(customDashPattern); + //penNormal2V.setDashPattern(customDashPattern); + } + + pc = Qt::white; + QPen penHidden1(pc); + QPen penHidden2(pc, 2.0); + penHidden2.setCosmetic(true); + //customDashPattern.clear(); + //customDashPattern << 2.0 << 10.0; + //penHidden1.setDashPattern(customDashPattern); + //customDashPattern.clear(); + //customDashPattern << 1.0 << 5.0; + //penHidden2.setDashPattern(customDashPattern); + + bool lbt = ((NPart*)item)->leftBorderTouches; + bool rbt = ((NPart*)item)->rightBorderTouches; + + QLineF l1( lbt?xs_1:xs_0, ys_0, rbt?xe_1:xe_0, ys_0); // Top + //QLineF l2(rbt?xe_1:xe_0, r.y() + (rbt?y_1:y_2) - 1, rbt?xe_1:xe_0, r.y() + r.height() - 1); // Right + QLineF l3( lbt?xs_1:xs_0, ye_0, rbt?xe_1:xe_0, ye_0); // Bottom + //QLineF l4(r.x(), r.y() + (lbt?y_1:y_2), r.x(), r.y() + r.height() - (lbt?y_1:y_2)); // Left + + if(het & Part::RightEventsHidden) + p.setPen(((NPart*)item)->rightBorderTouches ? penHidden1 : penHidden2); + else + { + if(((NPart*)item)->rightBorderTouches) + p.setPen(part->selected() ? penSelect1V : penNormal1V); + else + p.setPen(part->selected() ? penSelect2V : penNormal2V); + } + //p.drawLine(l2); // Right line + + double xx = rbt?xe_1:xe_0; + if(clone) + { + double yinc = 7.0 * y_1; + for(double yy = (rbt?ys_1:ys_2); yy < ye_2; yy += yinc) + { + double yi = (rbt?3.0:2.0) * y_1; + if(yy + yi > ye_2) + yi = ye_2 - yy; + p.drawLine(QPointF(xx, yy), QPointF(xx, yy + yi)); // Right dashed line + } + } + else + p.drawLine(QPointF(xx, rbt?ys_1:ys_2), QPointF(xx, rbt?ye_1:ye_2)); // Right line + + if(het & Part::LeftEventsHidden) + p.setPen(((NPart*)item)->leftBorderTouches ? penHidden1 : penHidden2); + else + { + if(((NPart*)item)->leftBorderTouches) + p.setPen(part->selected() ? penSelect1V : penNormal1V); + else + p.setPen(part->selected() ? penSelect2V : penNormal2V); + } + //p.drawLine(l4); // Left line + + xx = xs_0; + if(clone) + { + double yinc = 7.0 * y_1; + for(double yy = (lbt?ys_1:ys_2); yy < ye_2; yy += yinc) + { + double yi = (lbt?3.0:2.0) * y_1; + if(yy + yi > ye_2) + yi = ye_2 - yy; + p.drawLine(QPointF(xx, yy), QPointF(xx, yy + yi)); // Left dashed line + } + } + else + p.drawLine(QPointF(xx, lbt?ys_1:ys_2), QPointF(xx, lbt?ye_1:ye_2)); // Left line + + p.setPen(part->selected() ? penSelect2H : penNormal2H); + p.drawLine(l1); // Top line + p.drawLine(l3); // Bottom line + + #endif + + //p.restore(); + if (config.canvasShowPartType & 1) { // show names // draw name // FN: Set text color depending on part color (black / white) int part_r, part_g, part_b, brightness; - //config.partColors[i].getRgb(&part_r, &part_g, &part_b); // Since we'll draw the text on the bottom (to accommodate drum 'slivers'), // get the lowest colour in the gradient used to draw the part. QRect rr = map(r); rr.setX(rr.x() + 3); - gGradientFromQColor(config.partColors[i], rr.topLeft(), rr.bottomLeft()).stops().last().second.getRgb(&part_r, &part_g, &part_b); + gGradientFromQColor(config.partColors[cidx], rr.topLeft(), rr.bottomLeft()).stops().last().second.getRgb(&part_r, &part_g, &part_b); brightness = part_r*29 + part_g*59 + part_b*12; - //if (brightness < 12000 || part->selected()) - // p.setPen(Qt::white); /* too dark: use white for text color */ - //else - // p.setPen(Qt::black); /* otherwise use black */ - bool rev = brightness < 12000 || part->selected(); - //QRect rr = map(r); - //rr.setX(rr.x() + 3); + //bool rev = (brightness < 12000 || part->selected()) && !part->mute() && !item->isMoving(); + bool rev = brightness >= 12000 && !part->selected(); p.save(); p.setFont(config.fonts[1]); p.setWorldMatrixEnabled(false); if (rev) - p.setPen(Qt::black); - else p.setPen(Qt::white); + else + p.setPen(Qt::black); p.drawText(rr.translated(1, 1), Qt::AlignBottom|Qt::AlignLeft, part->name()); if (rev) - p.setPen(Qt::white); - else p.setPen(Qt::black); + else + p.setPen(Qt::white); p.drawText(rr, Qt::AlignBottom|Qt::AlignLeft, part->name()); p.restore(); } } +#endif + +void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect) + { + int from = rect.x(); + int to = from + rect.width(); + + //printf("from %d to %d\n", from,to); + Part* part = ((NPart*)item)->part(); + int pTick = part->tick(); + from -= pTick; + to -= pTick; + if(from < 0) + from = 0; + if((unsigned int)to > part->lenTick()) + to = part->lenTick(); + + bool clone = part->events()->arefCount() > 1; + QBrush brush; + + QRect r = item->bbox(); + // Compensation required for two pixel wide border. FIXME Prefer to do this after the map, but r is needed below. + r.moveTop(r.y() + rmapyDev(1)); + //QRect rr = p.transform().mapRect(r); // Gives inconsistent positions. Source shows wrong operation for our needs. + QRect rr = map(r); // Use our own map instead. + + // Item bounding box x is in tick coordinates, same as rectangle. + //if(item->bbox().intersect(rect).isNull()) + //if((item->bbox() & rect).isNull()) + if((rr & map(rect)).isNull()) + { + //printf("PartCanvas::drawItem rectangle is null\n"); + return; + } + + //printf("PartCanvas::drawItem called map rx:%d rw:%d rrx:%d rrw:%d\n", r.x(), r.width(), rr.x(), rr.width()); + //printf("PartCanvas::drawItem called map rx:%d rw:%d\n", r.x(), r.width()); + + p.save(); + p.setWorldMatrixEnabled(false); + + // NOTE: Optimization: For each item, hasHiddenEvents() is called once in Canvas::draw(), and we use cachedHasHiddenEvents(). + // Not used for now. + //int het = part->cachedHasHiddenEvents(); + int het = part->hasHiddenEvents(); + + int xs_0 = rr.x(); + int xe_0 = xs_0 + rr.width(); + int xs_1 = xs_0 + 1; + if(xs_1 > xe_0) + xs_1 = xe_0; + int xs_2 = xs_0 + 2; + if(xs_2 > xe_0) + xs_2 = xe_0; + int xs_j = xs_0 + 8; + if(xs_j > xe_0) + xs_j = xe_0; + + int xe_1 = xe_0 - 1; + if(xe_1 < xs_0) + xe_1 = xs_0; + int xe_2 = xe_0 - 2; + if(xe_2 < xs_0) + xe_2 = xs_0; + int xe_j = xe_0 - 8; + if(xe_j < xs_0) + xe_j = xs_0; + + int ys_0 = rr.y(); + int ye_0 = ys_0 + rr.height(); + int ys_1 = ys_0 + 1; + if(ys_1 > ye_0) + ys_1 = ye_0; + int ys_2 = ys_0 + 2; + if(ys_2 > ye_0) + ys_2 = ye_0; + int ys_3 = ys_0 + 3; + if(ys_3 > ye_0) + ys_3 = ye_0; + + int ye_1 = ye_0 - 1; + if(ye_1 < ys_0) + ye_1 = ys_0; + int ye_2 = ye_0 - 2; + if(ye_2 < ys_0) + ye_2 = ys_0; + + int cidx = part->colorIndex(); + if (item->isMoving()) + { + QColor c(Qt::gray); + c.setAlpha(config.globalAlphaBlend); + QLinearGradient gradient(rr.topLeft(), rr.bottomLeft()); + gradient.setColorAt(0, c); + gradient.setColorAt(1, c.darker()); + brush = QBrush(gradient); + } + else + if (part->selected()) + { + QColor c(Qt::black); + c.setAlpha(config.globalAlphaBlend); + QLinearGradient gradient(rr.topLeft(), rr.bottomLeft()); + // Use a colour only about 20% lighter than black, rather than the 50% we use in gGradientFromQColor + // and is used in darker()/lighter(), so that it is distinguished a bit better from grey non-part tracks. + //c.setRgba(64, 64, 64, c.alpha()); + gradient.setColorAt(0, QColor(51, 51, 51, config.globalAlphaBlend)); + gradient.setColorAt(1, c); + brush = QBrush(gradient); + } + else + if (part->mute()) + { + QColor c(Qt::white); + c.setAlpha(config.globalAlphaBlend); + QLinearGradient gradient(rr.topLeft(), rr.bottomLeft()); + gradient.setColorAt(0, c); + gradient.setColorAt(1, c.darker()); + brush = QBrush(gradient); + } + else + { + QColor c(config.partColors[cidx]); + c.setAlpha(config.globalAlphaBlend); + brush = QBrush(gGradientFromQColor(c, rr.topLeft(), rr.bottomLeft())); + } + + int h = rr.height(); + double s = double(h) / 4.0; + int y0 = ys_0; + //int y1 = y0 + lrint(s); + int y2 = y0 + lrint(s * 2.0); + //int y3 = y0 + lrint(s * 3.0); + int y4 = y0 + h; + + //QPoint points[12]; + QPoint points[8]; + int pts; + + // + // Fill the part rectangles, accounting for hidden events by using 'jagged' edges... + // + + p.setBrush(brush); + p.setPen(Qt::NoPen); + if(het) + { + pts = 0; + if(het == (Part::LeftEventsHidden | Part::RightEventsHidden)) + { + //points[pts++] = QPoint(xs_0, y0); + //points[pts++] = QPoint(xe_0, y0); + //points[pts++] = QPoint(xe_j, y1); + //points[pts++] = QPoint(xe_0, y2); + //points[pts++] = QPoint(xe_j, y3); + //points[pts++] = QPoint(xe_0, y4); + //points[pts++] = QPoint(xs_0, y4); + //points[pts++] = QPoint(xs_j, y3); + //points[pts++] = QPoint(xs_0, y2); + //points[pts++] = QPoint(xs_j, y1); + + points[pts++] = QPoint(xs_0, y0); + points[pts++] = QPoint(xe_0, y0); + points[pts++] = QPoint(xe_j, y2); + points[pts++] = QPoint(xe_0, y4); + points[pts++] = QPoint(xs_0, y4); + points[pts++] = QPoint(xs_j, y2); + + p.drawConvexPolygon(points, pts); // Help says may be faster on some platforms (X11). + } + else + if(het == Part::LeftEventsHidden) + { + //points[pts++] = QPoint(xs_0, y0); + //points[pts++] = QPoint(xe_0, y0); + //points[pts++] = QPoint(xe_0, y4); + //points[pts++] = QPoint(xs_0, y4); + //points[pts++] = QPoint(xs_j, y3); + //points[pts++] = QPoint(xs_0, y2); + //points[pts++] = QPoint(xs_j, y1); + + points[pts++] = QPoint(xs_0, y0); + points[pts++] = QPoint(xe_0, y0); + points[pts++] = QPoint(xe_0, y4); + points[pts++] = QPoint(xs_0, y4); + points[pts++] = QPoint(xs_j, y2); + + p.drawConvexPolygon(points, pts); + } + else + if(het == Part::RightEventsHidden) + { + //points[pts++] = QPoint(xs_0, y0); + //points[pts++] = QPoint(xe_0, y0); + //points[pts++] = QPoint(xe_j, y1); + //points[pts++] = QPoint(xe_0, y2); + //points[pts++] = QPoint(xe_j, y3); + //points[pts++] = QPoint(xe_0, y4); + //points[pts++] = QPoint(xs_0, y4); + + points[pts++] = QPoint(xs_0, y0); + points[pts++] = QPoint(xe_0, y0); + points[pts++] = QPoint(xe_j, y2); + points[pts++] = QPoint(xe_0, y4); + points[pts++] = QPoint(xs_0, y4); + + p.drawConvexPolygon(points, pts); + } + + // + // Draw remaining 'hidden events' decorations with 'jagged' edges... + // + + int part_r, part_g, part_b, brightness, color_brightness; + config.partColors[cidx].getRgb(&part_r, &part_g, &part_b); + brightness = part_r*29 + part_g*59 + part_b*12; + //if ((brightness < 12000 || part->selected()) && !part->mute() && !item->isMoving()) + // color_brightness=223; // too dark: use lighter color + //else + // color_brightness=32; // otherwise use dark color + if ((brightness >= 12000 && !part->selected())) + color_brightness=96; //0; // too light: use dark color + else + color_brightness=180; //255; // too dark: use lighter color + QColor c(color_brightness,color_brightness,color_brightness, config.globalAlphaBlend); + p.setBrush(QBrush(gGradientFromQColor(c, rr.topLeft(), rr.bottomLeft()))); + //p.setBrush(QBrush(c)); + if(het & Part::RightEventsHidden) + { + pts = 0; + //points[pts++] = QPoint(xe_0, y0); + //points[pts++] = QPoint(xe_0, y4); + //points[pts++] = QPoint(xe_j, y3); + //points[pts++] = QPoint(xe_0, y2); + //points[pts++] = QPoint(xe_j, y1); + + points[pts++] = QPoint(xe_0, y0); + points[pts++] = QPoint(xe_0, y4); + points[pts++] = QPoint(xe_j, y2); + + p.drawConvexPolygon(points, pts); + } + if(het & Part::LeftEventsHidden) + { + pts = 0; + //points[pts++] = QPoint(xs_0, y0); + //points[pts++] = QPoint(xs_j, y1); + //points[pts++] = QPoint(xs_0, y2); + //points[pts++] = QPoint(xs_j, y3); + //points[pts++] = QPoint(xs_0, y4); + + points[pts++] = QPoint(xs_0, y0); + points[pts++] = QPoint(xs_j, y2); + points[pts++] = QPoint(xs_0, y4); + + p.drawConvexPolygon(points, pts); + } + } + else + { + p.fillRect(rr, brush); + } + + // Draw a pattern brush on muted parts... + if(part->mute()) + { + p.setPen(Qt::NoPen); + //brush.setStyle(Qt::DiagCrossPattern); + brush.setStyle(Qt::Dense7Pattern); + + p.fillRect(rr, brush); // FIXME: Some shifting going on + //p.fillRect(QRect(rr.x(), rr.y(), rr.width() + 1, rr.height() + 1), brush); // Same here + } + + p.setWorldMatrixEnabled(true); + + MidiPart* mp = 0; + WavePart* wp = 0; + Track::TrackType type = part->track()->type(); + if (type == Track::WAVE) { + wp =(WavePart*)part; + } + else { + mp = (MidiPart*)part; + } + + if (wp) + drawWavePart(p, rect, wp, r); + else if (mp) + { + drawMidiPart(p, rect, mp->events(), (MidiTrack*)part->track(), mp, r, mp->tick(), from, to); + } + + p.setWorldMatrixEnabled(false); + + #if 0 + // + // Now draw the borders... + // Works great but requires clones be drawn with the highest priority on top of all other parts, in Canvas::draw. + // + + QPen pen(part->selected() ? config.partColors[i] : Qt::black, 2.0, clone ? Qt::DotLine : Qt::SolidLine); + pen.setCosmetic(true); + p.setPen(pen); + p.setBrush(Qt::NoBrush); + p.drawRect(r); + + #else + // + // Now draw the borders, using custom segments... + // + + p.setBrush(Qt::NoBrush); + + QColor pc((part->mute() || item->isMoving())? Qt::white : config.partColors[cidx]); + QPen penSelect1H(pc); + QPen penSelect2H(pc, 2.0); + QPen penSelect1V(pc); + QPen penSelect2V(pc, 2.0); + penSelect1H.setCosmetic(true); + penSelect2H.setCosmetic(true); + penSelect1V.setCosmetic(true); + penSelect2V.setCosmetic(true); + + pc = Qt::black; + QPen penNormal1H(pc); + QPen penNormal2H(pc, 2.0); + QPen penNormal1V(pc); + QPen penNormal2V(pc, 2.0); + penNormal1H.setCosmetic(true); + penNormal2H.setCosmetic(true); + penNormal1V.setCosmetic(true); + penNormal2V.setCosmetic(true); + + //pc = Qt::white; + //pc = Qt::darkGray; + //QPen penHidden1(pc); + //QPen penHidden2(pc, 2.0); + //penHidden2.setCosmetic(true); + + QVector<qreal> customDashPattern; + + if(clone) + { + customDashPattern << 4.0 << 6.0; + penSelect1H.setDashPattern(customDashPattern); + penNormal1H.setDashPattern(customDashPattern); + penSelect1V.setDashPattern(customDashPattern); + penNormal1V.setDashPattern(customDashPattern); + penSelect1V.setDashOffset(2.0); + penNormal1V.setDashOffset(2.0); + //penHidden1.setDashPattern(customDashPattern); + customDashPattern.clear(); + customDashPattern << 2.0 << 3.0; + penSelect2H.setDashPattern(customDashPattern); + penNormal2H.setDashPattern(customDashPattern); + penSelect2V.setDashPattern(customDashPattern); + penNormal2V.setDashPattern(customDashPattern); + penSelect2V.setDashOffset(1.0); + penNormal2V.setDashOffset(1.0); + //penHidden2.setDashPattern(customDashPattern); + } + + bool lbt = ((NPart*)item)->leftBorderTouches; + bool rbt = ((NPart*)item)->rightBorderTouches; + + QLine l1(lbt?xs_1:xs_0, ys_0, rbt?xe_1:xe_0, ys_0); // Top + //QLine l2(rbt?xe_1:xe_0, rbt?ys_1:ys_2, rbt?xe_1:xe_0, rbt?ye_1:ye_2); // Right + QLine l2(rbt?xe_1:xe_0, ys_0, rbt?xe_1:xe_0, ye_0); // Right + QLine l3(lbt?xs_1:xs_0, ye_0, rbt?xe_1:xe_0, ye_0); // Bottom + //QLine l4(xs_0, lbt?ys_1:ys_2, xs_0, lbt?ye_1:ye_2); // Left + QLine l4(xs_0, ys_0, xs_0, ye_0); // Left + + //if(het & Part::RightEventsHidden) + // p.setPen(((NPart*)item)->rightBorderTouches ? penHidden1 : penHidden2); + //else + { + if(((NPart*)item)->rightBorderTouches) + p.setPen(part->selected() ? penSelect1V : penNormal1V); + else + p.setPen(part->selected() ? penSelect2V : penNormal2V); + } + p.drawLine(l2); // Right line + + /* + int xx = rbt?xe_1:xe_0; + if(clone) + { + int yinc = 7; + for(int yy = (rbt?ys_1:ys_2); yy < ye_2; yy += yinc) + { + int yi = rbt?3:2; + if(yy + yi > ye_2) + yi = ye_2 - yy; + p.drawLine(QPoint(xx, yy), QPoint(xx, yy + yi)); // Right dashed line + } + } + else + p.drawLine(QPoint(xx, rbt?ys_1:ys_2), QPoint(xx, rbt?ye_1:ye_2)); // Right line + */ + + //if(het & Part::LeftEventsHidden) + // p.setPen(((NPart*)item)->leftBorderTouches ? penHidden1 : penHidden2); + //else + { + if(((NPart*)item)->leftBorderTouches) + p.setPen(part->selected() ? penSelect1V : penNormal1V); + else + p.setPen(part->selected() ? penSelect2V : penNormal2V); + } + p.drawLine(l4); // Left line + + /* + xx = xs_0; + if(clone) + { + int yinc = 7; + for(int yy = (lbt?ys_1:ys_2); yy < ye_2; yy += yinc) + { + int yi = lbt?3:2; + if(yy + yi > ye_2) + yi = ye_2 - yy; + p.drawLine(QPoint(xx, yy), QPoint(xx, yy + yi)); // Left dashed line + } + } + else + p.drawLine(QPoint(xx, lbt?ys_1:ys_2), QPoint(xx, lbt?ye_1:ye_2)); // Left line + */ + + p.setPen(part->selected() ? penSelect2H : penNormal2H); + p.drawLine(l1); // Top line + p.drawLine(l3); // Bottom line + + #endif + + if (config.canvasShowPartType & 1) { // show names + // draw name + // FN: Set text color depending on part color (black / white) + int part_r, part_g, part_b, brightness; + // Since we'll draw the text on the bottom (to accommodate drum 'slivers'), + // get the lowest colour in the gradient used to draw the part. + //QRect rr = map(r); + QRect tr = rr; + tr.setX(tr.x() + 3); + gGradientFromQColor(config.partColors[cidx], tr.topLeft(), tr.bottomLeft()).stops().last().second.getRgb(&part_r, &part_g, &part_b); + brightness = part_r*29 + part_g*59 + part_b*12; + //bool rev = (brightness < 12000 || part->selected()) && !part->mute() && !item->isMoving(); + bool rev = brightness >= 12000 && !part->selected(); + p.setFont(config.fonts[1]); + if (rev) + p.setPen(Qt::white); + else + p.setPen(Qt::black); + p.drawText(tr.translated(1, 1), Qt::AlignBottom|Qt::AlignLeft, part->name()); + if (rev) + p.setPen(Qt::black); + else + p.setPen(Qt::white); + p.drawText(tr, Qt::AlignBottom|Qt::AlignLeft, part->name()); + } + + p.restore(); + //p.setWorldMatrixEnabled(true); + } //--------------------------------------------------------- // drawMoving @@ -1436,19 +2177,11 @@ void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect) void PartCanvas::drawMoving(QPainter& p, const CItem* item, const QRect&) { p.setPen( Qt::black); - - //p.setBrush( Qt::NoBrush); - //QColor c(Qt::gray); Part* part = ((NPart*)item)->part(); - QColor c(config.partColors[part->colorIndex()]); - - ///c.setAlpha(config.globalAlphaBlend); + QColor c(part->mute() ? Qt::white : config.partColors[part->colorIndex()]); + //c.setAlpha(config.globalAlphaBlend); c.setAlpha(128); // Fix this regardless of global setting. Should be OK. - p.setBrush(c); - - // NOTE: For one-pixel border use second line. For two-pixel border use first. - //p.drawRect(item->mp().x(), item->mp().y()+1, item->width(), item->height()); p.drawRect(item->mp().x(), item->mp().y(), item->width(), item->height()); } @@ -1468,10 +2201,14 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, EventList* events, Midi int part_r, part_g, part_b, brightness; config.partColors[pt->colorIndex()].getRgb(&part_r, &part_g, &part_b); brightness = part_r*29 + part_g*59 + part_b*12; - if (brightness < 12000 || pt->selected()) - color_brightness=192; // too dark: use lighter color + //if ((brightness < 12000 || pt->selected()) && !pt->mute()) + // color_brightness=192; // too dark: use lighter color + //else + // color_brightness=64; // otherwise use dark color + if (brightness >= 12000 && !pt->selected()) + color_brightness=64; // 96; // too bright: use dark color else - color_brightness=64; // otherwise use dark color + color_brightness=190; //160; // too dark: use lighter color } else color_brightness=80; @@ -1656,9 +2393,11 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, EventList* events, Midi if (te < (from + pTick)) continue; - if (te > (to + pTick)) - te = to + pTick; - + //if (te > (to + pTick)) + // te = to + pTick; + if (te >= (to + pTick)) + te = lrint(rmapxDev_f(rmapx_f(to + pTick) - 1.0)); + EventType type = i->second.type(); if (type == Note) { int pitch = i->second.pitch(); @@ -1685,8 +2424,10 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, EventList* events, Midi void PartCanvas::drawWavePart(QPainter& p, const QRect& bb, WavePart* wp, const QRect& _pr) { - QRect rr = p.worldMatrix().mapRect(bb); - QRect pr = p.worldMatrix().mapRect(_pr); + //QRect rr = p.worldMatrix().mapRect(bb); // Gives inconsistent positions. Source shows wrong operation for our needs. + QRect rr = map(bb); // Use our own map instead. + //QRect pr = p.worldMatrix().mapRect(_pr); + QRect pr = map(_pr); p.save(); p.resetTransform(); @@ -2359,9 +3100,22 @@ void PartCanvas::viewDropEvent(QDropEvent* event) void PartCanvas::drawCanvas(QPainter& p, const QRect& rect) { int x = rect.x(); - int y = rect.y(); + //int y = rect.y(); int w = rect.width(); - int h = rect.height(); + //int h = rect.height(); + + // Changed to draw in device coordinate space instead of virtual, transformed space. Tim. p4.0.30 + + //QRect mr = p.transform().mapRect(rect); // Gives inconsistent positions. Source shows wrong operation for our needs. + QRect mr = map(rect); // Use our own map instead. + + p.save(); + p.setWorldMatrixEnabled(false); + + int mx = mr.x(); + int my = mr.y(); + int mw = mr.width(); + int mh = mr.height(); ////////// // GRID // @@ -2379,13 +3133,17 @@ void PartCanvas::drawCanvas(QPainter& p, const QRect& rect) AL::sigmap.tickValues(x, &bar, &beat, &tick); for (;;) { int xt = AL::sigmap.bar2tick(bar++, 0, 0); + //int xt = mapx(AL::sigmap.bar2tick(bar++, 0, 0)); if (xt >= x + w) + //if (xt >= mx + mw) break; if (!((bar-1) % 4)) p.setPen(baseColor.dark(115)); else p.setPen(baseColor); - p.drawLine(xt, y, xt, y+h); + //p.drawLine(xt, y, xt, y+h); + int xtm = mapx(xt); + p.drawLine(xtm, my, xtm, my+mh); // append int noDivisors=0; @@ -2411,20 +3169,28 @@ void PartCanvas::drawCanvas(QPainter& p, const QRect& rect) noDivisors=noDivisors/2; } p.setPen(baseColor); + int xx; for (int t=1;t< noDivisors;t++) - p.drawLine(xt+r*t, y, xt+r*t, y+h); + { + //p.drawLine(xt+r*t, y, xt+r*t, y+h); + xx = mapx(xt + r * t); + p.drawLine(xx, my, xx, my+mh); + } } } } + //-------------------------------- // horizontal lines //-------------------------------- TrackList* tl = song->tracks(); - int yy = 0; + //int yy = 0; + int yy = -rmapy(yorg) - ypos; int th; for (iTrack it = tl->begin(); it != tl->end(); ++it) { - if (yy > y + h) + //if (yy > y + h) + if (yy > my + mh) break; Track* track = *it; th = track->height(); @@ -2433,22 +3199,46 @@ void PartCanvas::drawCanvas(QPainter& p, const QRect& rect) if (config.canvasShowGrid && (track->isMidiTrack() || track->type() == Track::WAVE)) // Tim. { p.setPen(baseColor.dark(130)); - p.drawLine(x, yy + th, x + w, yy + th); // Tim. - p.setPen(baseColor); - } - if (!track->isMidiTrack() && (track->type() != Track::WAVE)) { - QRect r = rect & QRect(x, yy, w, track->height()); - drawAudioTrack(p, r, (AudioTrack*)track); - p.setPen(baseColor); + //p.drawLine(x, yy + th, x + w, yy + th); + p.drawLine(mx, yy + th, mx + mw, yy + th); + //p.setPen(baseColor); } - if (!track->isMidiTrack()) { // draw automation - QRect r = rect & QRect(x, yy, w, track->height()); - drawAutomation(p, r, (AudioTrack*)track); - p.setPen(baseColor); - - } - yy += track->height(); + + // The update rectangle (rect and mr etc) is clipped at x<0 and y<0 in View::pdraw(). + // The 'corrupt drawing' bug of drawAudioTrack was actually because the recently added gradient + // used the update rectangle, so the gradient was also being clipped at 0,0. + // One could remove that limiter, but no, that is the correct way. So instead let's construct a + // 'pseudo bounding box' (half update rectangle, half bounding box), un-clipped. The gradient needs this! + // + // Here is a different situation than PartCanvas::drawItem which uses un-clipped part bounding boxes and + // does NOT depend on the update rectangle (except to check intersection). That's why this issue + // does not show up there. Should probably try to make that routine more efficient, just like here. Tim. p4.0.30 + QRect r(mx, yy, mw, th); + //if(r.intersects(mr)) + { + if (!track->isMidiTrack() && (track->type() != Track::WAVE)) { + //QRect r = rect & QRect(x, yy, w, track->height()); + drawAudioTrack(p, mr, r, (AudioTrack*)track); + //p.setPen(baseColor); + } + + // This was redundant drawing. Not required, done via drawTopItem in Canvas::draw + /* + //p.setWorldMatrixEnabled(true); + //if (!track->isMidiTrack()) { // draw automation + if (!track->isMidiTrack() && (track->type() != Track::WAVE)) { + //QRect r = rect & QRect(x, yy, w, track->height()); + drawAutomation(p, r, (AudioTrack*)track); + //p.setPen(baseColor); + } + //p.setWorldMatrixEnabled(false); + */ } + yy += th; + } + + p.restore(); + //p.setWorldMatrixEnabled(true); } //--------------------------------------------------------- @@ -2456,36 +3246,55 @@ void PartCanvas::drawCanvas(QPainter& p, const QRect& rect) //--------------------------------------------------------- void PartCanvas::drawTopItem(QPainter& p, const QRect& rect) { - int x = rect.x(); - int y = rect.y(); - int w = rect.width(); - int h = rect.height(); + //int x = rect.x(); + //int y = rect.y(); + //int w = rect.width(); + //int h = rect.height(); + // Changed to draw in device coordinate space instead of virtual, transformed space. Tim. p4.0.30 + + //QRect mr = p.transform().mapRect(rect); // Gives inconsistent positions. Source shows wrong operation for our needs. + QRect mr = map(rect); // Use our own map instead. + + //printf("PartCanvas::drawTopItem x:%d y:%d w:%d h:%d\n", rect.x(), rect.y(), rect.width(), rect.height()); + + int mx = mr.x(); + int my = mr.y(); + int mw = mr.width(); + int mh = mr.height(); + QColor baseColor(config.partCanvasBg.light(104)); - p.setPen(baseColor); + //p.setPen(baseColor); + p.save(); + p.setWorldMatrixEnabled(false); + TrackList* tl = song->tracks(); - int yy = 0; + int yoff = -rmapy(yorg) - ypos; + //int yy = 0; + int yy = yoff; int th; for (iTrack it = tl->begin(); it != tl->end(); ++it) { - if (yy > y + h) + //if (yy > y + h) + if (yy > my + mh) break; Track* track = *it; th = track->height(); if (!th) continue; if (!track->isMidiTrack()) { // draw automation - QRect r = rect & QRect(x, yy, w, track->height()); - drawAutomation(p, r, (AudioTrack*)track); - p.setPen(baseColor); - + //QRect r = rect & QRect(x, yy, w, track->height()); + QRect r(mx, yy, mw, th); + if(r.intersects(mr)) + { + drawAutomation(p, r, (AudioTrack*)track); + //p.setPen(baseColor); + } } - yy += track->height(); + //yy += track->height(); + yy += th; } - QRect rr = p.worldMatrix().mapRect(rect); - - unsigned int startPos = audio->getStartRecordPos().tick(); if (song->punchin()) startPos=song->lpos(); @@ -2493,38 +3302,47 @@ void PartCanvas::drawTopItem(QPainter& p, const QRect& rect) int width = mapx(song->cpos()) - mapx(startPos); if (song->cpos() < startPos) { + //p.setWorldMatrixEnabled(true); + p.restore(); return; // no drawing if we are before punch out } if (song->punchout() && song->cpos() > song->rpos()) { + //p.setWorldMatrixEnabled(true); + p.restore(); return; // no drawing if we are beyond punch out. } - p.save(); - p.resetTransform(); + ///p.save(); + ///p.resetTransform(); // write recording while it happens to get feedback // should be enhanced with solution that draws waveform also - int yPos=0; + //int yPos=0; + int yPos = yoff; if (song->record() && audio->isPlaying()) { for (iTrack it = tl->begin(); it != tl->end(); ++it) { Track* track = *it; + th = track->height(); + if (!th) + continue; if (track->recordFlag()) { QPen pen(Qt::black, 0, Qt::SolidLine); p.setPen(pen); QColor c(config.partColors[0]); c.setAlpha(config.globalAlphaBlend); - QLinearGradient gradient(QPoint(startx,yPos), QPoint(startx,yPos+track->height())); + QLinearGradient gradient(QPoint(startx,yPos), QPoint(startx,yPos+th)); gradient.setColorAt(0, c); gradient.setColorAt(1, c.darker()); QBrush cc(gradient); p.setBrush(cc); - p.drawRect(startx,yPos, width, track->height()); + p.drawRect(startx,yPos, width, th); } - yPos+=track->height(); + yPos+=th; } } p.restore(); + //p.setWorldMatrixEnabled(true); // draw midi events on yPos=0; @@ -2568,53 +3386,71 @@ void PartCanvas::drawTopItem(QPainter& p, const QRect& rect) } } - } //--------------------------------------------------------- // drawAudioTrack //--------------------------------------------------------- -void PartCanvas::drawAudioTrack(QPainter& p, const QRect& r, AudioTrack* /* t */) +void PartCanvas::drawAudioTrack(QPainter& p, const QRect& r, const QRect& bbox, AudioTrack* /*t*/) { - // NOTE: For one-pixel border use first line and don't bother with setCosmetic. - // For a two-pixel border use second line and MUST use setCosmetic! Tim. - QPen pen(Qt::black, 0, Qt::SolidLine); - //p.setPen(QPen(Qt::black, 2, Qt::SolidLine)); - //pen.setCosmetic(true); - p.setPen(pen); - //p.setBrush(Qt::gray); - + QRect mr = r & bbox; + if(mr.isNull()) + return; + int mx = mr.x(); + int my = mr.y(); + int mw = mr.width(); + int mh = mr.height(); + int mex = bbox.x(); + int mey = bbox.y(); + //int mew = bbox.width(); + int meh = bbox.height(); + + p.setPen(Qt::black); QColor c(Qt::gray); c.setAlpha(config.globalAlphaBlend); - QLinearGradient gradient(r.topLeft(), r.bottomLeft()); + //QLinearGradient gradient(r.topLeft(), r.bottomLeft()); + QLinearGradient gradient(mex + 1, mey + 1, mex + 1, mey + meh - 1); // Inside the border gradient.setColorAt(0, c); gradient.setColorAt(1, c.darker()); - QBrush cc(gradient); - p.setBrush(cc); - p.drawRect(r); - - // Factor in pen stroking size: - //QRect rr(r); - //rr.setHeight(rr.height() -1); + QBrush brush(gradient); + p.fillRect(mr, brush); // p4.0.30 ... + + //int xx = -rmapx(xorg) - xpos; + //printf("PartCanvas::drawAudioTrack x:%d y:%d w:%d h:%d th:%d xx:%d\n", r.x(), r.y(), r.width(), r.height(), t->height(), xx); + //if(r.x() <= xx) + // p.drawLine(r.x(), r.y(), r.x(), r.y() + r.height()); // The left edge + //p.drawLine(r.x(), r.y(), r.x() + r.width(), r.y()); // The top edge + //p.drawLine(r.x(), r.y() + r.height(), r.x() + r.width(), r.y() + r.height()); // The bottom edge -// p.fillRect(r, cc); + if(mex >= mx && mex <= mx + mw) + p.drawLine(mex, my, mex, my + mh - 1); // The left edge + //if(mex + mew >= mx && mex + mew <= mx + mw) + // p.drawLine(mex + mew, my, mex + mew, my + mh - 1); // The right edge. Not used - infinite to the right + if(mey >= my && mey <= my + mh) + p.drawLine(mx, mey, mx + mw - 1, mey); // The top edge + if(mey + meh >= my && mey + meh <= my + mh) + p.drawLine(mx, mey + meh, mx + mw - 1, mey + meh); // The bottom edge. Special for Audio track - draw one past bottom. } //--------------------------------------------------------- // drawAutomation //--------------------------------------------------------- -void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t) +void PartCanvas::drawAutomation(QPainter& p, const QRect& rr, AudioTrack *t) { - QRect rr = p.worldMatrix().mapRect(r); + ///QRect rr = p.worldMatrix().mapRect(r); - p.save(); - p.resetTransform(); + ///p.save(); + ///p.resetTransform(); int height=rr.bottom()-rr.top()-4; // limit height + //printf("PartCanvas::drawAutomation x:%d y:%d w:%d h:%d height:%d\n", rr.x(), rr.y(), rr.width(), rr.height(), height); + + p.setBrush(Qt::NoBrush); + CtrlListList* cll = t->controller(); - bool firstRun=true; + ///bool firstRun=true; for(CtrlListList::iterator icll =cll->begin();icll!=cll->end();++icll) { //iCtrlList *icl = icll->second; @@ -2625,7 +3461,8 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t) iCtrl ic=cl->begin(); if (!cl->isVisible()) continue; // skip this iteration if this controller isn't in the visible list - p.setPen(QPen(cl->color(),1,Qt::SolidLine)); + ///p.setPen(QPen(cl->color(),1,Qt::SolidLine)); + p.setPen(QPen(cl->color(), 0, Qt::SolidLine)); // First check that there ARE automation, ic == cl->end means no automation if (ic != cl->end()) { @@ -2651,6 +3488,7 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t) p.drawRect(mapx(tempomap.frame2tick(prevPosFrame))-1, (rr.bottom()-2)-prevVal*height-1, 3, 3); p.drawRect(mapx(tempomap.frame2tick(prevPosFrame))-2, (rr.bottom()-2)-prevVal*height-2, 5, 5); + bool firstRun=true; for (; ic !=cl->end(); ++ic) { CtrlVal cv = ic->second; @@ -2671,6 +3509,7 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t) } int currentPixel = mapx(tempomap.frame2tick(cv.frame)); + //printf(" line x1:%d x2:%d prevVal:%f nextVal:%f\n", leftX, currentPixel, prevVal, nextVal); p.drawLine( leftX, (rr.bottom()-2)-prevVal*height, currentPixel, @@ -2683,20 +3522,23 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t) prevPosFrame=cv.frame; prevVal=nextVal; if (currentPixel > rr.x()+ rr.width()) - goto quitDrawing; + ///goto quitDrawing; + break; // draw a square around the point p.drawRect(mapx(tempomap.frame2tick(prevPosFrame))-2, (rr.bottom()-2)-prevVal*height-2, 5, 5); p.drawRect(mapx(tempomap.frame2tick(prevPosFrame))-1, (rr.bottom()-1)-prevVal*height-2, 3, 3); } + //printf(" endline prevVal:%f\n", prevVal); p.drawLine(mapx(tempomap.frame2tick(prevPosFrame)), (rr.bottom()-2)-prevVal*height, rr.x()+rr.width(), (rr.bottom()-2)-prevVal*height); } } -quitDrawing: - p.restore(); +///quitDrawing: + ///p.restore(); + return; } diff --git a/muse2/muse/arranger/pcanvas.h b/muse2/muse/arranger/pcanvas.h index a0c25f6e..71a0129c 100644 --- a/muse2/muse/arranger/pcanvas.h +++ b/muse2/muse/arranger/pcanvas.h @@ -3,11 +3,14 @@ // Linux Music Editor // $Id: pcanvas.h,v 1.11.2.4 2009/05/24 21:43:44 terminator356 Exp $ // (C) Copyright 1999 Werner Schweer (ws@seh.de) +// Additions, modifications (C) Copyright 2011 Tim E. Real (terminator356 on users DOT sourceforge DOT net) //========================================================= #ifndef __PCANVAS_H__ #define __PCANVAS_H__ +#include <QVector> + #include "song.h" #include "canvas.h" #include "trackautomationview.h" @@ -33,6 +36,9 @@ class NPart : public CItem { const QString name() const { return part()->name(); } void setName(const QString& s) { part()->setName(s); } Track* track() const { return part()->track(); } + + bool leftBorderTouches; // Whether the borders touch other part borders. + bool rightBorderTouches; }; enum ControllerVals { doNothing, movingController, addNewController }; @@ -109,7 +115,7 @@ class PartCanvas : public Canvas { //void drawMidiPart(QPainter&, const QRect& rect, EventList* events, MidiTrack*mt, const QRect& r, int pTick, int from, int to); void drawMidiPart(QPainter&, const QRect& rect, EventList* events, MidiTrack*mt, MidiPart*pt, const QRect& r, int pTick, int from, int to); Track* y2Track(int) const; - void drawAudioTrack(QPainter& p, const QRect& r, AudioTrack* track); + void drawAudioTrack(QPainter& p, const QRect& r, const QRect& bbox, AudioTrack* track); void drawAutomation(QPainter& p, const QRect& r, AudioTrack* track); void drawTopItem(QPainter& p, const QRect& rect); diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp index d7cda62f..6fe2f31d 100644 --- a/muse2/muse/arranger/tlist.cpp +++ b/muse2/muse/arranger/tlist.cpp @@ -227,8 +227,7 @@ void TList::paint(const QRect& r) for (int index = 0; index < header->count(); ++index) { int section = header->logicalIndex(index); int w = header->sectionSize(section); - //QRect r = p.xForm(QRect(x+2, yy, w-4, trackHeight)); - QRect r = p.combinedTransform().mapRect(QRect(x+2, yy, w-4, trackHeight)); + QRect r = p.combinedTransform().mapRect(QRect(x+2, yy, w-4, trackHeight)); switch (section) { case COL_RECORD: diff --git a/muse2/muse/ctrl/ctrlcanvas.cpp b/muse2/muse/ctrl/ctrlcanvas.cpp index 678cd823..68e29f20 100644 --- a/muse2/muse/ctrl/ctrlcanvas.cpp +++ b/muse2/muse/ctrl/ctrlcanvas.cpp @@ -25,9 +25,6 @@ #include "ctrlpanel.h" #include "midiedit/drummap.h" -extern void drawTickRaster(QPainter& p, int x, int y, - int w, int h, int quant); - static MidiCtrlValList veloList(CTRL_VELOCITY); // dummy //--------------------------------------------------------- diff --git a/muse2/muse/driver/jack.cpp b/muse2/muse/driver/jack.cpp index 4857ede5..529e8a60 100644 --- a/muse2/muse/driver/jack.cpp +++ b/muse2/muse/driver/jack.cpp @@ -977,7 +977,8 @@ void JackAudioDevice::graphChanged() // p3.3.37 //delete ports; - free(ports); + //free(ports); + jack_free(ports); // p4.0.29 ports = NULL; } @@ -1063,7 +1064,8 @@ void JackAudioDevice::graphChanged() // p3.3.37 //delete ports; - free(ports); + //free(ports); + jack_free(ports); // p4.0.29 ports = NULL; } @@ -1182,7 +1184,8 @@ void JackAudioDevice::graphChanged() // p3.3.55 // Done with ports. Free them. - free(ports); + //free(ports); + jack_free(ports); // p4.0.29 } } } @@ -1279,7 +1282,8 @@ void JackAudioDevice::graphChanged() } // p3.3.55 // Done with ports. Free them. - free(ports); + //free(ports); + jack_free(ports); // p4.0.29 } } } @@ -1662,7 +1666,8 @@ std::list<QString> JackAudioDevice::outputPorts(bool midi, int aliases) // p3.3.37 if(ports) - free(ports); + //free(ports); + jack_free(ports); // p4.0.29 return clientList; } @@ -1734,7 +1739,8 @@ std::list<QString> JackAudioDevice::inputPorts(bool midi, int aliases) // p3.3.37 if(ports) - free(ports); + //free(ports); + jack_free(ports); // p4.0.29 return clientList; } diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp index 7d5eecc0..5861ca9e 100644 --- a/muse2/muse/functions.cpp +++ b/muse2/muse/functions.cpp @@ -319,7 +319,7 @@ bool modify_notelen(const set<Part*>& parts, int range, int rate, int offset) if (len <= 0) len = 1; - if ((event.tick()+len > part->lenTick()) && (!part->hasHiddenNotes())) + if ((event.tick()+len > part->lenTick()) && (!part->hasHiddenEvents())) partlen[part]=event.tick()+len; // schedule auto-expanding if (event.lenTick() != len) @@ -522,7 +522,7 @@ bool move_notes(const set<Part*>& parts, int range, signed int ticks) if (newEvent.endTick() > part->lenTick()) //if exceeding the part's end: { - if (part->hasHiddenNotes()) // auto-expanding is forbidden, clip + if (part->hasHiddenEvents()) // auto-expanding is forbidden, clip { if (part->lenTick() > newEvent.tick()) newEvent.setLenTick(part->lenTick() - newEvent.tick()); @@ -776,7 +776,7 @@ void paste_at(Part* dest_part, const QString& pt, int pos) if (e.endTick() > dest_part->lenTick()) // event exceeds part? { - if (dest_part->hasHiddenNotes()) // auto-expanding is forbidden? + if (dest_part->hasHiddenEvents()) // auto-expanding is forbidden? { if (e.tick() < dest_part->lenTick()) e.setLenTick(dest_part->lenTick() - e.tick()); // clip diff --git a/muse2/muse/master/master.cpp b/muse2/muse/master/master.cpp index 4a33a8c4..6293e64c 100644 --- a/muse2/muse/master/master.cpp +++ b/muse2/muse/master/master.cpp @@ -22,9 +22,6 @@ #include "icons.h" #include "audio.h" -extern void drawTickRaster(QPainter& p, int x, int y, - int w, int h, int quant); - //--------------------------------------------------------- // Master //--------------------------------------------------------- diff --git a/muse2/muse/master/masteredit.cpp b/muse2/muse/master/masteredit.cpp index 68e8a3b2..777e6066 100644 --- a/muse2/muse/master/masteredit.cpp +++ b/muse2/muse/master/masteredit.cpp @@ -112,6 +112,7 @@ MasterEdit::MasterEdit() addToolBar(tools2); QToolBar* enableMaster = addToolBar(tr("Enable master")); + enableMaster->setObjectName("Enable master"); enableButton = new QToolButton(); enableButton->setCheckable(true); enableButton->setText(tr("Enable")); @@ -121,6 +122,7 @@ MasterEdit::MasterEdit() connect(enableButton, SIGNAL(toggled(bool)), song, SLOT(setMasterFlag(bool))); QToolBar* info = addToolBar(tr("Info")); + info->setObjectName("Info"); QLabel* label = new QLabel(tr("Cursor")); label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); label->setIndent(3); diff --git a/muse2/muse/master/tscale.cpp b/muse2/muse/master/tscale.cpp index d37d5924..9ea34fba 100644 --- a/muse2/muse/master/tscale.cpp +++ b/muse2/muse/master/tscale.cpp @@ -20,8 +20,9 @@ TScale::TScale(QWidget* parent, int ymag) : View(parent, 1, ymag) { - setFont(config.fonts[3]); - int w = 4 * QFontMetrics(config.fonts[4]).width('0'); + setFont(config.fonts[4]); + //int w = 4 * QFontMetrics(config.fonts[4]).width('0'); + int w = 4 * fontMetrics().width('0'); setFixedWidth(w); setMouseTracking(true); } @@ -34,7 +35,7 @@ void TScale::pdraw(QPainter& p, const QRect& r) { int y = r.y(); int h = r.height(); - p.setFont(config.fonts[4]); + //p.setFont(config.fonts[4]); QString s; for (int i = 30000; i <= 250000; i += 10000) { int yy = mapy(280000 - i); @@ -44,8 +45,9 @@ void TScale::pdraw(QPainter& p, const QRect& r) continue; p.drawLine(0, yy, width(), yy); s.setNum(i/1000); - QFontMetrics fm(config.fonts[4]); - p.drawText(width() - fm.width(s) - 1, yy-2, s); + //QFontMetrics fm(config.fonts[4]); + //p.drawText(width() - fm.width(s) - 1, yy-2, s); + p.drawText(width() - fontMetrics().width(s) - 1, yy-2, s); // Use the window font. Tim p4.0.31 } } diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp index 921e59f6..615653b3 100644 --- a/muse2/muse/midiedit/dcanvas.cpp +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -158,7 +158,7 @@ Undo DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp for(iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c) { Part* opart = ip2c->first; - if (opart->hasHiddenNotes()) + if (opart->hasHiddenEvents()) { forbidden=true; break; @@ -350,7 +350,7 @@ void DrumCanvas::newItem(CItem* item, bool noSnap, bool replace) Undo operations; int diff = event.endTick()-part->lenTick(); - if (! ((diff > 0) && part->hasHiddenNotes()) ) //operation is allowed + if (! ((diff > 0) && part->hasHiddenEvents()) ) //operation is allowed { operations.push_back(UndoOp(UndoOp::AddEvent,event, part, false, false)); @@ -463,8 +463,6 @@ void DrumCanvas::drawMoving(QPainter& p, const CItem* item, const QRect& rect) // drawCanvas //--------------------------------------------------------- -extern void drawTickRaster(QPainter& p, int, int, int, int, int); - void DrumCanvas::drawCanvas(QPainter& p, const QRect& rect) { int x = rect.x(); diff --git a/muse2/muse/midiedit/dlist.cpp b/muse2/muse/midiedit/dlist.cpp index 66922e83..d2d5659c 100644 --- a/muse2/muse/midiedit/dlist.cpp +++ b/muse2/muse/midiedit/dlist.cpp @@ -52,15 +52,18 @@ void DList::draw(QPainter& p, const QRect& rect) // else // p.eraseRect(x, yy, w, TH); QHeaderView *h = header; + p.save(); + p.setWorldMatrixEnabled(false); for (int k = 0; k < h->count(); ++k) { int x = h->sectionPosition(k); int w = h->sectionSize(k); - QRect r = p.combinedTransform().mapRect(QRect(x+2, yy, w-4, TH)); + //QRect r = p.combinedTransform().mapRect(QRect(x+2, yy, w-4, TH)); // Gives inconsistent positions. Source shows wrong operation for our needs. + QRect r = map(QRect(x+2, yy, w-4, TH)); // Use our own map instead. QString s; int align = Qt::AlignVCenter | Qt::AlignHCenter; - p.save(); - p.setWorldMatrixEnabled(false); + //p.save(); + //p.setWorldMatrixEnabled(false); switch (k) { case COL_VOL: s.setNum(dm->vol); @@ -114,8 +117,9 @@ void DList::draw(QPainter& p, const QRect& rect) } if (!s.isEmpty()) p.drawText(r, align, s); - p.restore(); + //p.restore(); } + p.restore(); } //--------------------------------------------------- diff --git a/muse2/muse/midiedit/drumedit.cpp b/muse2/muse/midiedit/drumedit.cpp index 5477752d..f8061c06 100644 --- a/muse2/muse/midiedit/drumedit.cpp +++ b/muse2/muse/midiedit/drumedit.cpp @@ -228,7 +228,7 @@ DrumEdit::DrumEdit(PartList* pl, QWidget* parent, const char* name, unsigned ini signalMapper->setMapping(nextAction, DrumCanvas::CMD_SELECT_NEXT_PART); // Functions - menuFunctions = menuBar()->addMenu(tr("&Functions")); + menuFunctions = menuBar()->addMenu(tr("Fu&nctions")); menuFunctions->setTearOffEnabled(true); diff --git a/muse2/muse/midiedit/pianoroll.cpp b/muse2/muse/midiedit/pianoroll.cpp index d8fdc34d..c98657ea 100644 --- a/muse2/muse/midiedit/pianoroll.cpp +++ b/muse2/muse/midiedit/pianoroll.cpp @@ -178,7 +178,7 @@ PianoRoll::PianoRoll(PartList* pl, QWidget* parent, const char* name, unsigned i - menuFunctions = menuBar()->addMenu(tr("&Functions")); + menuFunctions = menuBar()->addMenu(tr("Fu&nctions")); menuFunctions->setTearOffEnabled(true); diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp index d06274b4..82a6a215 100644 --- a/muse2/muse/midiedit/prcanvas.cpp +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -37,6 +37,7 @@ #include "song.h" #include "audio.h" #include "functions.h" +#include "gconfig.h" #define CHORD_TIMEOUT 75 @@ -101,7 +102,7 @@ PianoCanvas::PianoCanvas(MidiEditor* pr, QWidget* parent, int sx, int sy) int PianoCanvas::pitch2y(int pitch) const { int tt[] = { - 5, 12, 19, 26, 33, 44, 51, 58, 64, 71, 78, 85 + 5, 13, 19, 26, 34, 44, 52, 58, 65, 71, 78, 85 }; int y = (75 * KH) - (tt[pitch%12] + (7 * KH) * (pitch/12)); if (y < 0) @@ -146,9 +147,23 @@ void PianoCanvas::drawItem(QPainter& p, const CItem* item, QRect r = item->bbox(); if(!virt()) r.moveCenter(map(item->pos())); - r = r.intersected(rect); - if(!r.isValid()) + + //QRect rr = p.transform().mapRect(rect); // Gives inconsistent positions. Source shows wrong operation for our needs. + QRect rr = map(rect); // Use our own map instead. + QRect mer = map(r); + + ///r = r.intersected(rect); + //QRect rr = r & rect; + ///if(!r.isValid()) + //if(!rr.isValid()) + // return; + QRect mr = rr & mer; + //if(!mr.isValid()) + if(mr.isNull()) return; + + //p.save(); + p.setPen(Qt::black); struct Triple { int r, g, b; @@ -169,25 +184,25 @@ void PianoCanvas::drawItem(QPainter& p, const CItem* item, { 0xff, 0xbf, 0x7a } }; + QColor color; NEvent* nevent = (NEvent*) item; Event event = nevent->event(); if (nevent->part() != curPart){ if(item->isMoving()) - p.setBrush(Qt::gray); + color = Qt::gray; else if(item->isSelected()) - p.setBrush(Qt::black); + color = Qt::black; else - p.setBrush(Qt::lightGray); + color = Qt::lightGray; } else { if (item->isMoving()) { - p.setBrush(Qt::gray); + color = Qt::gray; } else if (item->isSelected()) { - p.setBrush(Qt::black); + color = Qt::black; } else { - QColor color; color.setRgb(0, 0, 255); switch(colorMode) { case 0: @@ -208,10 +223,50 @@ void PianoCanvas::drawItem(QPainter& p, const CItem* item, } break; } - p.setBrush(color); } } - p.drawRect(r); + + bool wmtxen = p.worldMatrixEnabled(); + p.setWorldMatrixEnabled(false); + int mx = mr.x(); + int my = mr.y(); + int mw = mr.width(); + int mh = mr.height(); + int mex = mer.x(); + int mey = mer.y(); + int mew = mer.width(); + int meh = mer.height(); + //int mfx = mx; + //if(mfx == mex) mfx += 1; + //int mfy = my; + //if(mfy == mey) mfy += 1; + //int mfw = mw; + //if(mfw == mew) mfw -= 1; + //if(mfx == mex) mfw -= 1; + //int mfh = mh; + //if(mfh == meh) mfh -= 1; + //if(mfy == mey) mfh -= 1; + color.setAlpha(config.globalAlphaBlend); + //QLinearGradient gradient(mex + 1, mey + 1, mex + 1, mey + meh - 2); // Inside the border + //gradient.setColorAt(0, color); + //gradient.setColorAt(1, color.darker()); + //QBrush brush(gradient); + QBrush brush(color); + p.fillRect(mr, brush); + //p.fillRect(mfx, mfy, mfw, mfh, brush); + + if(mex >= mx && mex <= mx + mw) + p.drawLine(mex, my, mex, my + mh - 1); // The left edge + if(mex + mew >= mx && mex + mew <= mx + mw) + p.drawLine(mex + mew, my, mex + mew, my + mh - 1); // The right edge + if(mey >= my && mey <= my + mh) + p.drawLine(mx, mey, mx + mw - 1, mey); // The top edge + if(mey + meh >= my && mey + meh <= my + mh) + p.drawLine(mx, mey + meh - 1, mx + mw - 1, mey + meh - 1); // The bottom edge + + //p.setWorldMatrixEnabled(true); + p.setWorldMatrixEnabled(wmtxen); + //p.restore(); } //--------------------------------------------------------- @@ -314,7 +369,7 @@ Undo PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dty for(iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c) { Part* opart = ip2c->first; - if (opart->hasHiddenNotes()) + if (opart->hasHiddenEvents()) { forbidden=true; break; @@ -468,7 +523,7 @@ void PianoCanvas::newItem(CItem* item, bool noSnap) Undo operations; int diff = event.endTick()-part->lenTick(); - if (! ((diff > 0) && part->hasHiddenNotes()) ) //operation is allowed + if (! ((diff > 0) && part->hasHiddenEvents()) ) //operation is allowed { operations.push_back(UndoOp(UndoOp::AddEvent,event, part, false, false)); @@ -513,7 +568,7 @@ void PianoCanvas::resizeItem(CItem* item, bool noSnap, bool) // experime Undo operations; int diff = event.tick()+len-part->lenTick(); - if (! ((diff > 0) && part->hasHiddenNotes()) ) //operation is allowed + if (! ((diff > 0) && part->hasHiddenEvents()) ) //operation is allowed { newEvent.setLenTick(len); operations.push_back(UndoOp(UndoOp::ModifyEvent,newEvent, event, nevent->part(), false, false)); @@ -680,48 +735,6 @@ void PianoCanvas::pianoReleased(int pitch, bool) } //--------------------------------------------------------- -// drawTickRaster -//--------------------------------------------------------- - -void drawTickRaster(QPainter& p, int x, int y, int w, int h, int raster) - { - int bar1, bar2, beat; - unsigned tick; - AL::sigmap.tickValues(x, &bar1, &beat, &tick); - AL::sigmap.tickValues(x+w, &bar2, &beat, &tick); - ++bar2; - int y2 = y + h; - for (int bar = bar1; bar < bar2; ++bar) { - unsigned x = AL::sigmap.bar2tick(bar, 0, 0); - p.setPen(Qt::black); - p.drawLine(x, y, x, y2); - int z, n; - AL::sigmap.timesig(x, z, n); - ///int q = p.xForm(QPoint(raster, 0)).x() - p.xForm(QPoint(0, 0)).x(); - int q = p.combinedTransform().map(QPoint(raster, 0)).x() - p.combinedTransform().map(QPoint(0, 0)).x(); - int qq = raster; - if (q < 8) // grid too dense - qq *= 2; - p.setPen(Qt::lightGray); - if (raster>=4) { - int xx = x + qq; - int xxx = AL::sigmap.bar2tick(bar, z, 0); - while (xx <= xxx) { - p.drawLine(xx, y, xx, y2); - xx += qq; - } - xx = xxx; - } - p.setPen(Qt::gray); - for (int beat = 1; beat < z; beat++) { - int xx = AL::sigmap.bar2tick(bar, beat, 0); - p.drawLine(xx, y, xx, y2); - } - - } - } - -//--------------------------------------------------------- // draw //--------------------------------------------------------- @@ -732,31 +745,63 @@ void PianoCanvas::drawCanvas(QPainter& p, const QRect& rect) int w = rect.width(); int h = rect.height(); + // Changed to draw in device coordinate space instead of virtual, transformed space. Tim. p4.0.30 + + //int mx = mapx(x); + //int my = mapy(y); + //int mw = mapx(x + w) - mx; + //int mw = mapx(x + w) - mx - 1; + //int mh = mapy(y + h) - my; + //int mh = mapy(y + h) - my - 1; + + // p.save(); + // FIXME Can't get horizontal lines quite right yet. Draw in virtual space for now... + ///p.setWorldMatrixEnabled(false); + //--------------------------------------------------- // horizontal lines //--------------------------------------------------- int yy = ((y-1) / KH) * KH + KH; + //int yy = my + KH; + //int yy = ((my-1) / KH) * KH + KH; + //int yoff = -rmapy(yorg) - ypos; int key = 75 - (yy / KH); + + //printf("PianoCanvas::drawCanvas x:%d y:%d w:%d h:%d mx:%d my:%d mw:%d mh:%d yy:%d key:%d\n", x, y, w, h, mx, my, mw, mh, yy, key); + for (; yy < y + h; yy += KH) { + //for (; yy + yoff < my + mh; yy += KH) { + //for (; yy < my + mh; yy += KH) { switch (key % 7) { case 0: case 3: p.setPen(Qt::black); p.drawLine(x, yy, x + w, yy); + //p.drawLine(mx, yy + yoff, mx + mw, yy + yoff); + //p.drawLine(mx, yy, mx + mw, yy); break; default: p.fillRect(x, yy-3, w, 6, QBrush(QColor(230,230,230))); + //p.fillRect(mx, yy-3 + yoff, mw, 6, QBrush(QColor(230,230,230))); + //p.fillRect(mx, yy-3, mw, 6, QBrush(QColor(230,230,230))); break; } --key; } - + //p.restore(); + ///p.setWorldMatrixEnabled(true); + + //p.setWorldMatrixEnabled(false); + //--------------------------------------------------- // vertical lines //--------------------------------------------------- drawTickRaster(p, x, y, w, h, editor->raster()); + + //p.restore(); + //p.setWorldMatrixEnabled(true); } //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index 2f077365..157a6845 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -422,7 +422,7 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) - QMenu* functions_menu = menuBar()->addMenu(tr("&Functions")); + QMenu* functions_menu = menuBar()->addMenu(tr("Fu&nctions")); func_quantize_action = functions_menu->addAction(tr("&Quantize"), menu_mapper, SLOT(map())); func_notelen_action = functions_menu->addAction(tr("Change note &length"), menu_mapper, SLOT(map())); @@ -3908,7 +3908,7 @@ void ScoreCanvas::mouseMoveEvent (QMouseEvent* event) unsigned newpartlen=dragged_event_part->lenTick(); if (tmp.endTick() > dragged_event_part->lenTick()) { - if (dragged_event_part->hasHiddenNotes()) // do not allow autoexpand + if (dragged_event_part->hasHiddenEvents()) // do not allow autoexpand { tmp.setLenTick(dragged_event_part->lenTick() - tmp.tick()); if (debugMsg) cout << "resized note would exceed its part; limiting length to " << tmp.lenTick() << endl; @@ -4461,7 +4461,7 @@ void staff_t::update_part_indices() * * o maybe remove "insert empty measure"? * o add "move other notes" or "overwrite notes" or "mix with notes" to paste - * o draw the edge of parts hiding notes "jagged" (hasHiddenNotes() is interesting for this) + * o draw the edge of parts hiding notes "jagged" (hasHiddenEvents() is interesting for this) - Done. Tim. * o shrink a part from its beginning as well! watch out for clones! * o insert empty measure should also work inside parts, that is, * move notes _within_ parts diff --git a/muse2/muse/mixer/astrip.cpp b/muse2/muse/mixer/astrip.cpp index 5644e6eb..658a4970 100644 --- a/muse2/muse/mixer/astrip.cpp +++ b/muse2/muse/mixer/astrip.cpp @@ -211,16 +211,14 @@ void AudioStrip::songChanged(int val) autoType->setCurrentItem(track->automationType()); if(track->automationType() == AUTO_TOUCH || track->automationType() == AUTO_WRITE) { - //autoType->setPaletteBackgroundColor(Qt::red); QPalette palette; - palette.setColor(autoType->backgroundRole(), QColor(Qt::red)); + palette.setColor(QPalette::Button, QColor(Qt::red)); autoType->setPalette(palette); } else { - //autoType->setPaletteBackgroundColor(qApp->palette().active().background()); QPalette palette; - palette.setColor(autoType->backgroundRole(), qApp->palette().color(QPalette::Active, QPalette::Background)); + palette.setColor(QPalette::Button, qApp->palette().color(QPalette::Active, QPalette::Background)); autoType->setPalette(palette); } @@ -927,41 +925,31 @@ AudioStrip::AudioStrip(QWidget* parent, AudioTrack* at) // automation type //--------------------------------------------------- - autoType = new ComboBox(this); + autoType = new ComboBox(); autoType->setFont(config.fonts[1]); autoType->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); - autoType->setAlignment(Qt::AlignCenter); - autoType->insertItem(tr("Off"), AUTO_OFF); - autoType->insertItem(tr("Read"), AUTO_READ); - autoType->insertItem(tr("Touch"), AUTO_TOUCH); - autoType->insertItem(tr("Write"), AUTO_WRITE); + autoType->addAction(tr("Off"), AUTO_OFF); + autoType->addAction(tr("Read"), AUTO_READ); + autoType->addAction(tr("Touch"), AUTO_TOUCH); + autoType->addAction(tr("Write"), AUTO_WRITE); autoType->setCurrentItem(t->automationType()); - // FIXME: TODO: Convert ComboBox to QT4 - //autoType->insertItem(AUTO_OFF, tr("Off")); - //autoType->insertItem(AUTO_READ, tr("Read")); - //autoType->insertItem(AUTO_TOUCH, tr("Touch")); - //autoType->insertItem(AUTO_WRITE, tr("Write")); - //autoType->setCurrentIndex(t->automationType()); - + if(t->automationType() == AUTO_TOUCH || t->automationType() == AUTO_WRITE) { - // FIXME: - //autoType->setPaletteBackgroundColor(Qt::red); - QPalette palette; - palette.setColor(autoType->backgroundRole(), QColor(Qt::red)); - autoType->setPalette(palette); + QPalette palette; + palette.setColor(QPalette::Button, QColor(Qt::red)); + autoType->setPalette(palette); } else { - // FIXME: - //autoType->setPaletteBackgroundColor(qApp->palette().active().background()); QPalette palette; - palette.setColor(autoType->backgroundRole(), qApp->palette().color(QPalette::Active, QPalette::Background)); + palette.setColor(QPalette::Button, qApp->palette().color(QPalette::Active, QPalette::Background)); autoType->setPalette(palette); } + autoType->setToolTip(tr("automation type")); - connect(autoType, SIGNAL(activated(int,int)), SLOT(setAutomationType(int,int))); + connect(autoType, SIGNAL(activated(int)), SLOT(setAutomationType(int))); grid->addWidget(autoType, _curGridRow++, 0, 1, 2); if (off) { diff --git a/muse2/muse/mixer/mstrip.cpp b/muse2/muse/mixer/mstrip.cpp index d773708a..ad21916d 100644 --- a/muse2/muse/mixer/mstrip.cpp +++ b/muse2/muse/mixer/mstrip.cpp @@ -405,28 +405,21 @@ MidiStrip::MidiStrip(QWidget* parent, MidiTrack* t) // automation mode //--------------------------------------------------- - autoType = new ComboBox(this); + autoType = new ComboBox(); autoType->setFont(config.fonts[1]); autoType->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); - autoType->setAlignment(Qt::AlignCenter); autoType->setEnabled(false); // Removed by T356. // Disabled for now. There is no midi automation mechanism yet... - //autoType->insertItem(tr("Off"), AUTO_OFF); - //autoType->insertItem(tr("Read"), AUTO_READ); - //autoType->insertItem(tr("Touch"), AUTO_TOUCH); - //autoType->insertItem(tr("Write"), AUTO_WRITE); + //autoType->addAction(tr("Off"), AUTO_OFF); + //autoType->addAction(tr("Read"), AUTO_READ); + //autoType->addAction(tr("Touch"), AUTO_TOUCH); + //autoType->addAction(tr("Write"), AUTO_WRITE); //autoType->setCurrentItem(t->automationType()); - // TODO: Convert ComboBox to QT4 - //autoType->insertItem(AUTO_OFF, tr("Off")); - //autoType->insertItem(AUTO_READ, tr("Read")); - //autoType->insertItem(AUTO_TOUCH, tr("Touch")); - //autoType->insertItem(AUTO_WRITE, tr("Write")); - //autoType->setCurrentIndex(t->automationType()); - //autoType->setToolTip(tr("automation type")); - - //connect(autoType, SIGNAL(activated(int,int)), SLOT(setAutomationType(int,int))); + //autoType->setToolTip(tr("automation type")); + //connect(autoType, SIGNAL(activated(int)), SLOT(setAutomationType(int))); + grid->addWidget(autoType, _curGridRow++, 0, 1, 2); connect(heartBeatTimer, SIGNAL(timeout()), SLOT(heartBeat())); inHeartBeat = false; diff --git a/muse2/muse/mixer/strip.cpp b/muse2/muse/mixer/strip.cpp index 0c4059d8..3cf9765d 100644 --- a/muse2/muse/mixer/strip.cpp +++ b/muse2/muse/mixer/strip.cpp @@ -257,7 +257,7 @@ Strip::~Strip() // setAutomationType //--------------------------------------------------------- -void Strip::setAutomationType(int t,int) +void Strip::setAutomationType(int t) { track->setAutomationType(AutomationType(t)); song->update(SC_AUTOMATION); diff --git a/muse2/muse/mixer/strip.h b/muse2/muse/mixer/strip.h index b138992e..cf3babe8 100644 --- a/muse2/muse/mixer/strip.h +++ b/muse2/muse/mixer/strip.h @@ -60,7 +60,7 @@ class Strip : public QFrame { protected slots: virtual void heartBeat(); - void setAutomationType(int t,int); + void setAutomationType(int t); public slots: void resetPeaks(); diff --git a/muse2/muse/part.cpp b/muse2/muse/part.cpp index 67cf441e..239d53d5 100644 --- a/muse2/muse/part.cpp +++ b/muse2/muse/part.cpp @@ -4,6 +4,7 @@ // $Id: part.cpp,v 1.12.2.17 2009/06/25 05:13:02 terminator356 Exp $ // // (C) Copyright 1999/2000 Werner Schweer (ws@seh.de) +// Additions, modifications (C) Copyright 2011 Tim E. Real (terminator356 on users DOT sourceforge DOT net) //========================================================= #include <stdio.h> @@ -655,6 +656,7 @@ Part* PartList::find(int idx) Part::Part(Track* t) { + _hiddenEvents = NoEventsHidden; _prevClone = this; _nextClone = this; setSn(newSn()); @@ -673,6 +675,7 @@ Part::Part(Track* t) Part::Part(Track* t, EventList* ev) { + _hiddenEvents = NoEventsHidden; _prevClone = this; _nextClone = this; setSn(newSn()); @@ -849,7 +852,6 @@ void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len, bool doClo Event newEvent = e.clone(); newEvent.setLenFrame(new_partlength - event_startframe); // Do not do port controller values and clone parts. - audio->msgChangeEvent(e, newEvent, nPart, false, false, false); operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, e, nPart, false,false)); } } @@ -889,7 +891,6 @@ void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len, bool doClo nPart->setLenFrame(new_partlength); // Do not do port controller values and clone parts. - audio->msgChangePart(oPart, nPart, false, false, false); operations.push_back(UndoOp(UndoOp::ModifyPart, oPart, nPart, false, false)); song->applyOperationGroup(operations); } @@ -1169,15 +1170,38 @@ WavePart* WavePart::clone() const return new WavePart(*this); } +/* +bool Part::hasHiddenNotes() +{ + unsigned lastNote=0; + for (iEvent ev=events()->begin(); ev!=events()->end(); ev++) + if (ev->second.endTick() > lastNote) + lastNote=ev->second.endTick(); + + return lastNote > lenTick(); +} +*/ -bool Part::hasHiddenNotes() +//--------------------------------------------------------- +// hasHiddenEvents +// Returns combination of HiddenEventsType enum. +//--------------------------------------------------------- + +int Part::hasHiddenEvents() { - unsigned lastNote=0; + unsigned len = lenTick(); - for (iEvent ev=events()->begin(); ev!=events()->end(); ev++) - if (ev->second.endTick() > lastNote) - lastNote=ev->second.endTick(); - - return lastNote > lenTick(); + // TODO: For now, we don't support events before the left border, only events past the right border. + for(iEvent ev=events()->begin(); ev!=events()->end(); ev++) + { + if(ev->second.endTick() > len) + { + _hiddenEvents = RightEventsHidden; // Cache the result for later. + return _hiddenEvents; + } + } + _hiddenEvents = NoEventsHidden; // Cache the result for later. + return _hiddenEvents; } + diff --git a/muse2/muse/part.h b/muse2/muse/part.h index ff7091a6..67a67dbb 100644 --- a/muse2/muse/part.h +++ b/muse2/muse/part.h @@ -4,6 +4,7 @@ // $Id: part.h,v 1.5.2.4 2009/05/24 21:43:44 terminator356 Exp $ // // (C) Copyright 1999/2000 Werner Schweer (ws@seh.de) +// Additions, modifications (C) Copyright 2011 Tim E. Real (terminator356 on users DOT sourceforge DOT net) //========================================================= #ifndef __PART_H__ @@ -40,6 +41,10 @@ typedef CloneList::iterator iClone; //--------------------------------------------------------- class Part : public PosLen { + public: + enum HiddenEventsType { NoEventsHidden = 0, LeftEventsHidden, RightEventsHidden }; + + private: static int snGen; int _sn; @@ -48,6 +53,8 @@ class Part : public PosLen { bool _mute; int _colorIndex; + int _hiddenEvents; // Combination of HiddenEventsType. + protected: Track* _track; EventList* _events; @@ -82,7 +89,11 @@ class Part : public PosLen { void setPrevClone(Part* p) { _prevClone = p; } void setNextClone(Part* p) { _nextClone = p; } - bool hasHiddenNotes(); + // Returns combination of HiddenEventsType enum. + int hasHiddenEvents(); + // If repeated calls to hasHiddenEvents() are desired, then to avoid re-iteration of the event list, + // call this after hasHiddenEvents(). + int cachedHasHiddenEvents() const { return _hiddenEvents; } iEvent addEvent(Event& p); diff --git a/muse2/muse/steprec.cpp b/muse2/muse/steprec.cpp index c1fc23b1..45af3930 100644 --- a/muse2/muse/steprec.cpp +++ b/muse2/muse/steprec.cpp @@ -77,7 +77,7 @@ void StepRec::record(Part* part, int pitch, int len, int step, int velo, bool ct { // if we already entered the note, delete it // if we would find a note after part->lenTick(), the above "if" - // avoids this. this has to be avoided because then part->hasHiddenNotes() is true + // avoids this. this has to be avoided because then part->hasHiddenEvents() is true // which results in forbidding any action beyond its end EventRange range = events->equal_range(tick - part->tick()); for (iEvent i = range.first; i != range.second; ++i) @@ -173,7 +173,7 @@ void StepRec::record(Part* part, int pitch, int len, int step, int velo, bool ct } steprec_record_foot: - if (!((lasttick > part->lenTick()) && part->hasHiddenNotes())) // allowed? + if (!((lasttick > part->lenTick()) && part->hasHiddenEvents())) // allowed? { if (lasttick > part->lenTick()) // we have to expand the part? schedule_resize_all_same_len_clone_parts(part, lasttick, operations); diff --git a/muse2/muse/widgets/canvas.cpp b/muse2/muse/widgets/canvas.cpp index a74e8a8f..c7186a2d 100644 --- a/muse2/muse/widgets/canvas.cpp +++ b/muse2/muse/widgets/canvas.cpp @@ -3,6 +3,7 @@ // Linux Music Editor // $Id: canvas.cpp,v 1.10.2.17 2009/05/03 04:14:01 terminator356 Exp $ // (C) Copyright 1999 Werner Schweer (ws@seh.de) +// Additions, modifications (C) Copyright 2011 Tim E. Real (terminator356 on users DOT sourceforge DOT net) //========================================================= #include <stdio.h> @@ -18,6 +19,8 @@ #include <QMouseEvent> #include <QWheelEvent> +#include <vector> + #include "song.h" #include "event.h" #include "citem.h" @@ -148,6 +151,11 @@ void Canvas::draw(QPainter& p, const QRect& rect) int h = rect.height(); int x2 = x + w; + std::vector<CItem*> list1; + std::vector<CItem*> list2; + //std::vector<CItem*> list3; + std::vector<CItem*> list4; + if (virt()) { drawCanvas(p, rect); @@ -157,22 +165,24 @@ void Canvas::draw(QPainter& p, const QRect& rect) iCItem to(items.lower_bound(x2)); + /* // Draw items from other parts behind all others. // Only for items with events (not arranger parts). for(iCItem i = items.begin(); i != to; ++i) { CItem* ci = i->second; + // NOTE Optimization: For each item call this once now, then use cached results later via cachedHasHiddenEvents(). + ci->part()->hasHiddenEvents(); if(!ci->event().empty() && ci->part() != curPart) - { drawItem(p, ci, rect); - } } - + + // Draw unselected parts behind selected. for (iCItem i = items.begin(); i != to; ++i) { CItem* ci = i->second; - // Draw unselected parts behind selected. - if(!ci->isSelected() && !ci->isMoving() && (ci->event().empty() || ci->part() == curPart)) + if((!ci->isSelected() && !ci->isMoving() && (ci->event().empty() || ci->part() == curPart)) + && !(ci->event().empty() && (ci->part()->events()->arefCount() > 1 || ci->part()->cachedHasHiddenEvents()))) // p4.0.29 { drawItem(p, ci, rect); } @@ -181,12 +191,57 @@ void Canvas::draw(QPainter& p, const QRect& rect) // Draw selected parts in front of unselected. for (iCItem i = items.begin(); i != to; ++i) { - CItem* ci = i->second; - if(ci->isSelected() && !ci->isMoving() && (ci->event().empty() || ci->part() == curPart)) - { - drawItem(p, ci, rect); - } + CItem* ci = i->second; + if(ci->isSelected() && !ci->isMoving() && (ci->event().empty() || ci->part() == curPart)) + //if((ci->isSelected() && !ci->isMoving() && (ci->event().empty() || ci->part() == curPart)) + // || (ci->event().empty() && (ci->part()->events()->arefCount() > 1 || ci->part()->cachedHasHiddenEvents()))) + { + drawItem(p, ci, rect); + } + } + */ + + // p4.0.29 + for(iCItem i = items.begin(); i != to; ++i) + { + CItem* ci = i->second; + // NOTE Optimization: For each item call this once now, then use cached results later via cachedHasHiddenEvents(). + // Not required for now. + //ci->part()->hasHiddenEvents(); + + // Draw items from other parts behind all others. + // Only for items with events (not arranger parts). + if(!ci->event().empty() && ci->part() != curPart) + list1.push_back(ci); + else if(!ci->isMoving() && (ci->event().empty() || ci->part() == curPart)) + { + // Draw selected parts in front of all others. + if(ci->isSelected()) + list4.push_back(ci); + // Draw clone parts, and parts with hidden events, in front of others all except selected. + //else if(ci->event().empty() && (ci->part()->events()->arefCount() > 1 || ci->part()->cachedHasHiddenEvents())) + // Draw clone parts in front of others all except selected. + //else if(ci->event().empty() && (ci->part()->events()->arefCount() > 1)) + // list3.push_back(ci); + else + // Draw unselected parts. + list2.push_back(ci); + } } + int i; + int sz = list1.size(); + for(i = 0; i != sz; ++i) + drawItem(p, list1[i], rect); + sz = list2.size(); + for(i = 0; i != sz; ++i) + drawItem(p, list2[i], rect); + //sz = list3.size(); + //for(i = 0; i != sz; ++i) + // drawItem(p, list3[i], rect); + sz = list4.size(); + for(i = 0; i != sz; ++i) + drawItem(p, list4[i], rect); + to = moving.lower_bound(x2); for (iCItem i = moving.begin(); i != to; ++i) { @@ -237,21 +292,22 @@ void Canvas::draw(QPainter& p, const QRect& rect) //--------------------------------------------------- // draw Canvas Items //--------------------------------------------------- - + + /* // Draw items from other parts behind all others. // Only for items with events (not arranger parts). for(iCItem i = items.begin(); i != items.end(); ++i) { CItem* ci = i->second; + // NOTE Optimization: For each item call this once now, then use cached results later via cachedHasHiddenEvents(). + ci->part()->hasHiddenEvents(); if(!ci->event().empty() && ci->part() != curPart) - { drawItem(p, ci, rect); - } - } - + } + + // Draw unselected parts behind selected. for (iCItem i = items.begin(); i != items.end(); ++i) { CItem* ci = i->second; - // Draw unselected parts behind selected. if(!ci->isSelected() && !ci->isMoving() && (ci->event().empty() || ci->part() == curPart)) { drawItem(p, ci, rect); @@ -262,10 +318,55 @@ void Canvas::draw(QPainter& p, const QRect& rect) for (iCItem i = items.begin(); i != items.end(); ++i) { CItem* ci = i->second; if(ci->isSelected() && !ci->isMoving() && (ci->event().empty() || ci->part() == curPart)) - { - drawItem(p, ci, rect); - } - } + //if((ci->isSelected() && !ci->isMoving() && (ci->event().empty() || ci->part() == curPart)) + // || (ci->event().empty() && (ci->part()->events()->arefCount() > 1 || ci->part()->cachedHasHiddenEvents()))) + { + drawItem(p, ci, rect); + } + } + */ + + // p4.0.29 + for(iCItem i = items.begin(); i != items.end(); ++i) + { + CItem* ci = i->second; + // NOTE Optimization: For each item call this once now, then use cached results later via cachedHasHiddenEvents(). + // Not required for now. + //ci->part()->hasHiddenEvents(); + + // Draw items from other parts behind all others. + // Only for items with events (not arranger parts). + if(!ci->event().empty() && ci->part() != curPart) + list1.push_back(ci); + else if(!ci->isMoving() && (ci->event().empty() || ci->part() == curPart)) + { + // Draw selected parts in front of all others. + if(ci->isSelected()) + list4.push_back(ci); + // Draw clone parts, and parts with hidden events, in front of others all except selected. + //else if(ci->event().empty() && (ci->part()->events()->arefCount() > 1 || ci->part()->cachedHasHiddenEvents())) + // Draw clone parts in front of others all except selected. + //else if(ci->event().empty() && (ci->part()->events()->arefCount() > 1)) + // list3.push_back(ci); + else + // Draw unselected parts. + list2.push_back(ci); + } + } + int i; + int sz = list1.size(); + for(i = 0; i != sz; ++i) + drawItem(p, list1[i], rect); + sz = list2.size(); + for(i = 0; i != sz; ++i) + drawItem(p, list2[i], rect); + //sz = list3.size(); + //for(i = 0; i != sz; ++i) + // drawItem(p, list3[i], rect); + sz = list4.size(); + for(i = 0; i != sz; ++i) + drawItem(p, list4[i], rect); + for (iCItem i = moving.begin(); i != moving.end(); ++i) { drawItem(p, i->second, rect); @@ -273,19 +374,26 @@ void Canvas::draw(QPainter& p, const QRect& rect) drawTopItem(p, QRect(x,y,w,h)); p.save(); setPainter(p); - } + } //--------------------------------------------------- // draw marker //--------------------------------------------------- - int y2 = y + h; + //p.save(); + bool wmtxen = p.worldMatrixEnabled(); + p.setWorldMatrixEnabled(false); + + int my = mapy(y); + //int y2 = y + h; + int my2 = mapy(y + h); MarkerList* marker = song->marker(); for (iMarker m = marker->begin(); m != marker->end(); ++m) { int xp = m->second.tick(); if (xp >= x && xp < x+w) { p.setPen(Qt::green); - p.drawLine(xp, y, xp, y2); + //p.drawLine(xp, y, xp, y2); + p.drawLine(mapx(xp), my, mapx(xp), my2); } } @@ -294,16 +402,28 @@ void Canvas::draw(QPainter& p, const QRect& rect) //--------------------------------------------------- p.setPen(Qt::blue); + int mx; if (pos[1] >= unsigned(x) && pos[1] < unsigned(x2)) { - p.drawLine(pos[1], y, pos[1], y2); + //p.drawLine(pos[1], y, pos[1], y2); + mx = mapx(pos[1]); + p.drawLine(mx, my, mx, my2); + } + if (pos[2] >= unsigned(x) && pos[2] < unsigned(x2)) { + //p.drawLine(pos[2], y, pos[2], y2); + mx = mapx(pos[2]); + p.drawLine(mx, my, mx, my2); } - if (pos[2] >= unsigned(x) && pos[2] < unsigned(x2)) - p.drawLine(pos[2], y, pos[2], y2); p.setPen(Qt::red); if (pos[0] >= unsigned(x) && pos[0] < unsigned(x2)) { - p.drawLine(pos[0], y, pos[0], y2); + //p.drawLine(pos[0], y, pos[0], y2); + mx = mapx(pos[0]); + p.drawLine(mx, my, mx, my2); } + //p.restore(); + //p.setWorldMatrixEnabled(true); + p.setWorldMatrixEnabled(wmtxen); + //--------------------------------------------------- // draw lasso //--------------------------------------------------- diff --git a/muse2/muse/widgets/canvas.h b/muse2/muse/widgets/canvas.h index dbe13fcb..99bbabee 100644 --- a/muse2/muse/widgets/canvas.h +++ b/muse2/muse/widgets/canvas.h @@ -3,6 +3,7 @@ // Linux Music Editor // $Id: canvas.h,v 1.3.2.8 2009/02/02 21:38:01 terminator356 Exp $ // (C) Copyright 1999 Werner Schweer (ws@seh.de) +// Additions, modifications (C) Copyright 2011 Tim E. Real (terminator356 on users DOT sourceforge DOT net) //========================================================= #ifndef __CANVAS_H__ diff --git a/muse2/muse/widgets/combobox.cpp b/muse2/muse/widgets/combobox.cpp index 9e278376..bd78d6f2 100644 --- a/muse2/muse/widgets/combobox.cpp +++ b/muse2/muse/widgets/combobox.cpp @@ -6,6 +6,8 @@ //========================================================= #include <QMenu> +#include <QSignalMapper> +#include <QWheelEvent> #include "combobox.h" @@ -14,67 +16,75 @@ //--------------------------------------------------------- ComboBox::ComboBox(QWidget* parent, const char* name) - : QLabel(parent) + : QToolButton(parent) { setObjectName(name); _currentItem = 0; - _id = -1; - list = new QMenu(0); - connect(list, SIGNAL(triggered(QAction*)), SLOT(activatedIntern(QAction*))); - setFrameStyle(QFrame::Panel | QFrame::Raised); - setLineWidth(2); + + menu = new QMenu(this); + + autoTypeSignalMapper = new QSignalMapper(this); + connect(autoTypeSignalMapper, SIGNAL(mapped(int)), this, SLOT(activatedIntern(int))); } ComboBox::~ComboBox() { - delete list; + delete menu; } //--------------------------------------------------------- // mousePressEvent //--------------------------------------------------------- -void ComboBox::mousePressEvent(QMouseEvent*) +void ComboBox::mousePressEvent(QMouseEvent* /*ev*/) + { + menu->exec(QCursor::pos()); + } + +//--------------------------------------------------------- +// wheelEvent +//--------------------------------------------------------- + +void ComboBox::wheelEvent(QWheelEvent* ev) { - list->exec(QCursor::pos()); + int i = itemlist.indexOf(_currentItem); + int len = itemlist.count(); + if (ev->delta() > 0 && i > 0) + activatedIntern(_currentItem-1); + else if (ev->delta() < 0 && -1 < i && i < len - 1) + activatedIntern(_currentItem+1); } //--------------------------------------------------------- // activated //--------------------------------------------------------- -void ComboBox::activatedIntern(QAction* act) +void ComboBox::activatedIntern(int id) { - _currentItem = act->data().toInt(); - emit activated(_currentItem, _id); - setText(act->text()); + setCurrentItem(id); + emit activated(id); } //--------------------------------------------------------- // setCurrentItem //--------------------------------------------------------- -void ComboBox::setCurrentItem(int i) +void ComboBox::setCurrentItem(int id) { - _currentItem = i; - // ORCAN - CHECK - QList<QAction *> actions = list->actions(); - for (QList<QAction *>::iterator it = actions.begin(); it != actions.end(); ++it) { - QAction* act = *it; - if (act->data().toInt() == i) { - setText(act->text()); - break; - } - } + QAction* act = (QAction*) autoTypeSignalMapper->mapping(id); + _currentItem = id; + setText(act->text()); } //--------------------------------------------------------- // insertItem //--------------------------------------------------------- -void ComboBox::insertItem(const QString& s, int id) +void ComboBox::addAction(const QString& s, int id) { - QAction *act = list->addAction(s); - act->setData(id); + QAction *act = menu->addAction(s); + connect(act, SIGNAL(triggered()), autoTypeSignalMapper, SLOT(map())); + autoTypeSignalMapper->setMapping(act, id); + itemlist << id; } diff --git a/muse2/muse/widgets/combobox.h b/muse2/muse/widgets/combobox.h index 305ad0b3..c099b3ce 100644 --- a/muse2/muse/widgets/combobox.h +++ b/muse2/muse/widgets/combobox.h @@ -8,36 +8,38 @@ #ifndef __COMBOBOX_H__ #define __COMBOBOX_H__ -#include <QLabel> +#include <QToolButton> class QMenu; +class QSignalMapper; //--------------------------------------------------------- // ComboBox //--------------------------------------------------------- -class ComboBox : public QLabel { +class ComboBox : public QToolButton { Q_OBJECT - Q_PROPERTY( int id READ id WRITE setId ) - int _id; int _currentItem; - QMenu* list; + QList<int> itemlist; + + QMenu* menu; virtual void mousePressEvent(QMouseEvent*); + virtual void wheelEvent(QWheelEvent*); + + QSignalMapper* autoTypeSignalMapper; private slots: - void activatedIntern(QAction*); + void activatedIntern(int id); signals: - void activated(int val, int id); + void activated(int id); public: - ComboBox(QWidget* parent, const char* name = 0); + ComboBox(QWidget* parent = 0, const char* name = 0); ~ComboBox(); void setCurrentItem(int); - void insertItem(const QString& s, int id = -1); - int id() const { return _id; } - void setId(int i) { _id = i; } + void addAction(const QString& s, int id = -1); }; #endif diff --git a/muse2/muse/widgets/knob.cpp b/muse2/muse/widgets/knob.cpp index ae88e2f4..dc41e1c4 100644 --- a/muse2/muse/widgets/knob.cpp +++ b/muse2/muse/widgets/knob.cpp @@ -64,6 +64,9 @@ Knob::Knob(QWidget* parent, const char* name) d_markerColor = palette().dark().color().darker(125); d_dotWidth = 8; + l_slope = 0; + l_const = 100; + setMinimumSize(30,30); setUpdateTime(50); } @@ -94,6 +97,31 @@ void Knob::setTotalAngle (double angle) } //------------------------------------------------------------ +// Knob::setRange +// Set the range and step size of the knob +// +// Sets the paramaters that define the shininess of the ring +// surrounding the knob and then proceeds by passing the +// parameters to the parent class' setRange() function. +//------------------------------------------------------------ + +void Knob::setRange(double vmin, double vmax, double vstep, int pagesize) + { + // divide by zero protection. probably too cautious + if (! (vmin == vmax || qMax(-vmin, vmax) == 0)) + { + if (vmin * vmax < 0) + l_slope = 80.0 / qMax(-vmin, vmax); + else + { + l_slope = 80.0 / (vmax - vmin); + l_const = 100 - l_slope * vmin; + } + } + SliderBase::setRange(vmin, vmax, vstep, pagesize); + } + +//------------------------------------------------------------ // QwtKnob::drawKnob // const QRect &r -- borders of the knob //------------------------------------------------------------ @@ -132,7 +160,8 @@ void Knob::drawKnob(QPainter* p, const QRect& r) QPen pn; pn.setCapStyle(Qt::FlatCap); - pn.setColor(d_shinyColor.lighter(100+ abs(d_angle*100)/300)); + + pn.setColor(d_shinyColor.lighter(l_const + abs(value() * l_slope))); pn.setWidth(d_shineWidth * 2); p->setPen(pn); p->drawArc(aRect, 0, 360 * 16); diff --git a/muse2/muse/widgets/knob.h b/muse2/muse/widgets/knob.h index 09e13c93..2a553c4e 100644 --- a/muse2/muse/widgets/knob.h +++ b/muse2/muse/widgets/knob.h @@ -36,6 +36,9 @@ class Knob : public SliderBase, public ScaleIf double d_totalAngle; double d_nTurns; + double l_const; + double l_slope; + QRect kRect; bool _faceColSel; QColor d_faceColor; @@ -62,6 +65,8 @@ class Knob : public SliderBase, public ScaleIf Knob(QWidget* parent = 0, const char *name = 0); ~Knob() {} + void setRange(double vmin, double vmax, double vstep = 0.0, + int pagesize = 1); void setKnobWidth(int w); void setTotalAngle (double angle); void setBorderWidth(int bw); diff --git a/muse2/muse/widgets/meter.cpp b/muse2/muse/widgets/meter.cpp index 6619d1dc..9f13059e 100644 --- a/muse2/muse/widgets/meter.cpp +++ b/muse2/muse/widgets/meter.cpp @@ -2,11 +2,11 @@ // MusE // Linux Music Editor // $Id: meter.cpp,v 1.4.2.2 2009/05/03 04:14:00 terminator356 Exp $ +// redesigned by oget on 2011/08/15 // // (C) Copyright 2000 Werner Schweer (ws@seh.de) //========================================================= -#include <stdio.h> #include <cmath> #include <QMouseEvent> @@ -30,7 +30,8 @@ Meter::Meter(QWidget* parent, MeterType type) // 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); - + //setFrameStyle(QFrame::Raised | QFrame::StyledPanel); + mtype = type; overflow = false; val = 0.0; @@ -41,6 +42,57 @@ Meter::Meter(QWidget* parent, MeterType type) redScale = 0; setLineWidth(0); setMidLineWidth(0); + + dark_red_end = QColor(0x8e0000); + dark_red_begin = QColor(0x8e3800); + + dark_yellow_end = QColor(0x8e6800); + dark_yellow_center = QColor(0x8e8e00); + dark_yellow_begin = QColor(0x6a8400); + + dark_green_end = QColor(0x467800); + dark_green_begin = QColor(0x007000); + + light_red_end = QColor(0xff0000); + light_red_begin = QColor(0xdd8800); + + light_yellow_end = QColor(0xddcc00); + light_yellow_center = QColor(0xffff00); + light_yellow_begin = QColor(0xddff00); + + light_green_end = QColor(0x88ff00); + light_green_begin = QColor(0x00ff00); + + mask_center = QColor(225, 225, 225, 64); + mask_edge = QColor(30, 30, 30, 64); + + separator_color = QColor(0x666666); + peak_color = QColor(0xeeeeee); + + darkGradGreen.setColorAt(1, dark_green_begin); + darkGradGreen.setColorAt(0, dark_green_end); + + darkGradYellow.setColorAt(1, dark_yellow_begin); + darkGradYellow.setColorAt(0.5, dark_yellow_center); + darkGradYellow.setColorAt(0, dark_yellow_end); + + darkGradRed.setColorAt(1, dark_red_begin); + darkGradRed.setColorAt(0, dark_red_end); + + lightGradGreen.setColorAt(1, light_green_begin); + lightGradGreen.setColorAt(0, light_green_end); + + lightGradYellow.setColorAt(1, light_yellow_begin); + lightGradYellow.setColorAt(0.5, light_yellow_center); + lightGradYellow.setColorAt(0, light_yellow_end); + + lightGradRed.setColorAt(1, light_red_begin); + lightGradRed.setColorAt(0, light_red_end); + + maskGrad.setColorAt(0, mask_edge); + maskGrad.setColorAt(0.5, mask_center); + maskGrad.setColorAt(1, mask_edge); + } //--------------------------------------------------------- @@ -106,17 +158,23 @@ void Meter::setRange(double min, double max) // paintEvent //--------------------------------------------------------- -void Meter::paintEvent(QPaintEvent* /*ev*/) +void Meter::paintEvent(QPaintEvent* ev) { // TODO: Could make better use of event rectangle, for speed. QPainter p(this); + //p.setRenderHint(QPainter::Antialiasing); double range = maxScale - minScale; - + /* int fw = frameWidth(); int w = width() - 2*fw; int h = height() - 2*fw; + */ + + QRect rect = ev->rect(); + int w = rect.width(); + int h = rect.height(); int yv; if(mtype == DBMeter) @@ -135,10 +193,17 @@ void Meter::paintEvent(QPaintEvent* /*ev*/) ymax = maxVal == 0 ? 0 : int(((maxScale - (fast_log10(maxVal) * 20.0)) * h)/range); else ymax = maxVal == 0 ? 0 : int(((maxScale - maxVal) * h)/range); - p.setPen(Qt::white); + p.setPen(peak_color); p.drawLine(0, ymax, w, ymax); + + // Draw the transparent layer on top of everything to give a 3d look + maskGrad.setStart(QPointF(0, 0)); + maskGrad.setFinalStop(QPointF(w, 0)); + p.fillRect(0, 0, w, h, QBrush(maskGrad)); + } + //--------------------------------------------------------- // drawVU //--------------------------------------------------------- @@ -150,60 +215,119 @@ void Meter::drawVU(QPainter& p, int w, int h, int yv) double range = maxScale - minScale; int y1 = int((maxScale - redScale) * h / range); int y2 = int((maxScale - yellowScale) * h / range); - + + darkGradGreen.setStart(QPointF(0, y2)); + darkGradGreen.setFinalStop(QPointF(0, h)); + darkGradYellow.setStart(QPointF(0, y1)); + darkGradYellow.setFinalStop(QPointF(0, y2)); + darkGradRed.setStart(QPointF(0, 0)); + darkGradRed.setFinalStop(QPointF(0, y1)); + + lightGradGreen.setStart(QPointF(0, y2)); + lightGradGreen.setFinalStop(QPointF(0, h)); + lightGradYellow.setStart(QPointF(0, y1)); + lightGradYellow.setFinalStop(QPointF(0, y2)); + lightGradRed.setStart(QPointF(0, 0)); + lightGradRed.setFinalStop(QPointF(0, y1)); + if(yv < y1) { // Red section: - p.fillRect(0, 0, w, yv, QBrush(0x8e0000)); // dark red - p.fillRect(0, yv, w, y1-yv, QBrush(0xff0000)); // light red + p.fillRect(0, 0, w, yv, QBrush(darkGradRed)); // dark red + p.fillRect(0, yv, w, y1-yv, QBrush(lightGradRed)); // light red // Yellow section: - p.fillRect(0, y1, w, y2-y1, QBrush(0xffff00)); // light yellow + p.fillRect(0, y1, w, y2-y1, QBrush(lightGradYellow)); // light yellow // Green section: - p.fillRect(0, y2, w, h-y2, QBrush(0x00ff00)); // light green + p.fillRect(0, y2, w, h-y2, QBrush(lightGradGreen)); // light green } else if(yv < y2) { // Red section: - p.fillRect(0, 0, w, y1, QBrush(0x8e0000)); // dark red + p.fillRect(0, 0, w, y1, QBrush(darkGradRed)); // dark red // Yellow section: - p.fillRect(0, y1, w, yv-y1, QBrush(0x8e8e00)); // dark yellow - p.fillRect(0, yv, w, y2-yv, QBrush(0xffff00)); // light yellow + p.fillRect(0, y1, w, yv-y1, QBrush(darkGradYellow)); // dark yellow + p.fillRect(0, yv, w, y2-yv, QBrush(lightGradYellow)); // light yellow // Green section: - p.fillRect(0, y2, w, h-y2, QBrush(0x00ff00)); // light green + p.fillRect(0, y2, w, h-y2, QBrush(lightGradGreen)); // light green } else //if(yv <= y3) { // Red section: - p.fillRect(0, 0, w, y1, QBrush(0x8e0000)); // dark red + p.fillRect(0, 0, w, y1, QBrush(darkGradRed)); // dark red // Yellow section: - p.fillRect(0, y1, w, y2-y1, QBrush(0x8e8e00)); // dark yellow + p.fillRect(0, y1, w, y2-y1, QBrush(darkGradYellow)); // dark yellow // Green section: - p.fillRect(0, y2, w, yv-y2, QBrush(0x007000)); // dark green - p.fillRect(0, yv, w, h-yv, QBrush(0x00ff00)); // light green + p.fillRect(0, y2, w, yv-y2, QBrush(darkGradGreen)); // dark green + p.fillRect(0, yv, w, h-yv, QBrush(lightGradGreen)); // light green } + + p.fillRect(0,y1, w, 1, separator_color); + p.fillRect(0,y2, w, 1, separator_color); + } else { - p.fillRect(0, 0, w, yv, QBrush(0x007000)); // dark green - p.fillRect(0, yv, w, h-yv, QBrush(0x00ff00)); // light green + darkGradGreen.setStart(QPointF(0, 0)); + darkGradGreen.setFinalStop(QPointF(0, h)); + + lightGradGreen.setStart(QPointF(0, 0)); + lightGradGreen.setFinalStop(QPointF(0, h)); + + p.fillRect(0, 0, w, yv, QBrush(darkGradGreen)); // dark green + p.fillRect(0, yv, w, h-yv, QBrush(lightGradGreen)); // light green } + } //--------------------------------------------------------- // resizeEvent //--------------------------------------------------------- -void Meter::resizeEvent(QResizeEvent* /*ev*/) +void Meter::resizeEvent(QResizeEvent* ev) { - + // Round corners of the widget. + + QSize size = ev->size(); + int w = size.width(); + int h = size.height(); + QPainterPath rounded_rect; + rounded_rect.addRoundedRect(0,0,w,h, w/2.5, w/3); + QRegion maskregion(rounded_rect.toFillPolygon().toPolygon()); + setMask(maskregion); + + /* + // Another method to do the above. I don't know yet which one is more efficient - Orcan + QRect rect(0,0,w,h); + int r = 6; + + QRegion region; + // middle and borders + region += rect.adjusted(r, 0, -r, 0); + region += rect.adjusted(0, r, 0, -r); + // top left + QRect corner(rect.topLeft(), QSize(r*2, r*2)); + region += QRegion(corner, QRegion::Ellipse); + // top right + corner.moveTopRight(rect.topRight()); + region += QRegion(corner, QRegion::Ellipse); + // bottom left + corner.moveBottomLeft(rect.bottomLeft()); + region += QRegion(corner, QRegion::Ellipse); + // bottom right + corner.moveBottomRight(rect.bottomRight()); + region += QRegion(corner, QRegion::Ellipse); + // return region; + setMask(region); + */ + } //--------------------------------------------------------- diff --git a/muse2/muse/widgets/meter.h b/muse2/muse/widgets/meter.h index cced6e7a..848ae855 100644 --- a/muse2/muse/widgets/meter.h +++ b/muse2/muse/widgets/meter.h @@ -2,6 +2,7 @@ // MusE // Linux Music Editor // $Id: meter.h,v 1.1.1.1.2.2 2009/05/03 04:14:00 terminator356 Exp $ +// redesigned by oget on 2011/08/15 // // (C) Copyright 2000 Werner Schweer (ws@seh.de) //========================================================= @@ -20,6 +21,41 @@ class Meter : public QFrame { Q_OBJECT public: enum MeterType {DBMeter, LinMeter}; + + protected: + QLinearGradient darkGradRed; + QColor dark_red_end; + QColor dark_red_begin; + + QLinearGradient darkGradYellow; + QColor dark_yellow_end; + QColor dark_yellow_center; + QColor dark_yellow_begin; + + QLinearGradient darkGradGreen; + QColor dark_green_end; + QColor dark_green_begin; + + QLinearGradient lightGradRed; + QColor light_red_end; + QColor light_red_begin; + + QLinearGradient lightGradYellow; + QColor light_yellow_end; + QColor light_yellow_center; + QColor light_yellow_begin; + + QLinearGradient lightGradGreen; + QColor light_green_end; + QColor light_green_begin; + + QLinearGradient maskGrad; + QColor mask_center; + QColor mask_edge; + + QColor separator_color;; + QColor peak_color; + private: MeterType mtype; bool overflow; @@ -30,7 +66,6 @@ class Meter : public QFrame { void drawVU(QPainter& p, int, int, int); - void paintEvent(QPaintEvent*); void resizeEvent(QResizeEvent*); void mousePressEvent(QMouseEvent*); diff --git a/muse2/muse/widgets/verticalmeter.cpp b/muse2/muse/widgets/verticalmeter.cpp index dbe50723..76f8dcd1 100644 --- a/muse2/muse/widgets/verticalmeter.cpp +++ b/muse2/muse/widgets/verticalmeter.cpp @@ -2,11 +2,11 @@ // MusE // Linux Music Editor // $Id: meter.cpp,v 1.4.2.2 2009/05/03 04:14:00 terminator356 Exp $ +// redesigned by oget on 2011/08/15 // // (C) Copyright 2000 Werner Schweer (ws@seh.de) //========================================================= -#include <stdio.h> #include <cmath> #include <QMouseEvent> @@ -107,7 +107,7 @@ void VerticalMeter::setRange(double min, double max) // paintEvent //--------------------------------------------------------- -void VerticalMeter::paintEvent(QPaintEvent* /*ev*/) +void VerticalMeter::paintEvent(QPaintEvent* ev) { // TODO: Could make better use of event rectangle, for speed. @@ -115,9 +115,15 @@ void VerticalMeter::paintEvent(QPaintEvent* /*ev*/) double range = maxScale - minScale; + /* int fw = frameWidth(); int w = width() - 2*fw; int h = height() - 2*fw; + */ + + QRect rect = ev->rect(); + int w = rect.width(); + int h = rect.height(); int xv; @@ -139,8 +145,13 @@ void VerticalMeter::paintEvent(QPaintEvent* /*ev*/) xcenter = maxVal == 0 ? 0 : int(((maxScale - (fast_log10(0) * 20.0)) * w)/range); else xcenter = maxVal == 0 ? 0 : int(((0) * w)/range); - p.setPen(Qt::white); + p.setPen(peak_color); p.drawLine(xcenter, 0, xcenter, h); + + // Draw the transparent layer on top of everything to give a 3d look + maskGrad.setStart(QPointF(0, 0)); + maskGrad.setFinalStop(QPointF(0, h)); + p.fillRect(0, 0, w, h, QBrush(maskGrad)); } //--------------------------------------------------------- @@ -154,58 +165,92 @@ void VerticalMeter::drawVU(QPainter& p, int w, int h, int xv) double range = maxScale - minScale; int x1 = int((maxScale - redScale) * w / range); int x2 = int((maxScale - yellowScale) * w / range); + + darkGradGreen.setStart(QPointF(x2, 0)); + darkGradGreen.setFinalStop(QPointF(w, 0)); + darkGradYellow.setStart(QPointF(x1, 0)); + darkGradYellow.setFinalStop(QPointF(x2, 0)); + darkGradRed.setStart(QPointF(0, 0)); + darkGradRed.setFinalStop(QPointF(x1, 0)); + + lightGradGreen.setStart(QPointF(x2, 0)); + lightGradGreen.setFinalStop(QPointF(w, 0)); + lightGradYellow.setStart(QPointF(x1, 0)); + lightGradYellow.setFinalStop(QPointF(x2, 0)); + lightGradRed.setStart(QPointF(0, 0)); + lightGradRed.setFinalStop(QPointF(x1, 0)); + if(xv < x1) { // Red section: - p.fillRect(0, 0, xv, h, QBrush(0x8e0000)); // dark red - p.fillRect(xv, 0, x1-xv, h, QBrush(0xff0000)); // light red + p.fillRect(0, 0, xv, h, QBrush(darkGradRed)); // dark red + p.fillRect(xv, 0, x1-xv, h, QBrush(lightGradRed)); // light red // Yellow section: - p.fillRect(x1, 0, x2-x1, h, QBrush(0xffff00)); // light yellow + p.fillRect(x1, 0, x2-x1, h, QBrush(lightGradYellow)); // light yellow // Green section: - p.fillRect(x2, 0, w-x2, h, QBrush(0x00ff00)); // light green + p.fillRect(x2, 0, w-x2, h, QBrush(lightGradGreen)); // light green } else if(xv < x2) { // Red section: - p.fillRect(0, 0, x1, h, QBrush(0x8e0000)); // dark red + p.fillRect(0, 0, x1, h, QBrush(darkGradRed)); // dark red // Yellow section: - p.fillRect(x1, 0, xv-x1, h, QBrush(0x8e8e00)); // dark yellow - p.fillRect(xv, 0, x2-xv, h, QBrush(0xffff00)); // light yellow + p.fillRect(x1, 0, xv-x1, h, QBrush(darkGradYellow)); // dark yellow + p.fillRect(xv, 0, x2-xv, h, QBrush(lightGradYellow)); // light yellow // Green section: - p.fillRect(x2, 0, w-x2, h, QBrush(0x00ff00)); // light green + p.fillRect(x2, 0, w-x2, h, QBrush(lightGradGreen)); // light green } else //if(yv <= y3) { // Red section: - p.fillRect(0, 0, x1, h, QBrush(0x8e0000)); // dark red + p.fillRect(0, 0, x1, h, QBrush(darkGradRed)); // dark red // Yellow section: - p.fillRect(x1, 0, x2-x1, h, QBrush(0x8e8e00)); // dark yellow + p.fillRect(x1, 0, x2-x1, h, QBrush(darkGradYellow)); // dark yellow // Green section: - p.fillRect(x2, 0, xv-x2, h, QBrush(0x007000)); // dark green - p.fillRect(xv, 0, w-xv, h, QBrush(0x00ff00)); // light green + p.fillRect(x2, 0, xv-x2, h, QBrush(darkGradGreen)); // dark green + p.fillRect(xv, 0, w-xv, h, QBrush(lightGradGreen)); // light green } + + p.fillRect(x1,0, 1, h, separator_color); + p.fillRect(x2,0, 1, h, separator_color); + } else { - p.fillRect(0, 0, xv, h, QBrush(0x00ff00)); // dark green - p.fillRect(xv, 0, w-xv, h, QBrush(0x007000)); // light green + darkGradGreen.setStart(QPointF(0, 0)); + darkGradGreen.setFinalStop(QPointF(w, 0)); + + lightGradGreen.setStart(QPointF(0, 0)); + lightGradGreen.setFinalStop(QPointF(w, 0)); + + p.fillRect(0, 0, xv, h, QBrush(lightGradGreen)); // light green + p.fillRect(xv, 0, w-xv, h, QBrush(darkGradGreen)); // dark green } + } //--------------------------------------------------------- // resizeEvent //--------------------------------------------------------- -void VerticalMeter::resizeEvent(QResizeEvent* /*ev*/) +void VerticalMeter::resizeEvent(QResizeEvent* ev) { + // Round corners of the widget. + QSize size = ev->size(); + int w = size.width(); + int h = size.height(); + QPainterPath rounded_rect; + rounded_rect.addRoundedRect(0,0,w,h, h/3, h/2.5); + QRegion maskregion(rounded_rect.toFillPolygon().toPolygon()); + setMask(maskregion); } diff --git a/muse2/muse/widgets/verticalmeter.h b/muse2/muse/widgets/verticalmeter.h index facc8b8c..9613ec43 100644 --- a/muse2/muse/widgets/verticalmeter.h +++ b/muse2/muse/widgets/verticalmeter.h @@ -9,9 +9,9 @@ #ifndef __VERTICALMETER_H__ #define __VERTICALMETER_H__ -#include <QFrame> #include "meter.h" +class QPaintEvent; class QResizeEvent; class QMouseEvent; class QPainter; diff --git a/muse2/muse/widgets/view.cpp b/muse2/muse/widgets/view.cpp index fb480527..57955c19 100644 --- a/muse2/muse/widgets/view.cpp +++ b/muse2/muse/widgets/view.cpp @@ -3,6 +3,7 @@ // Linux Music Editor // $Id: view.cpp,v 1.3.2.2 2009/04/06 01:24:55 terminator356 Exp $ // (C) Copyright 1999 Werner Schweer (ws@seh.de) +// Additions, modifications (C) Copyright 2011 Tim E. Real (terminator356 on users DOT sourceforge DOT net) //========================================================= #include "view.h" @@ -16,6 +17,10 @@ #include <QKeyEvent> #include <QPaintEvent> +#include "math.h" + +#include "al/sig.h" + // 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 @@ -491,26 +496,33 @@ void View::pdraw(QPainter& p, const QRect& r) int w = r.width(); int h = r.height(); if (xmag <= 0) { - x -= 1; + // TODO These adjustments are required, otherwise gaps. Tried, unable to remove them for now. p4.0.30 + x -= 1; w += 2; - x = (x + xpos + rmapx(xorg)) * (-xmag); + //x = (x + xpos + rmapx(xorg)) * (-xmag); + x = lrint((double(x + xpos) + rmapx_f(xorg)) * double(-xmag)); w = w * (-xmag); } else { - x = (x + xpos + rmapx(xorg)) / xmag; - w = (w + xmag - 1) / xmag; + //x = (x + xpos + rmapx(xorg)) / xmag; + x = lrint((double(x + xpos) + rmapx_f(xorg)) / double(xmag)); + //w = (w + xmag - 1) / xmag; + w = lrint(double(w) / double(xmag)); x -= 1; w += 2; } if (ymag <= 0) { y -= 1; h += 2; - y = (y + ypos + rmapy(yorg)) * (-ymag); + //y = (y + ypos + rmapy(yorg)) * (-ymag); + y = lrint((double(y + ypos) + rmapy_f(yorg)) * double(-ymag)); h = h * (-ymag); } else { - y = (y + ypos + rmapy(yorg)) / ymag; - h = (h + ymag - 1) / ymag; + //y = (y + ypos + rmapy(yorg)) / ymag; + y = lrint((double(y + ypos) + rmapy_f(yorg)) / double(ymag)); + //h = (h + ymag - 1) / ymag; + h = lrint(double(h) / double(ymag)); y -= 1; h += 2; } @@ -535,19 +547,116 @@ void View::setPainter(QPainter& p) p.resetMatrix(); // Q3 support says use resetMatrix instead, but resetMatrix advises resetTransform instead... //p.resetTransform(); - p.translate(double(-(xpos+rmapx(xorg))), double(-(ypos+rmapy(yorg)))); - double xMag = (xmag < 0) ? 1.0/(-xmag) : double(xmag); - double yMag = (ymag < 0) ? 1.0/(-ymag) : double(ymag); + //p.translate(double(-(xpos+rmapx(xorg))), double(-(ypos+rmapy(yorg)))); + p.translate( -(double(xpos) + rmapx_f(xorg)) , -(double(ypos) + rmapy(yorg))); + //double xMag = (xmag < 0) ? 1.0/(-xmag) : double(xmag); + //double yMag = (ymag < 0) ? 1.0/(-ymag) : double(ymag); + double xMag = (xmag < 0) ? 1.0/double(-xmag) : double(xmag); + double yMag = (ymag < 0) ? 1.0/double(-ymag) : double(ymag); p.scale(xMag, yMag); } //--------------------------------------------------------- +// drawTickRaster +//--------------------------------------------------------- + +void View::drawTickRaster(QPainter& p, int x, int y, int w, int h, int raster) + { + // Changed to draw in device coordinate space instead of virtual, transformed space. Tim. p4.0.30 + + //int mx = mapx(x); + int my = mapy(y); + //int mw = mapx(x + w) - mx; + //int mw = mapx(x + w) - mx - 1; + //int mh = mapy(y + h) - my; + //int mh = mapy(y + h) - my - 1; + + //p.save(); + bool wmtxen = p.worldMatrixEnabled(); + p.setWorldMatrixEnabled(false); + + int xx,bar1, bar2, beat; + unsigned tick; + AL::sigmap.tickValues(x, &bar1, &beat, &tick); + AL::sigmap.tickValues(x+w, &bar2, &beat, &tick); + ++bar2; + ///int y2 = y + h; + //int y2 = my + mh; + int y2 = mapy(y + h) - 1; + //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); + //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); + for (int bar = bar1; bar < bar2; ++bar) { + ///unsigned x = AL::sigmap.bar2tick(bar, 0, 0); + unsigned xb = AL::sigmap.bar2tick(bar, 0, 0); + int xt = mapx(xb); + p.setPen(Qt::black); + ///p.drawLine(x, y, x, y2); + p.drawLine(xt, my, xt, y2); + int z, n; + ///AL::sigmap.timesig(x, z, n); + AL::sigmap.timesig(xb, z, n); + ///int q = p.xForm(QPoint(raster, 0)).x() - p.xForm(QPoint(0, 0)).x(); + ///int q = p.combinedTransform().map(QPoint(raster, 0)).x() - p.combinedTransform().map(QPoint(0, 0)).x(); + //int q = rmapx(raster); + int qq = raster; + //if (q < 8) // grid too dense + if (rmapx(raster) < 8) // grid too dense + qq *= 2; + p.setPen(Qt::lightGray); + if (raster>=4) { + ///int xx = x + qq; + //int xx = mapx(xb + qq); + xx = xb + qq; + int xxx = AL::sigmap.bar2tick(bar, z, 0); + //int xxx = mapx(AL::sigmap.bar2tick(bar, z, 0)); + while (xx <= xxx) { + ///p.drawLine(xx, y, xx, y2); + int x = mapx(xx); + p.drawLine(x, my, x, y2); + xx += qq; + //xx += rmapx(qq); + } + //xx = xxx; + } + p.setPen(Qt::gray); + for (int beat = 1; beat < z; beat++) { + ///int xx = AL::sigmap.bar2tick(bar, beat, 0); + xx = mapx(AL::sigmap.bar2tick(bar, beat, 0)); + //printf(" bar:%d z:%d beat:%d xx:%d\n", bar, z, beat, xx); + ///p.drawLine(xx, y, xx, y2); + p.drawLine(xx, my, xx, y2); + } + + } + //p.setWorldMatrixEnabled(true); + p.setWorldMatrixEnabled(wmtxen); + //p.restore(); + } + +//--------------------------------------------------------- // map //--------------------------------------------------------- +QRect View::mapDev(const QRect& r) const + { + return QRect(mapxDev(r.x()), mapyDev(r.y()), + rmapxDev(r.width()), rmapyDev(r.height())); + } + +QPoint View::mapDev(const QPoint& r) const + { + return QPoint(mapxDev(r.x()), mapyDev(r.y())); + } + +#if 0 + // + // Calculations using integer rounding methods... + // + QRect View::map(const QRect& r) const { int x, y, w, h; + //printf("View::map xmag:%d xpos:%d xorg:%d\n", xmag, xpos, xorg); if (xmag < 0) { x = r.x()/(-xmag) - (xpos + rmapx(xorg)); // round down w = (r.width()-xmag-1) / (-xmag); // round up @@ -585,17 +694,6 @@ QPoint View::map(const QPoint& p) const return QPoint(x, y); } -QRect View::mapDev(const QRect& r) const - { - return QRect(mapxDev(r.x()), mapyDev(r.y()), - rmapxDev(r.width()), rmapyDev(r.height())); - } - -QPoint View::mapDev(const QPoint& r) const - { - return QPoint(mapxDev(r.x()), mapyDev(r.y())); - } - int View::mapx(int x) const { if (xmag < 0) { @@ -664,6 +762,166 @@ int View::rmapyDev(int y) const return (y + ymag/2) / ymag; } + +#else + // + // Calculations using more accurate methods... p4.0.29 Tim. + // + +QRect View::map(const QRect& r) const + { + //int x, y, w, h; + double x, y, w, h; + int xx, yy, ww, hh; + //printf("View::map xmag:%d xpos:%d xorg:%d\n", xmag, xpos, xorg); + if (xmag < 0) { + //x = lrint(double(r.x())/double(-xmag) - rmapx_f(xorg)) - xpos; + x = double(r.x())/double(-xmag) - rmapx_f(xorg) - xpos; + //w = lrint(double(r.width()) / double(-xmag)); + w = double(r.width()) / double(-xmag); + xx = lrint(x); + ww = lrint(x + w) - xx; + } + else { + xx = r.x()*xmag - xpos - lrint(rmapx_f(xorg)); + ww = r.width() * xmag; + } + if (ymag < 0) { + //y = lrint(double(r.y())/double(-ymag) - rmapy_f(yorg)) - ypos; + y = double(r.y())/double(-ymag) - rmapy_f(yorg) - ypos; + //h = lrint(double(r.height()) / double(-ymag)); + h = double(r.height()) / double(-ymag); + yy = lrint(y); + hh = lrint(y + h) - yy; + } + else { + yy = r.y()*ymag - ypos - lrint(rmapy_f(yorg)); + hh = r.height() * ymag; + } + return QRect(xx, yy, ww, hh); + } + +QPoint View::map(const QPoint& p) const + { + /* + int x, y; + if (xmag < 0) { + x = lrint(double(p.x())/double(-xmag) - rmapx_f(xorg)) - xpos; + } + else { + x = p.x()*xmag - xpos - lrint(rmapx_f(xorg)); + } + if (ymag < 0) { + y = lrint(double(p.y())/double(-ymag) - rmapy_f(yorg)) - ypos; + } + else { + y = p.y()*ymag - ypos - lrint(rmapy_f(yorg)); + } + return QPoint(x, y); + */ + return QPoint(mapx(p.x()), mapy(p.y())); + } + +int View::mapx(int x) const + { + if (xmag < 0) { + return lrint(double(x)/double(-xmag) - rmapx_f(xorg)) - xpos; + } + else { + return x*xmag - xpos - lrint(rmapx_f(xorg)); + } + } +int View::mapy(int y) const + { + if (ymag < 0) { + return lrint(double(y)/double(-ymag) - rmapy_f(yorg)) - ypos; + } + else { + return y*ymag - ypos - lrint(rmapy_f(yorg)); + } + } +int View::mapxDev(int x) const + { + int val; + if (xmag <= 0) + val = lrint((double(x + xpos) + rmapx_f(xorg)) * double(-xmag)); + else + val = lrint((double(x + xpos) + rmapx_f(xorg)) / double(xmag)); + if (val < 0) // DEBUG + val = 0; + return val; + } + +int View::mapyDev(int y) const + { + if (ymag <= 0) + return lrint((double(y + ypos) + rmapy_f(yorg)) * double(-ymag)); + else + return lrint((double(y + ypos) + rmapy_f(yorg)) / double(ymag)); + } + +// r == relative conversion +int View::rmapx(int x) const + { + if (xmag < 0) + return lrint(double(x) / double(-xmag)); + else + return x * xmag; + } +int View::rmapy(int y) const + { + if (ymag < 0) + return lrint(double(y) / double(-ymag)); + else + return y * ymag; + } +int View::rmapxDev(int x) const + { + if (xmag <= 0) + return x * (-xmag); + else + return lrint(double(x) / double(xmag)); + } +int View::rmapyDev(int y) const + { + if (ymag <= 0) + return y * (-ymag); + else + return lrint(double(y) / double(ymag)); + } +#endif + +double View::rmapx_f(double x) const + { + if (xmag < 0) + return x / double(-xmag); + else + return x * double(xmag); + } +double View::rmapy_f(double y) const + { + if (ymag < 0) + return y / double(-ymag); + else + return y * double(ymag); + } +double View::rmapxDev_f(double x) const + { + if (xmag <= 0) + return x * double(-xmag); + else + return x / double(xmag); + } +double View::rmapyDev_f(double y) const + { + if (ymag <= 0) + return y * double(-ymag); + else + return y / double(ymag); + } + + + /* QRect View::devToVirt(const QRect& r) { diff --git a/muse2/muse/widgets/view.h b/muse2/muse/widgets/view.h index f53c4c72..a932f173 100644 --- a/muse2/muse/widgets/view.h +++ b/muse2/muse/widgets/view.h @@ -3,6 +3,7 @@ // Linux Music Editor // $Id: view.h,v 1.2.2.1 2008/01/26 07:23:21 terminator356 Exp $ // (C) Copyright 1999 Werner Schweer (ws@seh.de) +// Additions, modifications (C) Copyright 2011 Tim E. Real (terminator356 on users DOT sourceforge DOT net) //========================================================= #ifndef __VIEW_H__ @@ -49,6 +50,7 @@ class View : public QWidget { virtual void draw(QPainter&, const QRect&) {} virtual void drawOverlay(QPainter&) {} virtual QRect overlayRect() const { return QRect(0, 0, 0, 0); } + virtual void drawTickRaster(QPainter& p, int x, int y, int w, int h, int raster); virtual void pdraw(QPainter&, const QRect&); @@ -77,6 +79,10 @@ class View : public QWidget { int rmapy(int y) const; int rmapyDev(int y) const; //QRect devToVirt(const QRect&); + double rmapx_f(double x) const; + double rmapy_f(double y) const; + double rmapxDev_f(double x) const; + double rmapyDev_f(double y) const; void setPainter(QPainter& p); |