From 5b6f4685475be7f7b68375fcab465c1626950296 Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Sat, 6 Feb 2021 12:26:54 +0100 Subject: [PATCH] statistics: don't place labels at half-integer values Placing labels at half-integer values gives horrible rendering artifacts. Therefore, always round to integer values. The easiest way to do this is right before setting the position. Introduce a helper function to round QPointF in such scenarios. Signed-off-by: Berthold Stoeger --- Subsurface-mobile.pro | 2 ++ stats/CMakeLists.txt | 2 ++ stats/barseries.cpp | 12 ++++++------ stats/pieseries.cpp | 7 ++++--- stats/statshelper.cpp | 10 ++++++++++ stats/statshelper.h | 6 +++++- stats/statsview.cpp | 4 ++-- 7 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 stats/statshelper.cpp diff --git a/Subsurface-mobile.pro b/Subsurface-mobile.pro index 8e35c835d..a67ab8e72 100644 --- a/Subsurface-mobile.pro +++ b/Subsurface-mobile.pro @@ -143,6 +143,7 @@ SOURCES += subsurface-mobile-main.cpp \ stats/statsaxis.cpp \ stats/statscolors.cpp \ stats/statsgrid.cpp \ + stats/statshelper.cpp \ stats/statsseries.cpp \ stats/statsstate.cpp \ mobile-widgets/qmlinterface.cpp \ @@ -295,6 +296,7 @@ HEADERS += \ stats/statsaxis.h \ stats/statscolors.h \ stats/statsgrid.h \ + stats/statshelper.h \ stats/statsseries.h \ stats/statsstate.h \ stats/statstranslations.h \ diff --git a/stats/CMakeLists.txt b/stats/CMakeLists.txt index daeb22146..1381797da 100644 --- a/stats/CMakeLists.txt +++ b/stats/CMakeLists.txt @@ -34,6 +34,8 @@ set(SUBSURFACE_STATS_SRCS statscolors.cpp statsgrid.h statsgrid.cpp + statshelper.h + statshelper.cpp statsseries.h statsseries.cpp statsstate.h diff --git a/stats/barseries.cpp b/stats/barseries.cpp index 766843703..252f05af6 100644 --- a/stats/barseries.cpp +++ b/stats/barseries.cpp @@ -118,7 +118,7 @@ void BarSeries::BarLabel::updatePosition(bool horizontal, bool center, const QRe return; } QPointF pos = rect.center(); - pos.rx() -= round(itemSize.width() / 2.0); + pos.rx() -= itemSize.width() / 2.0; // Heuristics: if the label fits nicely into the bar (bar height is at least twice the label height), // then put the label in the middle of the bar. Otherwise, put it at the top of the bar. @@ -130,29 +130,29 @@ void BarSeries::BarLabel::updatePosition(bool horizontal, bool center, const QRe setVisible(false); return; } - pos.ry() -= round(itemSize.height() / 2.0); + pos.ry() -= itemSize.height() / 2.0; } - item->setPos(pos); + item->setPos(roundPos(pos)); // Round to integer to avoid ugly artifacts. } else { if (itemSize.height() > rect.height()) { setVisible(false); return; } QPointF pos = rect.center(); - pos.ry() -= round(itemSize.height() / 2.0); + pos.ry() -= itemSize.height() / 2.0; // Heuristics: if the label fits nicely into the bar (bar width is at least twice the label height), // then put the label in the middle of the bar. Otherwise, put it to the right of the bar. isOutside = !center && rect.width() < 2.0 * itemSize.width(); if (isOutside) { - pos.rx() = round(rect.right() + 2.0); // Leave two pixels(?) space + pos.rx() = rect.right() + 2.0; // Leave two pixels(?) space } else { if (itemSize.width() > rect.width()) { setVisible(false); return; } } - item->setPos(pos); + item->setPos(roundPos(pos)); // Round to integer to avoid ugly artifacts. } setVisible(true); // If label changed from inside to outside, or vice-versa, the color might change. diff --git a/stats/pieseries.cpp b/stats/pieseries.cpp index 8db3bdbe3..d837abe5a 100644 --- a/stats/pieseries.cpp +++ b/stats/pieseries.cpp @@ -44,8 +44,9 @@ void PieSeries::Item::updatePositions(const QPointF ¢er, double radius) // because half-integer values gives horrible aliasing artifacts. if (innerLabel) { QRectF labelRect = innerLabel->getRect(); - innerLabel->setPos(QPointF(round(center.x() + innerLabelPos.x() * radius - labelRect.width() / 2.0), - round(center.y() + innerLabelPos.y() * radius - labelRect.height() / 2.0))); + QPointF pos(center.x() + innerLabelPos.x() * radius - labelRect.width() / 2.0, + center.y() + innerLabelPos.y() * radius - labelRect.height() / 2.0); + innerLabel->setPos(roundPos(pos)); } if (outerLabel) { QRectF labelRect = outerLabel->getRect(); @@ -59,7 +60,7 @@ void PieSeries::Item::updatePositions(const QPointF ¢er, double radius) pos.ry() -= labelRect.height(); } - outerLabel->setPos(QPointF(round(pos.x()), round(pos.y()))); + outerLabel->setPos(roundPos(pos)); } } diff --git a/stats/statshelper.cpp b/stats/statshelper.cpp new file mode 100644 index 000000000..d84ce20cf --- /dev/null +++ b/stats/statshelper.cpp @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "statshelper.h" + +#include + +QPointF roundPos(const QPointF &p) +{ + return QPointF(round(p.x()), round(p.y())); +} diff --git a/stats/statshelper.h b/stats/statshelper.h index 6b4a30ab5..45d58d022 100644 --- a/stats/statshelper.h +++ b/stats/statshelper.h @@ -1,12 +1,16 @@ // SPDX-License-Identifier: GPL-2.0 -// Helper functions to render the stats. Currently contains +// Helper functions to render the stats. Includes // QSGNode template jugglery to overcome API flaws. #ifndef STATSHELPER_H #define STATSHELPER_H #include +#include #include +// Round positions to integer values to avoid ugly artifacts +QPointF roundPos(const QPointF &p); + // A stupid pointer class that initializes to null and can be copy // assigned. This is for historical reasons: unique_ptrs to ChartItems // were replaced by plain pointers. Instead of nulling the plain pointers diff --git a/stats/statsview.cpp b/stats/statsview.cpp index 5514aa35d..eec7b4ba5 100644 --- a/stats/statsview.cpp +++ b/stats/statsview.cpp @@ -397,8 +397,8 @@ void StatsView::updateTitlePos() { if (!title) return; - title->setPos(QPointF(round(sceneBorder + (boundingRect().width() - title->getRect().width()) / 2.0), - round(sceneBorder))); + QPointF pos(sceneBorder + (boundingRect().width() - title->getRect().width()) / 2.0, sceneBorder); + title->setPos(roundPos(pos)); } template