summaryrefslogtreecommitdiffstats
path: root/src/datavisualization/utils/utils.cpp
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@theqtcompany.com>2014-10-29 09:45:41 +0200
committerMiikka Heikkinen <miikka.heikkinen@theqtcompany.com>2014-10-29 09:45:41 +0200
commite3a4f132ca2a42af3d4bb889d6a17948b88d26a2 (patch)
tree554d2b8b3020dc71438301aa696dea1e9a36943a /src/datavisualization/utils/utils.cpp
parentcc50608385cf77a0803431ece1385f341a400b75 (diff)
parentbf716cfdf0afecccdb1f2eabb2e6a172c620fbff (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.cpp252
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