diff options
author | Miikka Heikkinen <miikka.heikkinen@theqtcompany.com> | 2014-10-29 09:45:41 +0200 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@theqtcompany.com> | 2014-10-29 09:45:41 +0200 |
commit | e3a4f132ca2a42af3d4bb889d6a17948b88d26a2 (patch) | |
tree | 554d2b8b3020dc71438301aa696dea1e9a36943a /src/datavisualization/utils/utils.cpp | |
parent | cc50608385cf77a0803431ece1385f341a400b75 (diff) | |
parent | bf716cfdf0afecccdb1f2eabb2e6a172c620fbff (diff) |
Merge branch 'develop'
Conflicts:
.qmake.conf
README
src/datavisualization/global/qdatavisualizationglobal.h
Change-Id: Ia6941dcf3e6aa17e2e9ebc6f60fac16ef5049f11
Diffstat (limited to 'src/datavisualization/utils/utils.cpp')
-rw-r--r-- | src/datavisualization/utils/utils.cpp | 252 |
1 files changed, 182 insertions, 70 deletions
diff --git a/src/datavisualization/utils/utils.cpp b/src/datavisualization/utils/utils.cpp index 2368d86a..cb64eb8f 100644 --- a/src/datavisualization/utils/utils.cpp +++ b/src/datavisualization/utils/utils.cpp @@ -17,6 +17,7 @@ ****************************************************************************/ #include "utils_p.h" +#include "qutils.h" #include <QtGui/QPainter> @@ -25,11 +26,12 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION #define NUM_IN_POWER(y, x) for (;y<x;y<<=1) #define MIN_POWER 2 -GLuint Utils::getNearestPowerOfTwo(GLuint value, GLuint &padding) +static GLint maxTextureSize = 0; // Safe, as all instances have the same texture size + +GLuint Utils::getNearestPowerOfTwo(GLuint value) { GLuint powOfTwoValue = MIN_POWER; NUM_IN_POWER(powOfTwoValue, value); - padding = powOfTwoValue - value; return powOfTwoValue; } @@ -54,35 +56,76 @@ QImage Utils::printTextToImage(const QFont &font, const QString &text, const QCo const QColor &txtColor, bool labelBackground, bool borders, int maxLabelWidth) { + if (maxTextureSize == 0) { + QOpenGLContext::currentContext()->functions()->glGetIntegerv( + GL_MAX_TEXTURE_SIZE, &maxTextureSize); + } GLuint paddingWidth = 20; GLuint paddingHeight = 20; + GLuint prePadding = 20; + GLint targetWidth = maxTextureSize; + // Calculate text dimensions QFont valueFont = font; valueFont.setPointSize(textureFontSize); QFontMetrics valueFM(valueFont); int valueStrWidth = valueFM.width(text); - if (maxLabelWidth && labelBackground) + + // ES2 needs to use maxLabelWidth always (when given) because of the power of 2 -issue. + if (maxLabelWidth && (labelBackground || Utils::isOpenGLES())) valueStrWidth = maxLabelWidth; int valueStrHeight = valueFM.height(); valueStrWidth += paddingWidth / 2; // Fix clipping problem with skewed fonts (italic or italic-style) QSize labelSize; + qreal fontRatio = 1.0; -#if defined(QT_OPENGL_ES_2) - // ES2 can't handle textures with dimensions not in power of 2. Resize labels accordingly. - // Add some padding before converting to power of two to avoid too tight fit - GLuint prePadding = 5; - // ES2 needs to use this always (when given) because of the power of 2 -issue. - if (maxLabelWidth) - valueStrWidth = maxLabelWidth + paddingWidth / 2; - labelSize = QSize(valueStrWidth + prePadding, valueStrHeight + prePadding); - labelSize.setWidth(getNearestPowerOfTwo(labelSize.width(), paddingWidth)); - labelSize.setHeight(getNearestPowerOfTwo(labelSize.height(), paddingHeight)); -#else - if (!labelBackground) - labelSize = QSize(valueStrWidth, valueStrHeight); - else - labelSize = QSize(valueStrWidth + paddingWidth * 2, valueStrHeight + paddingHeight * 2); -#endif + if (Utils::isOpenGLES()) { + // Test if text with slighly smaller font would fit into one step smaller texture + // ie. if the text is just exceeded the smaller texture boundary, it would + // make a label with large empty space + uint testWidth = getNearestPowerOfTwo(valueStrWidth + prePadding) >> 1; + int diffToFit = (valueStrWidth + prePadding) - testWidth; + int maxSqueeze = int((valueStrWidth + prePadding) * 0.1f); + if (diffToFit < maxSqueeze && maxTextureSize > GLint(testWidth)) + targetWidth = testWidth; + } + + bool sizeOk = false; + int currentFontSize = textureFontSize; + do { + if (Utils::isOpenGLES()) { + // ES2 can't handle textures with dimensions not in power of 2. Resize labels accordingly. + // Add some padding before converting to power of two to avoid too tight fit + labelSize = QSize(valueStrWidth + prePadding, valueStrHeight + prePadding); + labelSize.setWidth(getNearestPowerOfTwo(labelSize.width())); + labelSize.setHeight(getNearestPowerOfTwo(labelSize.height())); + } else { + if (!labelBackground) + labelSize = QSize(valueStrWidth, valueStrHeight); + else + labelSize = QSize(valueStrWidth + paddingWidth * 2, valueStrHeight + paddingHeight * 2); + } + + if (!maxTextureSize || (labelSize.width() <= maxTextureSize + && (labelSize.width() <= targetWidth || !Utils::isOpenGLES()))) { + // Make sure the label is not too wide + sizeOk = true; + } else if (--currentFontSize == 4) { + qCritical() << "Label" << text << "is too long to be generated."; + return QImage(); + } else { + fontRatio = (qreal)currentFontSize / (qreal)textureFontSize; + // Reduce font size and try again + valueFont.setPointSize(currentFontSize); + QFontMetrics currentValueFM(valueFont); + if (maxLabelWidth && (labelBackground || Utils::isOpenGLES())) + valueStrWidth = maxLabelWidth * fontRatio; + else + valueStrWidth = currentValueFM.width(text); + valueStrHeight = currentValueFM.height(); + valueStrWidth += paddingWidth / 2; + } + } while (!sizeOk); // Create image QImage image = QImage(labelSize, QImage::Format_ARGB32); @@ -96,27 +139,30 @@ QImage Utils::printTextToImage(const QFont &font, const QString &text, const QCo painter.setFont(valueFont); if (!labelBackground) { painter.setPen(txtColor); -#if defined(QT_OPENGL_ES_2) - painter.drawText((labelSize.width() - valueStrWidth) / 2.0f, - (labelSize.height() - valueStrHeight) / 2.0f, - valueStrWidth, valueStrHeight, - Qt::AlignCenter | Qt::AlignVCenter, - text); -#else - painter.drawText(0, 0, - valueStrWidth, valueStrHeight, - Qt::AlignCenter | Qt::AlignVCenter, - text); -#endif + if (Utils::isOpenGLES()) { + painter.drawText((labelSize.width() - valueStrWidth) / 2.0f, + (labelSize.height() - valueStrHeight) / 2.0f, + valueStrWidth, valueStrHeight, + Qt::AlignCenter | Qt::AlignVCenter, + text); + } else { + painter.drawText(0, 0, + valueStrWidth, valueStrHeight, + Qt::AlignCenter | Qt::AlignVCenter, + text); + } } else { painter.setBrush(QBrush(bgrColor)); + qreal radius = 10.0 * fontRatio; if (borders) { - painter.setPen(QPen(QBrush(txtColor), 5, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin)); - painter.drawRoundedRect(5, 5, labelSize.width() - 10, labelSize.height() - 10, - 10.0, 10.0); + painter.setPen(QPen(QBrush(txtColor), 5.0 * fontRatio, + Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin)); + painter.drawRoundedRect(5, 5, + labelSize.width() - 10, labelSize.height() - 10, + radius, radius); } else { painter.setPen(bgrColor); - painter.drawRoundedRect(0, 0, labelSize.width(), labelSize.height(), 10.0, 10.0); + painter.drawRoundedRect(0, 0, labelSize.width(), labelSize.height(), radius, radius); } painter.setPen(txtColor); painter.drawText((labelSize.width() - valueStrWidth) / 2.0f, @@ -133,62 +179,74 @@ QVector4D Utils::getSelection(QPoint mousepos, int height) // This is the only one that works with OpenGL ES 2.0, so we're forced to use it // Item count will be limited to 256*256*256 GLubyte pixel[4] = {255, 255, 255, 255}; - glReadPixels(mousepos.x(), height - mousepos.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, - (void *)pixel); + QOpenGLContext::currentContext()->functions()->glReadPixels(mousepos.x(), height - mousepos.y(), + 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, + (void *)pixel); QVector4D selectedColor(pixel[0], pixel[1], pixel[2], pixel[3]); return selectedColor; } -QImage Utils::getGradientImage(const QLinearGradient &gradient) +QImage Utils::getGradientImage(QLinearGradient &gradient) { - QImage image(QSize(1, 101), QImage::Format_RGB32); + QImage image(QSize(gradientTextureWidth, gradientTextureHeight), QImage::Format_RGB32); + gradient.setFinalStop(qreal(gradientTextureWidth), qreal(gradientTextureHeight)); + gradient.setStart(0.0, 0.0); + QPainter pmp(&image); pmp.setBrush(QBrush(gradient)); pmp.setPen(Qt::NoPen); - pmp.drawRect(0, 0, 1, 101); + pmp.drawRect(0, 0, int(gradientTextureWidth), int(gradientTextureHeight)); return image; } -Utils::ParamType Utils::mapFormatCharToParamType(const QChar &formatChar) +Utils::ParamType Utils::preParseFormat(const QString &format, QString &preStr, QString &postStr, + int &precision, char &formatSpec) { - ParamType retVal = ParamTypeUnknown; - if (formatChar == QLatin1Char('d') - || formatChar == QLatin1Char('i') - || formatChar == QLatin1Char('c')) { - retVal = ParamTypeInt; - } else if (formatChar == QLatin1Char('u') - || formatChar == QLatin1Char('o') - || formatChar == QLatin1Char('x') - || formatChar == QLatin1Char('X')) { - retVal = ParamTypeUInt; - } else if (formatChar == QLatin1Char('f') - || formatChar == QLatin1Char('F') - || formatChar == QLatin1Char('e') - || formatChar == QLatin1Char('E') - || formatChar == QLatin1Char('g') - || formatChar == QLatin1Char('G')) { - retVal = ParamTypeReal; + static QRegExp formatMatcher(QStringLiteral("^([^%]*)%([\\-\\+#\\s\\d\\.lhjztL]*)([dicuoxfegXFEG])(.*)$")); + static QRegExp precisionMatcher(QStringLiteral("\\.(\\d+)")); + + Utils::ParamType retVal; + + if (formatMatcher.indexIn(format, 0) != -1) { + preStr = formatMatcher.cap(1); + // Six and 'g' are defaults in Qt API + precision = 6; + if (!formatMatcher.cap(2).isEmpty()) { + if (precisionMatcher.indexIn(formatMatcher.cap(2), 0) != -1) + precision = precisionMatcher.cap(1).toInt(); + } + if (formatMatcher.cap(3).isEmpty()) + formatSpec = 'g'; + else + formatSpec = formatMatcher.cap(3).at(0).toLatin1(); + postStr = formatMatcher.cap(4); + retVal = mapFormatCharToParamType(formatSpec); + } else { + retVal = ParamTypeUnknown; + // The out parameters are irrelevant in unknown case } return retVal; } -Utils::ParamType Utils::findFormatParamType(const QString &format) +Utils::ParamType Utils::mapFormatCharToParamType(char formatSpec) { - static QRegExp formatMatcher(QStringLiteral("%[\\-\\+#\\s\\d\\.lhjztL]*([dicuoxfegXFEG])")); - - if (formatMatcher.indexIn(format, 0) != -1) { - QString capStr = formatMatcher.cap(1); - if (capStr.isEmpty()) - return ParamTypeUnknown; - else - return mapFormatCharToParamType(capStr.at(0)); + ParamType retVal = ParamTypeUnknown; + if (formatSpec == 'd' || formatSpec == 'i' || formatSpec == 'c') { + retVal = ParamTypeInt; + } else if (formatSpec == 'u' || formatSpec == 'o' + || formatSpec == 'x'|| formatSpec == 'X') { + retVal = ParamTypeUInt; + } else if (formatSpec == 'f' || formatSpec == 'F' + || formatSpec == 'e' || formatSpec == 'E' + || formatSpec == 'g' || formatSpec == 'G') { + retVal = ParamTypeReal; } - return ParamTypeUnknown; + return retVal; } -QString Utils::formatLabel(const QByteArray &format, ParamType paramType, qreal value) +QString Utils::formatLabelSprintf(const QByteArray &format, Utils::ParamType paramType, qreal value) { switch (paramType) { case ParamTypeInt: @@ -198,7 +256,24 @@ QString Utils::formatLabel(const QByteArray &format, ParamType paramType, qreal case ParamTypeReal: return QString().sprintf(format, value); default: - return QString::fromUtf8(format); // To detect errors + // Return format string to detect errors. Bars selection label logic also depends on this. + return QString::fromUtf8(format); + } +} + +QString Utils::formatLabelLocalized(Utils::ParamType paramType, qreal value, + const QLocale &locale, const QString &preStr, const QString &postStr, + int precision, char formatSpec, const QByteArray &format) +{ + switch (paramType) { + case ParamTypeInt: + case ParamTypeUInt: + return preStr + locale.toString(qint64(value)) + postStr; + case ParamTypeReal: + return preStr + locale.toString(value, formatSpec, precision) + postStr; + default: + // Return format string to detect errors. Bars selection label logic also depends on this. + return QString::fromUtf8(format); } } @@ -238,4 +313,41 @@ QQuaternion Utils::calculateRotation(const QVector3D &xyzRotations) return totalRotation; } +bool Utils::isOpenGLES() +{ +#if defined(QT_OPENGL_ES_2) + return true; +#elif (QT_VERSION < QT_VERSION_CHECK(5, 3, 0)) + return false; +#else + static bool resolved = false; + static bool isES = false; + if (!resolved) { + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QWindow *dummySurface = 0; + if (!ctx) { + QSurfaceFormat surfaceFormat = qDefaultSurfaceFormat(); + dummySurface = new QWindow(); + dummySurface->setSurfaceType(QWindow::OpenGLSurface); + dummySurface->setFormat(surfaceFormat); + dummySurface->create(); + ctx = new QOpenGLContext; + ctx->setFormat(surfaceFormat); + ctx->create(); + ctx->makeCurrent(dummySurface); + } + + isES = ctx->isOpenGLES(); + resolved = true; + + if (dummySurface) { + ctx->doneCurrent(); + delete ctx; + delete dummySurface; + } + } + return isES; +#endif +} + QT_END_NAMESPACE_DATAVISUALIZATION |