diff --git a/src/gui/properties/pieceavailabilitybar.cpp b/src/gui/properties/pieceavailabilitybar.cpp index f6e4e53f9..0b968ea15 100644 --- a/src/gui/properties/pieceavailabilitybar.cpp +++ b/src/gui/properties/pieceavailabilitybar.cpp @@ -29,207 +29,202 @@ */ #include +#include #include "pieceavailabilitybar.h" -PieceAvailabilityBar::PieceAvailabilityBar(QWidget *parent) : - QWidget(parent) + +PieceAvailabilityBar::PieceAvailabilityBar(QWidget *parent) + : QWidget(parent) { - setFixedHeight(BAR_HEIGHT); + setFixedHeight(BAR_HEIGHT); - m_bgColor = 0xffffff; - m_borderColor = palette().color(QPalette::Dark).rgb(); - m_pieceColor = 0x0000ff; + m_bgColor = 0xffffff; + m_borderColor = palette().color(QPalette::Dark).rgb(); + m_pieceColor = 0x0000ff; - updatePieceColors(); + updatePieceColors(); } QVector PieceAvailabilityBar::intToFloatVector(const QVector &vecin, int reqSize) { - QVector result(reqSize, 0.0); - if (vecin.isEmpty()) return result; - - const float ratio = vecin.size() / (float)reqSize; + QVector result(reqSize, 0.0); + if (vecin.isEmpty()) return result; - const int maxElement = *std::max_element(vecin.begin(), vecin.end()); + const float ratio = vecin.size() / (float)reqSize; - // qMax because in normalization we don't want divide by 0 - // if maxElement == 0 check will be disabled please enable this line: - // const int maxElement = qMax(*std::max_element(avail.begin(), avail.end()), 1); + const int maxElement = *std::max_element(vecin.begin(), vecin.end()); - if (maxElement == 0) - return result; + // qMax because in normalization we don't want divide by 0 + // if maxElement == 0 check will be disabled please enable this line: + // const int maxElement = qMax(*std::max_element(avail.begin(), avail.end()), 1); - // simple linear transformation algorithm - // for example: - // image.x(0) = pieces.x(0.0 >= x < 1.7) - // image.x(1) = pieces.x(1.7 >= x < 3.4) + if (maxElement == 0) + return result; - for (int x = 0; x < reqSize; ++x) { + // simple linear transformation algorithm + // for example: + // image.x(0) = pieces.x(0.0 >= x < 1.7) + // image.x(1) = pieces.x(1.7 >= x < 3.4) - // don't use previously calculated value "ratio" here!!! - // float cannot save irrational number like 7/9, if this number will be rounded up by std::ceil - // give you x2 == pieces.size(), and index out of range: pieces[x2] - // this code is safe, so keep that in mind when you try optimize more. - // tested with size = 3000000ul + for (int x = 0; x < reqSize; ++x) { + // don't use previously calculated value "ratio" here!!! + // float cannot save irrational number like 7/9, if this number will be rounded up by std::ceil + // give you x2 == pieces.size(), and index out of range: pieces[x2] + // this code is safe, so keep that in mind when you try optimize more. + // tested with size = 3000000ul - // R - real - const float fromR = (x * vecin.size()) / (float)reqSize; - const float toR = ((x + 1) * vecin.size()) / (float)reqSize; + // R - real + const float fromR = (x * vecin.size()) / (float)reqSize; + const float toR = ((x + 1) * vecin.size()) / (float)reqSize; - // C - integer - int fromC = fromR;// std::floor not needed - int toC = std::ceil(toR); + // C - integer + int fromC = fromR;// std::floor not needed + int toC = std::ceil(toR); - // position in pieces table - // libtorrent::bitfield::m_size is unsigned int(31 bits), so qlonglong is not needed - // tested with size = 3000000ul - int x2 = fromC; + // position in pieces table + // libtorrent::bitfield::m_size is unsigned int(31 bits), so qlonglong is not needed + // tested with size = 3000000ul + int x2 = fromC; - // little speed up for really big pieces table, 10K+ size - const int toCMinusOne = toC - 1; + // little speed up for really big pieces table, 10K+ size + const int toCMinusOne = toC - 1; - // value in returned vector - float value = 0; + // value in returned vector + float value = 0; - // case when calculated range is (15.2 >= x < 15.7) - if (x2 == toCMinusOne) { - if (vecin[x2]) { - value += (toR - fromR) * vecin[x2]; - } - ++x2; - } - // case when (15.2 >= x < 17.8) - else { - // subcase (15.2 >= x < 16) - if (x2 != fromR) { - if (vecin[x2]) { - value += (1.0 - (fromR - fromC)) * vecin[x2]; + // case when calculated range is (15.2 >= x < 15.7) + if (x2 == toCMinusOne) { + if (vecin[x2]) + value += (toR - fromR) * vecin[x2]; + ++x2; } - ++x2; - } - - // subcase (16 >= x < 17) - for (; x2 < toCMinusOne; ++x2) { - if (vecin[x2]) { - value += vecin[x2]; + // case when (15.2 >= x < 17.8) + else { + // subcase (15.2 >= x < 16) + if (x2 != fromR) { + if (vecin[x2]) + value += (1.0 - (fromR - fromC)) * vecin[x2]; + ++x2; + } + + // subcase (16 >= x < 17) + for (; x2 < toCMinusOne; ++x2) + if (vecin[x2]) + value += vecin[x2]; + + // subcase (17 >= x < 17.8) + if (x2 == toCMinusOne) { + if (vecin[x2]) + value += (1.0 - (toC - toR)) * vecin[x2]; + ++x2; + } } - } - // subcase (17 >= x < 17.8) - if (x2 == toCMinusOne) { - if (vecin[x2]) { - value += (1.0 - (toC - toR)) * vecin[x2]; - } - ++x2; - } - } - - // normalization <0, 1> - value /= ratio * maxElement; + // normalization <0, 1> + value /= ratio * maxElement; - // float precision sometimes gives > 1, because in not possible to store irrational numbers - value = qMin(value, (float)1.0); + // float precision sometimes gives > 1, because in not possible to store irrational numbers + value = qMin(value, (float)1.0); - result[x] = value; - } + result[x] = value; + } - return result; + return result; } int PieceAvailabilityBar::mixTwoColors(int &rgb1, int &rgb2, float ratio) { - int r1 = qRed(rgb1); - int g1 = qGreen(rgb1); - int b1 = qBlue(rgb1); + int r1 = qRed(rgb1); + int g1 = qGreen(rgb1); + int b1 = qBlue(rgb1); - int r2 = qRed(rgb2); - int g2 = qGreen(rgb2); - int b2 = qBlue(rgb2); + int r2 = qRed(rgb2); + int g2 = qGreen(rgb2); + int b2 = qBlue(rgb2); - float ratio_n = 1.0 - ratio; - int r = (r1 * ratio_n) + (r2 * ratio); - int g = (g1 * ratio_n) + (g2 * ratio); - int b = (b1 * ratio_n) + (b2 * ratio); + float ratio_n = 1.0 - ratio; + int r = (r1 * ratio_n) + (r2 * ratio); + int g = (g1 * ratio_n) + (g2 * ratio); + int b = (b1 * ratio_n) + (b2 * ratio); - return qRgb(r, g, b); + return qRgb(r, g, b); } void PieceAvailabilityBar::updateImage() { - // qDebug() << "updateImageAv"; - QImage image2(width() - 2, 1, QImage::Format_RGB888); + QImage image2(width() - 2, 1, QImage::Format_RGB888); + if (image2.isNull()) { + qDebug() << "QImage image2() allocation failed, width():" << width(); + return; + } + + if (m_pieces.empty()) { + image2.fill(0xffffff); + m_image = image2; + update(); + return; + } + + QVector scaled_pieces = intToFloatVector(m_pieces, image2.width()); - if (m_pieces.empty()) { - image2.fill(0xffffff); + // filling image + for (int x = 0; x < scaled_pieces.size(); ++x) { + float pieces2_val = scaled_pieces.at(x); + image2.setPixel(x, 0, m_pieceColors[pieces2_val * 255]); + } m_image = image2; - update(); - return; - } - - QVector scaled_pieces = intToFloatVector(m_pieces, image2.width()); - - // filling image - for (int x = 0; x < scaled_pieces.size(); ++x) - { - float pieces2_val = scaled_pieces.at(x); - image2.setPixel(x, 0, m_pieceColors[pieces2_val * 255]); - } - m_image = image2; } void PieceAvailabilityBar::setAvailability(const QVector &avail) { - m_pieces = avail; + m_pieces = avail; - updateImage(); - update(); + updateImage(); + update(); } void PieceAvailabilityBar::updatePieceColors() { - m_pieceColors = QVector(256); - for (int i = 0; i < 256; ++i) { - float ratio = (i / 255.0); - m_pieceColors[i] = mixTwoColors(m_bgColor, m_pieceColor, ratio); - } + m_pieceColors = QVector(256); + for (int i = 0; i < 256; ++i) { + float ratio = (i / 255.0); + m_pieceColors[i] = mixTwoColors(m_bgColor, m_pieceColor, ratio); + } } void PieceAvailabilityBar::clear() { - m_image = QImage(); - update(); + m_image = QImage(); + update(); } void PieceAvailabilityBar::paintEvent(QPaintEvent *) { - QPainter painter(this); - QRect imageRect(1, 1, width() - 2, height() - 2); - if (m_image.isNull()) - { - painter.setBrush(Qt::white); - painter.drawRect(imageRect); - } - else - { - if (m_image.width() != imageRect.width()) - updateImage(); - painter.drawImage(imageRect, m_image); - } - QPainterPath border; - border.addRect(0, 0, width() - 1, height() - 1); - - painter.setPen(m_borderColor); - painter.drawPath(border); + QPainter painter(this); + QRect imageRect(1, 1, width() - 2, height() - 2); + if (m_image.isNull()) { + painter.setBrush(Qt::white); + painter.drawRect(imageRect); + } + else { + if (m_image.width() != imageRect.width()) + updateImage(); + painter.drawImage(imageRect, m_image); + } + QPainterPath border; + border.addRect(0, 0, width() - 1, height() - 1); + + painter.setPen(m_borderColor); + painter.drawPath(border); } void PieceAvailabilityBar::setColors(int background, int border, int available) { - m_bgColor = background; - m_borderColor = border; - m_pieceColor = available; + m_bgColor = background; + m_borderColor = border; + m_pieceColor = available; - updatePieceColors(); - updateImage(); - update(); + updatePieceColors(); + updateImage(); + update(); } - diff --git a/src/gui/properties/pieceavailabilitybar.h b/src/gui/properties/pieceavailabilitybar.h index af672cdad..52e78dc3f 100644 --- a/src/gui/properties/pieceavailabilitybar.h +++ b/src/gui/properties/pieceavailabilitybar.h @@ -37,48 +37,49 @@ #define BAR_HEIGHT 18 -class PieceAvailabilityBar: public QWidget { - Q_OBJECT - Q_DISABLE_COPY(PieceAvailabilityBar) + +class PieceAvailabilityBar: public QWidget +{ + Q_OBJECT + Q_DISABLE_COPY(PieceAvailabilityBar) private: - QImage m_image; + QImage m_image; - // I used values, because it should be possible to change colors in runtime + // I used values, because it should be possible to change colors in runtime - // background color - int m_bgColor; - // border color - int m_borderColor; - // complete piece color - int m_pieceColor; - // buffered 256 levels gradient from bg_color to piece_color - QVector m_pieceColors; + // background color + int m_bgColor; + // border color + int m_borderColor; + // complete piece color + int m_pieceColor; + // buffered 256 levels gradient from bg_color to piece_color + QVector m_pieceColors; - // last used int vector, uses to better resize redraw - // TODO: make a diff pieces to new pieces and update only changed pixels, speedup when update > 20x faster - QVector m_pieces; + // last used int vector, uses to better resize redraw + // TODO: make a diff pieces to new pieces and update only changed pixels, speedup when update > 20x faster + QVector m_pieces; - // scale int vector to float vector - QVector intToFloatVector(const QVector &vecin, int reqSize); + // scale int vector to float vector + QVector intToFloatVector(const QVector &vecin, int reqSize); - // mix two colors by light model, ratio <0, 1> - int mixTwoColors(int &rgb1, int &rgb2, float ratio); - // draw new image and replace actual image - void updateImage(); + // mix two colors by light model, ratio <0, 1> + int mixTwoColors(int &rgb1, int &rgb2, float ratio); + // draw new image and replace actual image + void updateImage(); public: - PieceAvailabilityBar(QWidget *parent); + PieceAvailabilityBar(QWidget *parent); - void setAvailability(const QVector &avail); - void updatePieceColors(); - void clear(); + void setAvailability(const QVector &avail); + void updatePieceColors(); + void clear(); - void setColors(int background, int border, int available); + void setColors(int background, int border, int available); protected: - void paintEvent(QPaintEvent *); - + void paintEvent(QPaintEvent *); }; #endif // PIECEAVAILABILITYBAR_H