summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--desktop-widgets/statswidget.cpp208
-rw-r--r--desktop-widgets/statswidget.h38
-rw-r--r--desktop-widgets/statswidget.ui131
3 files changed, 377 insertions, 0 deletions
diff --git a/desktop-widgets/statswidget.cpp b/desktop-widgets/statswidget.cpp
new file mode 100644
index 000000000..874a6db15
--- /dev/null
+++ b/desktop-widgets/statswidget.cpp
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "statswidget.h"
+#include "mainwindow.h"
+#include "stats/statsview.h"
+#include <QCheckBox>
+#include <QPainter>
+#include <QStyledItemDelegate>
+
+class ChartItemDelegate : public QStyledItemDelegate {
+private:
+ void paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const override;
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
+};
+
+// Number of pixels that non-toplevel items are indented
+static int indent(const QFontMetrics &fm)
+{
+#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
+ return 4 * fm.width('-');
+#else
+ return 4 * fm.horizontalAdvance('-');
+#endif
+}
+
+static const int iconSpace = 2; // Number of pixels between icon and text
+static const int topSpace = 2; // Number of pixels above icon
+
+void ChartItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ QFont font = index.data(Qt::FontRole).value<QFont>();
+ QFontMetrics fm(font);
+ QString name = index.data(ChartListModel::ChartNameRole).value<QString>();
+ painter->setFont(font);
+ QRect rect = option.rect;
+ if (option.state & QStyle::State_Selected) {
+ painter->save();
+ painter->setBrush(option.palette.highlight());
+ painter->setPen(Qt::NoPen);
+ painter->drawRect(rect);
+ painter->restore();
+ }
+ bool isHeader = index.data(ChartListModel::IsHeaderRole).value<bool>();
+ if (!isHeader)
+ rect.translate(indent(fm), 0);
+ QPixmap icon = index.data(ChartListModel::IconRole).value<QPixmap>();
+ if (!icon.isNull()) {
+ rect.translate(0, topSpace);
+ painter->drawPixmap(rect.topLeft(), icon);
+ rect.translate(icon.size().width() + iconSpace, (icon.size().height() - fm.height()) / 2);
+ }
+
+ painter->drawText(rect, name);
+}
+
+QSize ChartItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ QFont font = index.data(Qt::FontRole).value<QFont>();
+ QFontMetrics fm(font);
+ QString name = index.data(ChartListModel::ChartNameRole).value<QString>();
+ QSize iconSize = index.data(ChartListModel::IconSizeRole).value<QSize>();
+ QSize size = fm.size(Qt::TextSingleLine, name);
+ bool isHeader = index.data(ChartListModel::IsHeaderRole).value<bool>();
+ if (!isHeader)
+ size += QSize(indent(fm), 0);
+ if (iconSize.isValid())
+ size = QSize(size.width() + iconSize.width() + iconSpace,
+ std::max(size.height(), iconSize.height()) + 2 * topSpace);
+ return size;
+}
+
+StatsWidget::StatsWidget(QWidget *parent) : QWidget(parent)
+{
+ ui.setupUi(this);
+
+ connect(ui.close, &QToolButton::clicked, this, &StatsWidget::closeStats);
+
+ ui.chartType->setModel(&charts);
+ connect(ui.chartType, QOverload<int>::of(&QComboBox::activated), this, &StatsWidget::chartTypeChanged);
+ connect(ui.var1, QOverload<int>::of(&QComboBox::activated), this, &StatsWidget::var1Changed);
+ connect(ui.var2, QOverload<int>::of(&QComboBox::activated), this, &StatsWidget::var2Changed);
+ connect(ui.var1Binner, QOverload<int>::of(&QComboBox::activated), this, &StatsWidget::var1BinnerChanged);
+ connect(ui.var2Binner, QOverload<int>::of(&QComboBox::activated), this, &StatsWidget::var2BinnerChanged);
+ connect(ui.var2Operation, QOverload<int>::of(&QComboBox::activated), this, &StatsWidget::var2OperationChanged);
+}
+
+// Initialize QComboBox with list of variables
+static void setVariableList(QComboBox *combo, const StatsState::VariableList &list)
+{
+ combo->clear();
+ for (const StatsState::Variable &v: list.variables)
+ combo->addItem(v.name, QVariant(v.id));
+ combo->setCurrentIndex(list.selected);
+}
+
+// Initialize QComboBox and QLabel of binners. Hide if there are no binners.
+static void setBinList(QLabel *label, QComboBox *combo, const QString &varName, const StatsState::BinnerList &list)
+{
+ combo->clear();
+ if (list.binners.empty()) {
+ label->hide();
+ combo->hide();
+ return;
+ }
+
+ label->show();
+ combo->show();
+
+ for (const QString &s: list.binners)
+ combo->addItem(s);
+ combo->setCurrentIndex(list.selected);
+}
+
+// Initialize QComboBox and QLabel of operations. Hide if there are no operations.
+static void setOperationList(QLabel *label, QComboBox *combo, const QString &varName, const StatsState::VariableList &list)
+{
+ combo->clear();
+ if (list.variables.empty()) {
+ label->hide();
+ combo->hide();
+ return;
+ }
+
+ label->show();
+ combo->show();
+
+ setVariableList(combo, list);
+}
+
+void StatsWidget::updateUi()
+{
+ StatsState::UIState uiState = state.getUIState();
+ setVariableList(ui.var1, uiState.var1);
+ setVariableList(ui.var2, uiState.var2);
+ int pos = charts.update(uiState.charts);
+ ui.chartType->setCurrentIndex(pos);
+ ui.chartType->setItemDelegate(new ChartItemDelegate);
+ setBinList(ui.var1BinnerLabel, ui.var1Binner, uiState.var1Name, uiState.binners1);
+ setBinList(ui.var2BinnerLabel, ui.var2Binner, uiState.var2Name, uiState.binners2);
+ setOperationList(ui.var2OperationLabel, ui.var2Operation, uiState.var2Name, uiState.operations2);
+
+ // Add checkboxes for additional features
+ features.clear();
+ for (const StatsState::Feature &f: uiState.features) {
+ features.emplace_back(new QCheckBox(f.name));
+ QCheckBox *check = features.back().get();
+ check->setChecked(f.selected);
+ int id = f.id;
+ connect(check, &QCheckBox::stateChanged, [this,id] (int state) { featureChanged(id, state); });
+ ui.features->addWidget(check);
+ }
+
+ ui.stats->plot(state);
+}
+
+void StatsWidget::closeStats()
+{
+ MainWindow::instance()->setApplicationState(ApplicationState::Default);
+}
+
+void StatsWidget::chartTypeChanged(int idx)
+{
+ state.chartChanged(ui.chartType->itemData(idx).toInt());
+ updateUi();
+}
+
+void StatsWidget::var1Changed(int idx)
+{
+ state.var1Changed(ui.var1->itemData(idx).toInt());
+ updateUi();
+}
+
+void StatsWidget::var2Changed(int idx)
+{
+ state.var2Changed(ui.var2->itemData(idx).toInt());
+ updateUi();
+}
+
+void StatsWidget::var1BinnerChanged(int idx)
+{
+ state.binner1Changed(idx);
+ updateUi();
+}
+
+void StatsWidget::var2BinnerChanged(int idx)
+{
+ state.binner2Changed(idx);
+ updateUi();
+}
+
+void StatsWidget::var2OperationChanged(int idx)
+{
+ state.var2OperationChanged(ui.var2Operation->itemData(idx).toInt());
+ updateUi();
+}
+
+void StatsWidget::featureChanged(int idx, bool status)
+{
+ state.featureChanged(idx, status);
+ updateUi();
+}
+
+void StatsWidget::showEvent(QShowEvent *e)
+{
+ updateUi();
+ QWidget::showEvent(e);
+}
diff --git a/desktop-widgets/statswidget.h b/desktop-widgets/statswidget.h
new file mode 100644
index 000000000..40e6d106c
--- /dev/null
+++ b/desktop-widgets/statswidget.h
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef STATSWIDGET_H
+#define STATSWIDGET_H
+
+#include "stats/statsstate.h"
+#include "stats/chartlistmodel.h"
+#include "ui_statswidget.h"
+#include <vector>
+#include <memory>
+
+class QCheckBox;
+
+class StatsWidget : public QWidget {
+ Q_OBJECT
+public:
+ StatsWidget(QWidget *parent = 0);
+private
+slots:
+ void closeStats();
+ void chartTypeChanged(int);
+ void var1Changed(int);
+ void var2Changed(int);
+ void var1BinnerChanged(int);
+ void var2BinnerChanged(int);
+ void var2OperationChanged(int);
+ void featureChanged(int, bool);
+private:
+ Ui::StatsWidget ui;
+ StatsState state;
+ void updateUi();
+ std::vector<std::unique_ptr<QCheckBox>> features;
+
+ ChartListModel charts;
+ //QStringListModel charts;
+ void showEvent(QShowEvent *) override;
+};
+
+#endif // STATSWIDGET_H
diff --git a/desktop-widgets/statswidget.ui b/desktop-widgets/statswidget.ui
new file mode 100644
index 000000000..684b0fa58
--- /dev/null
+++ b/desktop-widgets/statswidget.ui
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>StatsWidget</class>
+ <widget class="QWidget" name="Statistics">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>555</width>
+ <height>848</height>
+ </rect>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="headerLayout">
+ <item>
+ <widget class="QToolButton" name="close">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ <property name="icon">
+ <iconset><normaloff>:filter-close</normaloff>:filter-close</iconset>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="var1Group">
+ <property name="title">
+ <string>Base variable</string>
+ </property>
+ <layout class="QVBoxLayout" name="var1Layout">
+ <item>
+ <widget class="QComboBox" name="var1" />
+ </item>
+ <item>
+ <widget class="QLabel" name="var1BinnerLabel">
+ <property name="text">
+ <string>Binning</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="var1Binner" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="var2Group">
+ <property name="title">
+ <string>Data</string>
+ </property>
+ <layout class="QVBoxLayout" name="var2Layout">
+ <item>
+ <widget class="QComboBox" name="var2" />
+ </item>
+ <item>
+ <widget class="QLabel" name="var2BinnerLabel">
+ <property name="text">
+ <string>Binning</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="var2Binner" />
+ </item>
+ <item>
+ <widget class="QLabel" name="var2OperationLabel">
+ <property name="text">
+ <string>Operation</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="var2Operation" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="chartGroup">
+ <property name="title">
+ <string>Chart</string>
+ </property>
+ <layout class="QVBoxLayout" name="chartLayout">
+ <item>
+ <widget class="QComboBox" name="chartType" />
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="features" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="StatsView" name="stats">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>StatsView</class>
+ <extends>QQuickWidget</extends>
+ <header>stats/statsview.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="../subsurface.qrc"/>
+ </resources>
+ <connections/>
+</ui>