diff --git a/CMakeLists.txt b/CMakeLists.txt index d25313e96..0fa9032ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -301,7 +301,7 @@ endif() #set up the subsurface_link_libraries variable set(SUBSURFACE_LINK_LIBRARIES ${SUBSURFACE_LINK_LIBRARIES} ${LIBDIVECOMPUTER_LIBRARIES} ${LIBGIT2_LIBRARIES} ${LIBUSB_LIBRARIES} ${LIBMTP_LIBRARIES}) if (NOT SUBSURFACE_TARGET_EXECUTABLE MATCHES "DownloaderExecutable") - qt5_add_resources(SUBSURFACE_RESOURCES subsurface.qrc map-widget/qml/map-widget.qrc stats/qml/statsview.qrc) + qt5_add_resources(SUBSURFACE_RESOURCES subsurface.qrc map-widget/qml/map-widget.qrc desktop-widgets/qml/statsview2.qrc) endif() # hack to build successfully on LGTM diff --git a/backend-shared/roundrectitem.cpp b/backend-shared/roundrectitem.cpp index 2dbfd7b03..52200b017 100644 --- a/backend-shared/roundrectitem.cpp +++ b/backend-shared/roundrectitem.cpp @@ -7,6 +7,10 @@ RoundRectItem::RoundRectItem(double radius, QGraphicsItem *parent) : QGraphicsRe { } +RoundRectItem::RoundRectItem(double radius) : RoundRectItem(radius, nullptr) +{ +} + void RoundRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) { painter->save(); diff --git a/backend-shared/roundrectitem.h b/backend-shared/roundrectitem.h index d3f58782f..b8cb3f89b 100644 --- a/backend-shared/roundrectitem.h +++ b/backend-shared/roundrectitem.h @@ -7,6 +7,7 @@ class RoundRectItem : public QGraphicsRectItem { public: RoundRectItem(double radius, QGraphicsItem *parent); + RoundRectItem(double radius); private: void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; double radius; diff --git a/desktop-widgets/qml/statsview2.qml b/desktop-widgets/qml/statsview2.qml new file mode 100644 index 000000000..ccad7fd1e --- /dev/null +++ b/desktop-widgets/qml/statsview2.qml @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +import QtQuick 2.0 +import org.subsurfacedivelog.mobile 1.0 + +StatsView { +} diff --git a/stats/qml/statsview.qrc b/desktop-widgets/qml/statsview2.qrc similarity index 64% rename from stats/qml/statsview.qrc rename to desktop-widgets/qml/statsview2.qrc index aeb65167e..d54f6c6b9 100644 --- a/stats/qml/statsview.qrc +++ b/desktop-widgets/qml/statsview2.qrc @@ -1,5 +1,5 @@ - statsview.qml + statsview2.qml diff --git a/desktop-widgets/statswidget.cpp b/desktop-widgets/statswidget.cpp index 01fd16eb1..e0090395f 100644 --- a/desktop-widgets/statswidget.cpp +++ b/desktop-widgets/statswidget.cpp @@ -70,6 +70,7 @@ QSize ChartItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QMod return size; } +static const QUrl urlStatsView = QUrl(QStringLiteral("qrc:/qml/statsview2.qml")); StatsWidget::StatsWidget(QWidget *parent) : QWidget(parent) { ui.setupUi(this); @@ -83,6 +84,13 @@ StatsWidget::StatsWidget(QWidget *parent) : QWidget(parent) connect(ui.var1Binner, QOverload::of(&QComboBox::activated), this, &StatsWidget::var1BinnerChanged); connect(ui.var2Binner, QOverload::of(&QComboBox::activated), this, &StatsWidget::var2BinnerChanged); connect(ui.var2Operation, QOverload::of(&QComboBox::activated), this, &StatsWidget::var2OperationChanged); + + ui.stats->setSource(urlStatsView); + ui.stats->setResizeMode(QQuickWidget::SizeRootObjectToView); + QQuickItem *root = ui.stats->rootObject(); + view = qobject_cast(root); + if (!view) + qWarning("Oops. The root of the StatsView is not a StatsView."); } // Initialize QComboBox with list of variables @@ -96,7 +104,7 @@ static void setVariableList(QComboBox *combo, const StatsState::VariableList &li } // Initialize QComboBox and QLabel of binners. Hide if there are no binners. -static void setBinList(QLabel *label, QComboBox *combo, const StatsState::BinnerList &list) +static void setBinList(QComboBox *combo, const StatsState::BinnerList &list) { combo->clear(); combo->setEnabled(!list.binners.empty()); @@ -114,8 +122,8 @@ void StatsWidget::updateUi() int pos = charts.update(uiState.charts); ui.chartType->setCurrentIndex(pos); ui.chartType->setItemDelegate(new ChartItemDelegate); - setBinList(ui.var1BinnerLabel, ui.var1Binner, uiState.binners1); - setBinList(ui.var2BinnerLabel, ui.var2Binner, uiState.binners2); + setBinList(ui.var1Binner, uiState.binners1); + setBinList(ui.var2Binner, uiState.binners2); setVariableList(ui.var2Operation, uiState.operations2); // Add checkboxes for additional features @@ -129,7 +137,8 @@ void StatsWidget::updateUi() ui.features->addWidget(check); } - ui.stats->plot(state); + if (view) + view->plot(state); } void StatsWidget::closeStats() diff --git a/desktop-widgets/statswidget.h b/desktop-widgets/statswidget.h index 40e6d106c..b85d89730 100644 --- a/desktop-widgets/statswidget.h +++ b/desktop-widgets/statswidget.h @@ -9,6 +9,7 @@ #include class QCheckBox; +class StatsView; class StatsWidget : public QWidget { Q_OBJECT @@ -27,6 +28,7 @@ slots: private: Ui::StatsWidget ui; StatsState state; + StatsView *view; void updateUi(); std::vector> features; diff --git a/desktop-widgets/statswidget.ui b/desktop-widgets/statswidget.ui index 684b0fa58..a20fb4a8f 100644 --- a/desktop-widgets/statswidget.ui +++ b/desktop-widgets/statswidget.ui @@ -105,7 +105,7 @@ - + 0 @@ -116,14 +116,6 @@ - - - StatsView - QQuickWidget -
stats/statsview.h
- 1 -
-
diff --git a/stats/barseries.cpp b/stats/barseries.cpp index 5727745a0..986aa7e0d 100644 --- a/stats/barseries.cpp +++ b/stats/barseries.cpp @@ -2,6 +2,7 @@ #include "barseries.h" #include "informationbox.h" #include "statscolors.h" +#include "statshelper.h" #include "statstranslations.h" #include "zvalues.h" @@ -27,19 +28,19 @@ bool BarSeries::Index::operator==(const Index &i2) const return std::tie(bar, subitem) == std::tie(i2.bar, i2.subitem); } -BarSeries::BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis, +BarSeries::BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis, bool horizontal, bool stacked, const QString &categoryName, const StatsVariable *valueVariable, std::vector valueBinNames) : - StatsSeries(chart, xAxis, yAxis), + StatsSeries(scene, xAxis, yAxis), horizontal(horizontal), stacked(stacked), categoryName(categoryName), valueVariable(valueVariable), valueBinNames(std::move(valueBinNames)) { } -BarSeries::BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis, +BarSeries::BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis, bool horizontal, const QString &categoryName, const std::vector &items) : - BarSeries(chart, xAxis, yAxis, horizontal, false, categoryName, nullptr, std::vector()) + BarSeries(scene, xAxis, yAxis, horizontal, false, categoryName, nullptr, std::vector()) { for (const CountItem &item: items) { StatsOperationResults res; @@ -50,10 +51,10 @@ BarSeries::BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis } } -BarSeries::BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis, +BarSeries::BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis, bool horizontal, const QString &categoryName, const StatsVariable *valueVariable, const std::vector &items) : - BarSeries(chart, xAxis, yAxis, horizontal, false, categoryName, valueVariable, std::vector()) + BarSeries(scene, xAxis, yAxis, horizontal, false, categoryName, valueVariable, std::vector()) { for (const ValueItem &item: items) { add_item(item.lowerBound, item.upperBound, makeSubItems(item.value, item.label), @@ -61,11 +62,11 @@ BarSeries::BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis } } -BarSeries::BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis, +BarSeries::BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis, bool horizontal, bool stacked, const QString &categoryName, const StatsVariable *valueVariable, std::vector valueBinNames, const std::vector &items) : - BarSeries(chart, xAxis, yAxis, horizontal, stacked, categoryName, valueVariable, std::move(valueBinNames)) + BarSeries(scene, xAxis, yAxis, horizontal, stacked, categoryName, valueVariable, std::move(valueBinNames)) { for (const MultiItem &item: items) { StatsOperationResults res; @@ -85,12 +86,12 @@ BarSeries::~BarSeries() { } -BarSeries::BarLabel::BarLabel(QtCharts::QChart *chart, const std::vector &labels, int bin_nr, int binCount) : +BarSeries::BarLabel::BarLabel(QGraphicsScene *scene, const std::vector &labels, int bin_nr, int binCount) : totalWidth(0.0), totalHeight(0.0), isOutside(false) { items.reserve(labels.size()); for (const QString &label: labels) { - items.emplace_back(new QGraphicsSimpleTextItem(chart)); + items.emplace_back(createItem(scene)); items.back()->setText(label); items.back()->setZValue(ZValues::seriesLabels); QRectF rect = items.back()->boundingRect(); @@ -175,7 +176,7 @@ void BarSeries::BarLabel::updatePosition(bool horizontal, bool center, const QRe highlight(false, bin_nr, binCount); } -BarSeries::Item::Item(QtCharts::QChart *chart, BarSeries *series, double lowerBound, double upperBound, +BarSeries::Item::Item(QGraphicsScene *scene, BarSeries *series, double lowerBound, double upperBound, std::vector subitemsIn, const QString &binName, const StatsOperationResults &res, int total, bool horizontal, bool stacked, int binCount) : @@ -264,9 +265,9 @@ std::vector BarSeries::makeSubItems(const std::vector 0.0) { - res.push_back({ std::make_unique(chart), {}, from, from + v, bin_nr }); + res.push_back({ createItemPtr(scene), {}, from, from + v, bin_nr }); if (!label.empty()) - res.back().label = std::make_unique(chart, label, bin_nr, binCount()); + res.back().label = std::make_unique(scene, label, bin_nr, binCount()); } if (stacked) from += v; @@ -292,7 +293,7 @@ void BarSeries::add_item(double lowerBound, double upperBound, std::vector(scene); information->setText(makeInfo(item, highlighted.subitem), pos); } else { information.reset(); diff --git a/stats/barseries.h b/stats/barseries.h index 114df540a..299998bfb 100644 --- a/stats/barseries.h +++ b/stats/barseries.h @@ -12,9 +12,7 @@ #include #include -namespace QtCharts { - class QAbstractAxis; -} +class QGraphicsScene; class InformationBox; class StatsVariable; @@ -49,13 +47,13 @@ public: // Note: this expects that all items are added with increasing pos // and that no bar is inside another bar, i.e. lowerBound and upperBound // are ordered identically. - BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis, + BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis, bool horizontal, const QString &categoryName, const std::vector &items); - BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis, + BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis, bool horizontal, const QString &categoryName, const StatsVariable *valueVariable, const std::vector &items); - BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis, + BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis, bool horizontal, bool stacked, const QString &categoryName, const StatsVariable *valueVariable, std::vector valueBinNames, const std::vector &items); @@ -65,7 +63,7 @@ public: bool hover(QPointF pos) override; void unhighlight() override; private: - BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis, + BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis, bool horizontal, bool stacked, const QString &categoryName, const StatsVariable *valueVariable, std::vector valueBinNames); @@ -85,7 +83,7 @@ private: std::vector> items; double totalWidth, totalHeight; // Size of the item bool isOutside; // Is shown outside of bar - BarLabel(QtCharts::QChart *chart, const std::vector &labels, int bin_nr, int binCount); + BarLabel(QGraphicsScene *scene, const std::vector &labels, int bin_nr, int binCount); void setVisible(bool visible); void updatePosition(bool horizontal, bool center, const QRectF &rect, int bin_nr, int binCount); void highlight(bool highlight, int bin_nr, int binCount); @@ -109,7 +107,7 @@ private: const QString binName; StatsOperationResults res; int total; - Item(QtCharts::QChart *chart, BarSeries *series, double lowerBound, double upperBound, + Item(QGraphicsScene *scene, BarSeries *series, double lowerBound, double upperBound, std::vector subitems, const QString &binName, const StatsOperationResults &res, int total, bool horizontal, bool stacked, int binCount); diff --git a/stats/boxseries.cpp b/stats/boxseries.cpp index 805e8cc8e..c684eff8b 100644 --- a/stats/boxseries.cpp +++ b/stats/boxseries.cpp @@ -2,6 +2,7 @@ #include "boxseries.h" #include "informationbox.h" #include "statscolors.h" +#include "statshelper.h" #include "statstranslations.h" #include "zvalues.h" @@ -12,9 +13,9 @@ static const double boxWidth = 0.8; // 1.0 = full width of category static const int boxBorderWidth = 2; -BoxSeries::BoxSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis, +BoxSeries::BoxSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis, const QString &variable, const QString &unit, int decimals) : - StatsSeries(chart, xAxis, yAxis), + StatsSeries(scene, xAxis, yAxis), variable(variable), unit(unit), decimals(decimals), highlighted(-1) { } @@ -23,12 +24,8 @@ BoxSeries::~BoxSeries() { } -BoxSeries::Item::Item(QtCharts::QChart *chart, BoxSeries *series, double lowerBound, double upperBound, +BoxSeries::Item::Item(QGraphicsScene *scene, BoxSeries *series, double lowerBound, double upperBound, const StatsQuartiles &q, const QString &binName) : - box(chart), - topWhisker(chart), bottomWhisker(chart), - topBar(chart), bottomBar(chart), - center(chart), lowerBound(lowerBound), upperBound(upperBound), q(q), binName(binName) { @@ -38,6 +35,12 @@ BoxSeries::Item::Item(QtCharts::QChart *chart, BoxSeries *series, double lowerBo topBar.setZValue(ZValues::series); bottomBar.setZValue(ZValues::series); center.setZValue(ZValues::series); + scene->addItem(&box); + scene->addItem(&topWhisker); + scene->addItem(&bottomWhisker); + scene->addItem(&topBar); + scene->addItem(&bottomBar); + scene->addItem(¢er); highlight(false); updatePosition(series); } @@ -89,7 +92,7 @@ void BoxSeries::Item::updatePosition(BoxSeries *series) void BoxSeries::append(double lowerBound, double upperBound, const StatsQuartiles &q, const QString &binName) { - items.emplace_back(new Item(chart, this, lowerBound, upperBound, q, binName)); + items.emplace_back(new Item(scene, this, lowerBound, upperBound, q, binName)); } void BoxSeries::updatePositions() @@ -147,7 +150,7 @@ bool BoxSeries::hover(QPointF pos) Item &item = *items[highlighted]; item.highlight(true); if (!information) - information.reset(new InformationBox(chart)); + information = createItemPtr(scene); information->setText(formatInformation(item), pos); } else { information.reset(); diff --git a/stats/boxseries.h b/stats/boxseries.h index 43b177619..175ad771e 100644 --- a/stats/boxseries.h +++ b/stats/boxseries.h @@ -14,10 +14,11 @@ #include class InformationBox; +class QGraphicsScene; class BoxSeries : public StatsSeries { public: - BoxSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis, + BoxSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis, const QString &variable, const QString &unit, int decimals); ~BoxSeries(); @@ -44,7 +45,7 @@ private: double lowerBound, upperBound; StatsQuartiles q; QString binName; - Item(QtCharts::QChart *chart, BoxSeries *series, double lowerBound, double upperBound, const StatsQuartiles &q, const QString &binName); + Item(QGraphicsScene *scene, BoxSeries *series, double lowerBound, double upperBound, const StatsQuartiles &q, const QString &binName); void updatePosition(BoxSeries *series); void highlight(bool highlight); }; diff --git a/stats/informationbox.cpp b/stats/informationbox.cpp index 727b6fe83..c11104333 100644 --- a/stats/informationbox.cpp +++ b/stats/informationbox.cpp @@ -4,6 +4,7 @@ #include #include +#include static const QColor informationBorderColor(Qt::black); static const QColor informationColor(0xff, 0xff, 0x00, 192); // Note: fourth argument is opacity @@ -11,7 +12,7 @@ static const int informationBorder = 2; 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 -InformationBox::InformationBox(QtCharts::QChart *chart) : RoundRectItem(informationBorderRadius, chart), chart(chart) +InformationBox::InformationBox() : RoundRectItem(informationBorderRadius, nullptr) { setPen(QPen(informationBorderColor, informationBorder)); setBrush(informationColor); @@ -37,7 +38,7 @@ void InformationBox::setText(const std::vector &text, QPointF pos) void InformationBox::setPos(QPointF pos) { - QRectF plotArea = chart->plotArea(); + QRectF plotArea = scene()->sceneRect(); double x = pos.x() + distanceFromPointer; if (x + width >= plotArea.right()) { @@ -79,6 +80,6 @@ void InformationBox::addLine(const QString &s) int InformationBox::recommendedMaxLines() const { QFontMetrics fm(font); - int maxHeight = static_cast(chart->plotArea().height()); + int maxHeight = static_cast(scene()->sceneRect().height()); return maxHeight * 2 / fm.height() / 3; } diff --git a/stats/informationbox.h b/stats/informationbox.h index 0c71447aa..741df537f 100644 --- a/stats/informationbox.h +++ b/stats/informationbox.h @@ -10,19 +10,16 @@ #include #include -namespace QtCharts { - class QChart; -} struct dive; +class QGraphicsScene; // Information window showing data of highlighted dive struct InformationBox : RoundRectItem { - InformationBox(QtCharts::QChart *chart); + InformationBox(); void setText(const std::vector &text, QPointF pos); void setPos(QPointF pos); int recommendedMaxLines() const; private: - QtCharts::QChart *chart; QFont font; // For future specialization. double width, height; void addLine(const QString &s); diff --git a/stats/legend.cpp b/stats/legend.cpp index 99340a8f9..27607fb51 100644 --- a/stats/legend.cpp +++ b/stats/legend.cpp @@ -4,8 +4,8 @@ #include "zvalues.h" #include +#include #include -#include #include static const double legendBorderSize = 2.0; @@ -16,8 +16,8 @@ static const double legendInternalBorderSize = 2.0; static const QColor legendColor(0x00, 0x8e, 0xcc, 192); // Note: fourth argument is opacity static const QColor legendBorderColor(Qt::black); -Legend::Legend(QGraphicsWidget *chart, const std::vector &names) : - RoundRectItem(legendBoxBorderRadius, chart), chart(chart), +Legend::Legend(const std::vector &names) : + RoundRectItem(legendBoxBorderRadius), displayedItems(0), width(0.0), height(0.0) { setZValue(ZValues::legend); @@ -40,8 +40,6 @@ Legend::Legend(QGraphicsWidget *chart, const std::vector &names) : } setPen(QPen(legendBorderColor, legendBorderSize)); setBrush(QBrush(legendColor)); - - resize(); // Draw initial legend } Legend::Entry::Entry(const QString &name, int idx, int numBins, QGraphicsItem *parent) : @@ -70,7 +68,7 @@ void Legend::resize() if (entries.empty()) return hide(); - QSizeF size = chart->size(); + QSizeF size = scene()->sceneRect().size(); // Silly heuristics: make the legend at most half as high and half as wide as the chart. // Not sure if that makes sense - this might need some optimization. @@ -110,7 +108,7 @@ void Legend::updatePosition() if (displayedItems <= 0) return hide(); // For now, place the legend in the top right corner. - QPointF pos(chart->size().width() - width - 10.0, 10.0); + QPointF pos(scene()->sceneRect().width() - width - 10.0, 10.0); setRect(QRectF(pos, QSizeF(width, height))); for (int i = 0; i < displayedItems; ++i) { QPointF itemPos = pos + entries[i].pos; diff --git a/stats/legend.h b/stats/legend.h index 2baf6f67b..c643a41f3 100644 --- a/stats/legend.h +++ b/stats/legend.h @@ -8,11 +8,12 @@ #include #include +class QGraphicsScene; class QGraphicsSceneMouseEvent; class Legend : public RoundRectItem { public: - Legend(QGraphicsWidget *chart, const std::vector &names); + Legend(const std::vector &names); void hover(QPointF pos); void resize(); // called when the chart size changes. private: @@ -24,7 +25,6 @@ private: double width; Entry(const QString &name, int idx, int numBins, QGraphicsItem *parent); }; - QGraphicsWidget *chart; int displayedItems; double width; double height; diff --git a/stats/pieseries.cpp b/stats/pieseries.cpp index 108046b23..ac43b6d3a 100644 --- a/stats/pieseries.cpp +++ b/stats/pieseries.cpp @@ -2,6 +2,7 @@ #include "pieseries.h" #include "informationbox.h" #include "statscolors.h" +#include "statshelper.h" #include "statstranslations.h" #include "zvalues.h" @@ -16,9 +17,9 @@ static const double pieBorderWidth = 1.0; static const double innerLabelRadius = 0.75; // 1.0 = at outer border of pie static const double outerLabelRadius = 1.01; // 1.0 = at outer border of pie -PieSeries::Item::Item(QtCharts::QChart *chart, const QString &name, int from, int count, int totalCount, +PieSeries::Item::Item(QGraphicsScene *scene, const QString &name, int from, int count, int totalCount, int bin_nr, int numBins, bool labels) : - item(new QGraphicsEllipseItem(chart)), + item(createItemPtr(scene)), name(name), count(count) { @@ -38,10 +39,10 @@ PieSeries::Item::Item(QtCharts::QChart *chart, const QString &name, int from, in if (labels) { double percentage = count * 100.0 / totalCount; QString innerLabelText = QStringLiteral("%1\%").arg(loc.toString(percentage, 'f', 1)); - innerLabel.reset(new QGraphicsSimpleTextItem(innerLabelText, chart)); + innerLabel = createItemPtr(scene, innerLabelText); innerLabel->setZValue(ZValues::seriesLabels); - outerLabel.reset(new QGraphicsSimpleTextItem(name, chart)); + outerLabel = createItemPtr(scene, name); outerLabel->setBrush(QBrush(darkLabelColor)); outerLabel->setZValue(ZValues::seriesLabels); } @@ -85,9 +86,9 @@ void PieSeries::Item::highlight(int bin_nr, bool highlight, int numBins) } } -PieSeries::PieSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis, const QString &categoryName, +PieSeries::PieSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis, const QString &categoryName, const std::vector> &data, bool keepOrder, bool labels) : - StatsSeries(chart, xAxis, yAxis), + StatsSeries(scene, xAxis, yAxis), categoryName(categoryName), highlighted(-1) { @@ -147,7 +148,7 @@ PieSeries::PieSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis int act = 0; for (auto it2 = sorted.begin(); it2 != it; ++it2) { int count = data[*it2].second; - items.emplace_back(chart, data[*it2].first, act, count, totalCount, (int)items.size(), numBins, labels); + items.emplace_back(scene, data[*it2].first, act, count, totalCount, (int)items.size(), numBins, labels); act += count; } @@ -157,7 +158,7 @@ PieSeries::PieSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis for (auto it2 = it; it2 != sorted.end(); ++it2) other.push_back({ data[*it2].first, data[*it2].second }); QString name = StatsTranslations::tr("other (%1 items)").arg(other.size()); - items.emplace_back(chart, name, act, totalCount - act, totalCount, (int)items.size(), numBins, labels); + items.emplace_back(scene, name, act, totalCount - act, totalCount, (int)items.size(), numBins, labels); } } @@ -167,7 +168,7 @@ PieSeries::~PieSeries() void PieSeries::updatePositions() { - QRectF plotRect = chart->plotArea(); + QRectF plotRect = scene->sceneRect(); center = plotRect.center(); radius = std::min(plotRect.width(), plotRect.height()) * pieSize / 2.0; QRectF rect(center.x() - radius, center.y() - radius, 2.0 * radius, 2.0 * radius); @@ -246,7 +247,7 @@ bool PieSeries::hover(QPointF pos) if (highlighted >= 0 && highlighted < (int)items.size()) { items[highlighted].highlight(highlighted, true, (int)items.size()); if (!information) - information.reset(new InformationBox(chart)); + information = createItemPtr(scene); information->setText(makeInfo(highlighted), pos); } else { information.reset(); diff --git a/stats/pieseries.h b/stats/pieseries.h index 242cfa781..c7e2af319 100644 --- a/stats/pieseries.h +++ b/stats/pieseries.h @@ -11,14 +11,16 @@ class InformationBox; class QGraphicsEllipseItem; +class QGraphicsScene; class QGraphicsSimpleTextItem; +class QRectF; class PieSeries : public StatsSeries { public: // The pie series is initialized with (name, count) pairs. // If keepOrder is false, bins will be sorted by size, otherwise the sorting // of the shown bins will be retained. Small bins are omitted for clarity. - PieSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis, const QString &categoryName, + PieSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis, const QString &categoryName, const std::vector> &data, bool keepOrder, bool labels); ~PieSeries(); @@ -42,7 +44,7 @@ private: double angleTo; // In fraction of total int count; QPointF innerLabelPos, outerLabelPos; // With respect to a (-1, -1)-(1, 1) rectangle. - Item(QtCharts::QChart *chart, const QString &name, int from, int count, int totalCount, + Item(QGraphicsScene *scene, const QString &name, int from, int count, int totalCount, int bin_nr, int numBins, bool labels); void updatePositions(const QRectF &rect, const QPointF ¢er, double radius); void highlight(int bin_nr, bool highlight, int numBins); diff --git a/stats/qml/statsview.qml b/stats/qml/statsview.qml deleted file mode 100644 index 24f1fe9d3..000000000 --- a/stats/qml/statsview.qml +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -import QtQuick 2.0 -import QtCharts 2.0 - -ChartView { - antialiasing: true - localizeNumbers: true -} diff --git a/stats/scatterseries.cpp b/stats/scatterseries.cpp index de7a8a3bd..67687de72 100644 --- a/stats/scatterseries.cpp +++ b/stats/scatterseries.cpp @@ -2,6 +2,7 @@ #include "scatterseries.h" #include "informationbox.h" #include "statscolors.h" +#include "statshelper.h" #include "statstranslations.h" #include "statsvariables.h" #include "zvalues.h" @@ -16,9 +17,9 @@ static const int scatterItemDiameter = 10; static const int scatterItemBorder = 1; -ScatterSeries::ScatterSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis, +ScatterSeries::ScatterSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis, const StatsVariable &varX, const StatsVariable &varY) : - StatsSeries(chart, xAxis, yAxis), + StatsSeries(scene, xAxis, yAxis), varX(varX), varY(varY) { } @@ -58,8 +59,8 @@ static const QPixmap &scatterPixmap(bool highlight) return highlight ? *scatterPixmapHighlightedPtr : *scatterPixmapPtr; } -ScatterSeries::Item::Item(QtCharts::QChart *chart, ScatterSeries *series, dive *d, double pos, double value) : - item(new QGraphicsPixmapItem(scatterPixmap(false), chart)), +ScatterSeries::Item::Item(QGraphicsScene *scene, ScatterSeries *series, dive *d, double pos, double value) : + item(createItemPtr(scene, scatterPixmap(false))), d(d), pos(pos), value(value) @@ -82,7 +83,7 @@ void ScatterSeries::Item::highlight(bool highlight) void ScatterSeries::append(dive *d, double pos, double value) { - items.emplace_back(chart, this, d, pos, value); + items.emplace_back(scene, this, d, pos, value); } void ScatterSeries::updatePositions() @@ -173,7 +174,7 @@ bool ScatterSeries::hover(QPointF pos) return false; } else { if (!information) - information.reset(new InformationBox(chart)); + information = createItemPtr(scene); std::vector text; text.reserve(highlighted.size() * 5); diff --git a/stats/scatterseries.h b/stats/scatterseries.h index 212a8e4ea..ec25369ae 100644 --- a/stats/scatterseries.h +++ b/stats/scatterseries.h @@ -11,13 +11,14 @@ #include class QGraphicsPixmapItem; +class QGraphicsScene; class InformationBox; struct StatsVariable; struct dive; class ScatterSeries : public StatsSeries { public: - ScatterSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis, + ScatterSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis, const StatsVariable &varX, const StatsVariable &varY); ~ScatterSeries(); @@ -36,7 +37,7 @@ private: std::unique_ptr item; dive *d; double pos, value; - Item(QtCharts::QChart *chart, ScatterSeries *series, dive *d, double pos, double value); + Item(QGraphicsScene *scene, ScatterSeries *series, dive *d, double pos, double value); void updatePosition(ScatterSeries *series); void highlight(bool highlight); }; diff --git a/stats/statsaxis.cpp b/stats/statsaxis.cpp index 019a16256..4d70488da 100644 --- a/stats/statsaxis.cpp +++ b/stats/statsaxis.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "statsaxis.h" #include "statscolors.h" +#include "statshelper.h" #include "statstranslations.h" #include "statsvariables.h" #include "zvalues.h" @@ -23,9 +24,8 @@ static const double axisLabelSpaceVertical = 2.0; // Space between axis or ticks static const double axisTitleSpaceHorizontal = 2.0; // Space between labels and title static const double axisTitleSpaceVertical = 2.0; // Space between labels and title -StatsAxis::StatsAxis(QtCharts::QChart *chart, const QString &titleIn, bool horizontal, bool labelsBetweenTicks) : - QGraphicsLineItem(chart), - chart(chart), horizontal(horizontal), labelsBetweenTicks(labelsBetweenTicks), +StatsAxis::StatsAxis(const QString &titleIn, bool horizontal, bool labelsBetweenTicks) : + horizontal(horizontal), labelsBetweenTicks(labelsBetweenTicks), size(1.0), zeroOnScreen(0.0), min(0.0), max(1.0), labelWidth(0.0) { // use a Light version of the application fond for both labels and title @@ -35,7 +35,7 @@ StatsAxis::StatsAxis(QtCharts::QChart *chart, const QString &titleIn, bool horiz setPen(QPen(axisColor, axisWidth)); setZValue(ZValues::axes); if (!titleIn.isEmpty()) { - title = std::make_unique(titleIn, chart); + title.reset(new QGraphicsSimpleTextItem(titleIn, this)); title->setFont(titleFont); title->setBrush(darkLabelColor); if (!horizontal) @@ -114,8 +114,8 @@ double StatsAxis::height() const (labelsBetweenTicks ? 0.0 : axisTickSizeHorizontal); } -StatsAxis::Label::Label(const QString &name, double pos, QtCharts::QChart *chart, const QFont &font) : - label(new QGraphicsSimpleTextItem(name, chart)), +StatsAxis::Label::Label(const QString &name, double pos, QGraphicsScene *scene, const QFont &font) : + label(createItem(scene, name)), pos(pos) { label->setBrush(QBrush(darkLabelColor)); @@ -125,11 +125,11 @@ StatsAxis::Label::Label(const QString &name, double pos, QtCharts::QChart *chart void StatsAxis::addLabel(const QString &label, double pos) { - labels.emplace_back(label, pos, chart, labelFont); + labels.emplace_back(label, pos, scene(), labelFont); } -StatsAxis::Tick::Tick(double pos, QtCharts::QChart *chart) : - item(new QGraphicsLineItem(chart)), +StatsAxis::Tick::Tick(double pos, QGraphicsScene *scene) : + item(createItemPtr(scene)), pos(pos) { item->setPen(QPen(axisColor, axisTickWidth)); @@ -138,7 +138,7 @@ StatsAxis::Tick::Tick(double pos, QtCharts::QChart *chart) : void StatsAxis::addTick(double pos) { - ticks.emplace_back(pos, chart); + ticks.emplace_back(pos, scene()); } std::vector StatsAxis::ticksPositions() const @@ -220,8 +220,8 @@ void StatsAxis::setPos(QPointF pos) } } -ValueAxis::ValueAxis(QtCharts::QChart *chart, const QString &title, double min, double max, int decimals, bool horizontal) : - StatsAxis(chart, title, horizontal, false), +ValueAxis::ValueAxis(const QString &title, double min, double max, int decimals, bool horizontal) : + StatsAxis(title, horizontal, false), min(min), max(max), decimals(decimals) { } @@ -275,8 +275,8 @@ void ValueAxis::updateLabels() } } -CountAxis::CountAxis(QtCharts::QChart *chart, const QString &title, int count, bool horizontal) : - ValueAxis(chart, title, 0.0, (double)count, 0, horizontal), +CountAxis::CountAxis(const QString &title, int count, bool horizontal) : + ValueAxis(title, 0.0, (double)count, 0, horizontal), count(count) { } @@ -328,27 +328,31 @@ void CountAxis::updateLabels() } } -CategoryAxis::CategoryAxis(QtCharts::QChart *chart, const QString &title, const std::vector &labelsIn, bool horizontal) : - StatsAxis(chart, title, horizontal, true) +CategoryAxis::CategoryAxis(const QString &title, const std::vector &labels, bool horizontal) : + StatsAxis(title, horizontal, true), + labelsText(labels) { - labels.reserve(labelsIn.size()); - ticks.reserve(labelsIn.size() + 1); - double pos = 0.0; - addTick(-0.5); - for (const QString &s: labelsIn) { - addLabel(s, pos); - addTick(pos + 0.5); - pos += 1.0; - } - setRange(-0.5, static_cast(labelsIn.size()) - 0.5); + setRange(-0.5, static_cast(labels.size()) + 0.5); } void CategoryAxis::updateLabels() { + // TODO: paint ellipses if space too small + labels.clear(); + ticks.clear(); + labels.reserve(labelsText.size()); + ticks.reserve(labelsText.size() + 1); + double pos = 0.0; + addTick(-0.5); + for (const QString &s: labelsText) { + addLabel(s, pos); + addTick(pos + 0.5); + pos += 1.0; + } } -HistogramAxis::HistogramAxis(QtCharts::QChart *chart, const QString &title, std::vector bins, bool horizontal) : - StatsAxis(chart, title, horizontal, false), +HistogramAxis::HistogramAxis(const QString &title, std::vector bins, bool horizontal) : + StatsAxis(title, horizontal, false), bin_values(std::move(bins)) { if (bin_values.size() < 2) // Less than two makes no sense -> there must be at least one category @@ -545,7 +549,7 @@ static std::vector timeRangeToBins(double from, double to) return res; } -DateAxis::DateAxis(QtCharts::QChart *chart, const QString &title, double from, double to, bool horizontal) : - HistogramAxis(chart, title, timeRangeToBins(from, to), horizontal) +DateAxis::DateAxis(const QString &title, double from, double to, bool horizontal) : + HistogramAxis(title, timeRangeToBins(from, to), horizontal) { } diff --git a/stats/statsaxis.h b/stats/statsaxis.h index d9fdd6b41..dbcfb6fbd 100644 --- a/stats/statsaxis.h +++ b/stats/statsaxis.h @@ -11,11 +11,9 @@ #include #include -namespace QtCharts { - class QChart; -} +class QGraphicsScene; -class StatsAxis : QGraphicsLineItem { +class StatsAxis : public QGraphicsLineItem { public: virtual ~StatsAxis(); // Returns minimum and maximum of shown range, not of data points. @@ -34,13 +32,12 @@ public: std::vector ticksPositions() const; // Positions in screen coordinates protected: - StatsAxis(QtCharts::QChart *chart, const QString &title, bool horizontal, bool labelsBetweenTicks); - QtCharts::QChart *chart; + StatsAxis(const QString &title, bool horizontal, bool labelsBetweenTicks); struct Label { std::unique_ptr label; double pos; - Label(const QString &name, double pos, QtCharts::QChart *chart, const QFont &font); + Label(const QString &name, double pos, QGraphicsScene *scene, const QFont &font); }; std::vector