mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
statistics: turn infobox into a QSGNode
A small step in converting from QGraphicsScene to QQuickItem. This is the second item to be converted (after the legend) and for now items are drawn in order of creation, which means that the infobox is on top of the legend. This will have to be made deterministic in follow-up commits. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
d7878dad36
commit
785d5189f6
8 changed files with 53 additions and 58 deletions
|
@ -4,6 +4,7 @@
|
||||||
#include "statscolors.h"
|
#include "statscolors.h"
|
||||||
#include "statshelper.h"
|
#include "statshelper.h"
|
||||||
#include "statstranslations.h"
|
#include "statstranslations.h"
|
||||||
|
#include "statsview.h"
|
||||||
#include "zvalues.h"
|
#include "zvalues.h"
|
||||||
|
|
||||||
#include <math.h> // for lrint()
|
#include <math.h> // for lrint()
|
||||||
|
@ -403,7 +404,7 @@ bool BarSeries::hover(QPointF pos)
|
||||||
Item &item = items[highlighted.bar];
|
Item &item = items[highlighted.bar];
|
||||||
item.highlight(index.subitem, true, binCount());
|
item.highlight(index.subitem, true, binCount());
|
||||||
if (!information)
|
if (!information)
|
||||||
information = createItemPtr<InformationBox>(scene);
|
information = view.createChartItem<InformationBox>();
|
||||||
information->setText(makeInfo(item, highlighted.subitem), pos);
|
information->setText(makeInfo(item, highlighted.subitem), pos);
|
||||||
} else {
|
} else {
|
||||||
information.reset();
|
information.reset();
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "statscolors.h"
|
#include "statscolors.h"
|
||||||
#include "statshelper.h"
|
#include "statshelper.h"
|
||||||
#include "statstranslations.h"
|
#include "statstranslations.h"
|
||||||
|
#include "statsview.h"
|
||||||
#include "zvalues.h"
|
#include "zvalues.h"
|
||||||
|
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
|
@ -149,7 +150,7 @@ bool BoxSeries::hover(QPointF pos)
|
||||||
Item &item = *items[highlighted];
|
Item &item = *items[highlighted];
|
||||||
item.highlight(true);
|
item.highlight(true);
|
||||||
if (!information)
|
if (!information)
|
||||||
information = createItemPtr<InformationBox>(scene);
|
information = view.createChartItem<InformationBox>();
|
||||||
information->setText(formatInformation(item), pos);
|
information->setText(formatInformation(item), pos);
|
||||||
} else {
|
} else {
|
||||||
information.reset();
|
information.reset();
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#include "informationbox.h"
|
#include "informationbox.h"
|
||||||
#include "statscolors.h"
|
#include "statscolors.h"
|
||||||
|
#include "statsview.h"
|
||||||
#include "zvalues.h"
|
#include "zvalues.h"
|
||||||
|
|
||||||
#include <QFontMetrics>
|
#include <QFontMetrics>
|
||||||
#include <QGraphicsScene>
|
|
||||||
|
|
||||||
static const QColor informationBorderColor(Qt::black);
|
static const QColor informationBorderColor(Qt::black);
|
||||||
static const QColor informationColor(0xff, 0xff, 0x00, 192); // Note: fourth argument is opacity
|
static const QColor informationColor(0xff, 0xff, 0x00, 192); // Note: fourth argument is opacity
|
||||||
|
@ -11,74 +11,65 @@ static const int informationBorder = 2;
|
||||||
static const double informationBorderRadius = 4.0; // Radius of rounded corners
|
static const double informationBorderRadius = 4.0; // Radius of rounded corners
|
||||||
static const int distanceFromPointer = 10; // Distance to place box from mouse pointer or scatter item
|
static const int distanceFromPointer = 10; // Distance to place box from mouse pointer or scatter item
|
||||||
|
|
||||||
InformationBox::InformationBox() : RoundRectItem(informationBorderRadius, nullptr)
|
InformationBox::InformationBox(StatsView &v) :
|
||||||
|
ChartRectItem(v, QPen(informationBorderColor, informationBorder),
|
||||||
|
QBrush(informationColor), informationBorderRadius)
|
||||||
{
|
{
|
||||||
setPen(QPen(informationBorderColor, informationBorder));
|
|
||||||
setBrush(informationColor);
|
|
||||||
setZValue(ZValues::informationBox);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InformationBox::setText(const std::vector<QString> &text, QPointF pos)
|
void InformationBox::setText(const std::vector<QString> &text, QPointF pos)
|
||||||
{
|
{
|
||||||
width = height = 0.0;
|
QFontMetrics fm(font);
|
||||||
textItems.clear();
|
double fontHeight = fm.height();
|
||||||
|
|
||||||
|
std::vector<double> widths;
|
||||||
|
widths.reserve(text.size());
|
||||||
|
width = 0.0;
|
||||||
for (const QString &s: text) {
|
for (const QString &s: text) {
|
||||||
if (!s.isEmpty())
|
widths.push_back(static_cast<double>(fm.size(Qt::TextSingleLine, s).width()));
|
||||||
addLine(s);
|
width = std::max(width, widths.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
width += 4.0 * informationBorder;
|
width += 4.0 * informationBorder;
|
||||||
height += 4.0 * informationBorder;
|
height = widths.size() * fontHeight + 4.0 * informationBorder;
|
||||||
|
|
||||||
// Setting the position will also set the proper size
|
ChartRectItem::resize(QSizeF(width, height));
|
||||||
setPos(pos);
|
|
||||||
|
painter->setPen(QPen(darkLabelColor)); // QPainter uses QPen to set text color!
|
||||||
|
double y = 2.0 * informationBorder;
|
||||||
|
for (size_t i = 0; i < widths.size(); ++i) {
|
||||||
|
QRectF rect(2.0 * informationBorder, y, widths[i], fontHeight);
|
||||||
|
painter->drawText(rect, text[i]);
|
||||||
|
y += fontHeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InformationBox::setPos(QPointF pos)
|
void InformationBox::setPos(QPointF pos)
|
||||||
{
|
{
|
||||||
QRectF plotArea = scene()->sceneRect();
|
QSizeF size = sceneSize();
|
||||||
|
|
||||||
double x = pos.x() + distanceFromPointer;
|
double x = pos.x() + distanceFromPointer;
|
||||||
if (x + width >= plotArea.right()) {
|
if (x + width >= size.width()) {
|
||||||
if (pos.x() - width >= plotArea.x())
|
if (pos.x() - width >= 0.0)
|
||||||
x = pos.x() - width;
|
x = pos.x() - width;
|
||||||
else
|
else
|
||||||
x = pos.x() - width / 2.0;
|
x = pos.x() - width / 2.0;
|
||||||
}
|
}
|
||||||
double y = pos.y() + distanceFromPointer;
|
double y = pos.y() + distanceFromPointer;
|
||||||
if (y + height >= plotArea.bottom()) {
|
if (y + height >= size.height()) {
|
||||||
if (pos.y() - height >= plotArea.y())
|
if (pos.y() - height >= 0.0)
|
||||||
y = pos.y() - height;
|
y = pos.y() - height;
|
||||||
else
|
else
|
||||||
y = pos.y() - height / 2.0;
|
y = pos.y() - height / 2.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
setRect(x, y, width, height);
|
ChartRectItem::setPos(QPointF(x, y));
|
||||||
double actY = y + 2.0 * informationBorder;
|
|
||||||
for (auto &item: textItems) {
|
|
||||||
item->setPos(QPointF(x + 2.0 * informationBorder, actY));
|
|
||||||
actY += item->boundingRect().height();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InformationBox::addLine(const QString &s)
|
|
||||||
{
|
|
||||||
textItems.emplace_back(new QGraphicsSimpleTextItem(s, this));
|
|
||||||
QGraphicsSimpleTextItem &item = *textItems.back();
|
|
||||||
item.setBrush(QBrush(darkLabelColor));
|
|
||||||
item.setPos(QPointF(0.0, height));
|
|
||||||
item.setFont(font);
|
|
||||||
item.setZValue(ZValues::informationBox);
|
|
||||||
QRectF rect = item.boundingRect();
|
|
||||||
width = std::max(width, rect.width());
|
|
||||||
height += rect.height();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to stay within three-thirds of the chart height
|
// Try to stay within three-thirds of the chart height
|
||||||
int InformationBox::recommendedMaxLines() const
|
int InformationBox::recommendedMaxLines() const
|
||||||
{
|
{
|
||||||
QFontMetrics fm(font);
|
QFontMetrics fm(font);
|
||||||
int maxHeight = static_cast<int>(scene()->sceneRect().height());
|
int maxHeight = static_cast<int>(sceneSize().height());
|
||||||
return maxHeight * 2 / fm.height() / 3;
|
return maxHeight * 2 / fm.height() / 3;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,26 +4,24 @@
|
||||||
#ifndef INFORMATION_BOX_H
|
#ifndef INFORMATION_BOX_H
|
||||||
#define INFORMATION_BOX_H
|
#define INFORMATION_BOX_H
|
||||||
|
|
||||||
#include "backend-shared/roundrectitem.h"
|
#include "chartitem.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <QFont>
|
#include <QFont>
|
||||||
|
|
||||||
struct dive;
|
struct dive;
|
||||||
class QGraphicsScene;
|
class StatsView;
|
||||||
|
|
||||||
// Information window showing data of highlighted dive
|
// Information window showing data of highlighted dive
|
||||||
struct InformationBox : RoundRectItem {
|
struct InformationBox : ChartRectItem {
|
||||||
InformationBox();
|
InformationBox(StatsView &);
|
||||||
void setText(const std::vector<QString> &text, QPointF pos);
|
void setText(const std::vector<QString> &text, QPointF pos);
|
||||||
void setPos(QPointF pos);
|
void setPos(QPointF pos);
|
||||||
int recommendedMaxLines() const;
|
int recommendedMaxLines() const;
|
||||||
private:
|
private:
|
||||||
QFont font; // For future specialization.
|
QFont font; // For future specialization.
|
||||||
double width, height;
|
double width, height;
|
||||||
void addLine(const QString &s);
|
|
||||||
std::vector<std::unique_ptr<QGraphicsSimpleTextItem>> textItems;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "statscolors.h"
|
#include "statscolors.h"
|
||||||
#include "statshelper.h"
|
#include "statshelper.h"
|
||||||
#include "statstranslations.h"
|
#include "statstranslations.h"
|
||||||
|
#include "statsview.h"
|
||||||
#include "zvalues.h"
|
#include "zvalues.h"
|
||||||
|
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
@ -246,7 +247,7 @@ bool PieSeries::hover(QPointF pos)
|
||||||
if (highlighted >= 0 && highlighted < (int)items.size()) {
|
if (highlighted >= 0 && highlighted < (int)items.size()) {
|
||||||
items[highlighted].highlight(highlighted, true, (int)items.size());
|
items[highlighted].highlight(highlighted, true, (int)items.size());
|
||||||
if (!information)
|
if (!information)
|
||||||
information = createItemPtr<InformationBox>(scene);
|
information = view.createChartItem<InformationBox>();
|
||||||
information->setText(makeInfo(highlighted), pos);
|
information->setText(makeInfo(highlighted), pos);
|
||||||
} else {
|
} else {
|
||||||
information.reset();
|
information.reset();
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "statshelper.h"
|
#include "statshelper.h"
|
||||||
#include "statstranslations.h"
|
#include "statstranslations.h"
|
||||||
#include "statsvariables.h"
|
#include "statsvariables.h"
|
||||||
|
#include "statsview.h"
|
||||||
#include "zvalues.h"
|
#include "zvalues.h"
|
||||||
#include "core/dive.h"
|
#include "core/dive.h"
|
||||||
#include "core/divelist.h"
|
#include "core/divelist.h"
|
||||||
|
@ -173,7 +174,7 @@ bool ScatterSeries::hover(QPointF pos)
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if (!information)
|
if (!information)
|
||||||
information = createItemPtr<InformationBox>(scene);
|
information = view.createChartItem<InformationBox>();
|
||||||
|
|
||||||
std::vector<QString> text;
|
std::vector<QString> text;
|
||||||
text.reserve(highlighted.size() * 5);
|
text.reserve(highlighted.size() * 5);
|
||||||
|
|
|
@ -279,14 +279,6 @@ T *StatsView::createAxis(const QString &title, Args&&... args)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, class... Args>
|
|
||||||
std::unique_ptr<T> StatsView::createChartItem(Args&&... args)
|
|
||||||
{
|
|
||||||
std::unique_ptr<T> res(new T(*this, std::forward<Args>(args)...));
|
|
||||||
items.push_back(res.get());
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatsView::setAxes(StatsAxis *x, StatsAxis *y)
|
void StatsView::setAxes(StatsAxis *x, StatsAxis *y)
|
||||||
{
|
{
|
||||||
xAxis = x;
|
xAxis = x;
|
||||||
|
|
|
@ -52,6 +52,9 @@ public:
|
||||||
QSizeF size() const;
|
QSizeF size() const;
|
||||||
void addQSGNode(QSGNode *node, int z); // Must only be called in render thread!
|
void addQSGNode(QSGNode *node, int z); // Must only be called in render thread!
|
||||||
void unregisterChartItem(const ChartItem *item);
|
void unregisterChartItem(const ChartItem *item);
|
||||||
|
template <typename T, class... Args>
|
||||||
|
std::unique_ptr<T> createChartItem(Args&&... args);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void replotIfVisible();
|
void replotIfVisible();
|
||||||
private:
|
private:
|
||||||
|
@ -109,9 +112,6 @@ private:
|
||||||
template <typename T, class... Args>
|
template <typename T, class... Args>
|
||||||
T *createAxis(const QString &title, Args&&... args);
|
T *createAxis(const QString &title, Args&&... args);
|
||||||
|
|
||||||
template <typename T, class... Args>
|
|
||||||
std::unique_ptr<T> createChartItem(Args&&... args);
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
CategoryAxis *createCategoryAxis(const QString &title, const StatsBinner &binner,
|
CategoryAxis *createCategoryAxis(const QString &title, const StatsBinner &binner,
|
||||||
const std::vector<T> &bins, bool isHorizontal);
|
const std::vector<T> &bins, bool isHorizontal);
|
||||||
|
@ -179,4 +179,14 @@ private:
|
||||||
QSGImageNode *rootNode;
|
QSGImageNode *rootNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This implementation detail must be known to users of the class.
|
||||||
|
// Perhaps move it into a statsview_impl.h file.
|
||||||
|
template <typename T, class... Args>
|
||||||
|
std::unique_ptr<T> StatsView::createChartItem(Args&&... args)
|
||||||
|
{
|
||||||
|
std::unique_ptr<T> res(new T(*this, std::forward<Args>(args)...));
|
||||||
|
items.push_back(res.get());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue