summaryrefslogtreecommitdiffstats
path: root/examples/charts/chartsgallery
diff options
context:
space:
mode:
Diffstat (limited to 'examples/charts/chartsgallery')
-rw-r--r--examples/charts/chartsgallery/CMakeLists.txt135
-rw-r--r--examples/charts/chartsgallery/areawidget.cpp51
-rw-r--r--examples/charts/chartsgallery/areawidget.h16
-rw-r--r--examples/charts/chartsgallery/barmodelmappermodel.cpp93
-rw-r--r--examples/charts/chartsgallery/barmodelmappermodel.h35
-rw-r--r--examples/charts/chartsgallery/barmodelmapperwidget.cpp100
-rw-r--r--examples/charts/chartsgallery/barmodelmapperwidget.h18
-rw-r--r--examples/charts/chartsgallery/barpercentwidget.cpp65
-rw-r--r--examples/charts/chartsgallery/barpercentwidget.h16
-rw-r--r--examples/charts/chartsgallery/barstackedwidget.cpp65
-rw-r--r--examples/charts/chartsgallery/barstackedwidget.h16
-rw-r--r--examples/charts/chartsgallery/barwidget.cpp67
-rw-r--r--examples/charts/chartsgallery/barwidget.h16
-rw-r--r--examples/charts/chartsgallery/boxplotdatareader.cpp71
-rw-r--r--examples/charts/chartsgallery/boxplotdatareader.h29
-rw-r--r--examples/charts/chartsgallery/boxplotwidget.cpp84
-rw-r--r--examples/charts/chartsgallery/boxplotwidget.h19
-rw-r--r--examples/charts/chartsgallery/callout.cpp111
-rw-r--r--examples/charts/chartsgallery/callout.h38
-rw-r--r--examples/charts/chartsgallery/calloutview.cpp113
-rw-r--r--examples/charts/chartsgallery/calloutview.h41
-rw-r--r--examples/charts/chartsgallery/calloutwidget.cpp19
-rw-r--r--examples/charts/chartsgallery/calloutwidget.h24
-rw-r--r--examples/charts/chartsgallery/candlestickdatareader.cpp58
-rw-r--r--examples/charts/chartsgallery/candlestickdatareader.h25
-rw-r--r--examples/charts/chartsgallery/candlestickwidget.cpp77
-rw-r--r--examples/charts/chartsgallery/candlestickwidget.h19
-rw-r--r--examples/charts/chartsgallery/chartsgallery.pro129
-rw-r--r--examples/charts/chartsgallery/chartsgallery.qrc10
-rw-r--r--examples/charts/chartsgallery/contentwidget.cpp62
-rw-r--r--examples/charts/chartsgallery/contentwidget.h34
-rw-r--r--examples/charts/chartsgallery/customchartwidget.cpp103
-rw-r--r--examples/charts/chartsgallery/customchartwidget.h16
-rw-r--r--examples/charts/chartsgallery/data/blue_triangle.pngbin0 -> 2220 bytes
-rw-r--r--examples/charts/chartsgallery/data/boxplot_a.txt13
-rw-r--r--examples/charts/chartsgallery/data/boxplot_b.txt13
-rw-r--r--examples/charts/chartsgallery/data/candlestick.txt24
-rw-r--r--examples/charts/chartsgallery/data/green_triangle.pngbin0 -> 1389 bytes
-rw-r--r--examples/charts/chartsgallery/data/sun_spots.txt284
-rw-r--r--examples/charts/chartsgallery/datetimeaxiswidget.cpp75
-rw-r--r--examples/charts/chartsgallery/datetimeaxiswidget.h19
-rw-r--r--examples/charts/chartsgallery/donutbreakdownchart.cpp100
-rw-r--r--examples/charts/chartsgallery/donutbreakdownchart.h25
-rw-r--r--examples/charts/chartsgallery/donutbreakdownmainslice.cpp36
-rw-r--r--examples/charts/chartsgallery/donutbreakdownmainslice.h30
-rw-r--r--examples/charts/chartsgallery/donutbreakdownwidget.cpp51
-rw-r--r--examples/charts/chartsgallery/donutbreakdownwidget.h16
-rw-r--r--examples/charts/chartsgallery/donutwidget.cpp34
-rw-r--r--examples/charts/chartsgallery/donutwidget.h16
-rw-r--r--examples/charts/chartsgallery/dynamicsplinewidget.cpp57
-rw-r--r--examples/charts/chartsgallery/dynamicsplinewidget.h34
-rw-r--r--examples/charts/chartsgallery/horizontalbarwidget.cpp67
-rw-r--r--examples/charts/chartsgallery/horizontalbarwidget.h16
-rw-r--r--examples/charts/chartsgallery/horizontalpercentbarwidget.cpp66
-rw-r--r--examples/charts/chartsgallery/horizontalpercentbarwidget.h16
-rw-r--r--examples/charts/chartsgallery/horizontalstackedbarwidget.cpp67
-rw-r--r--examples/charts/chartsgallery/horizontalstackedbarwidget.h16
-rw-r--r--examples/charts/chartsgallery/interactionschart.cpp77
-rw-r--r--examples/charts/chartsgallery/interactionschart.h34
-rw-r--r--examples/charts/chartsgallery/interactionsview.cpp34
-rw-r--r--examples/charts/chartsgallery/interactionsview.h27
-rw-r--r--examples/charts/chartsgallery/interactionswidget.cpp47
-rw-r--r--examples/charts/chartsgallery/interactionswidget.h16
-rw-r--r--examples/charts/chartsgallery/legendmarkerswidget.cpp161
-rw-r--r--examples/charts/chartsgallery/legendmarkerswidget.h35
-rw-r--r--examples/charts/chartsgallery/legendwidget.cpp285
-rw-r--r--examples/charts/chartsgallery/legendwidget.h61
-rw-r--r--examples/charts/chartsgallery/lightmarkerswidget.cpp211
-rw-r--r--examples/charts/chartsgallery/lightmarkerswidget.h53
-rw-r--r--examples/charts/chartsgallery/lineandbarwidget.cpp83
-rw-r--r--examples/charts/chartsgallery/lineandbarwidget.h16
-rw-r--r--examples/charts/chartsgallery/linewidget.cpp36
-rw-r--r--examples/charts/chartsgallery/linewidget.h16
-rw-r--r--examples/charts/chartsgallery/logaxiswidget.cpp47
-rw-r--r--examples/charts/chartsgallery/logaxiswidget.h16
-rw-r--r--examples/charts/chartsgallery/main.cpp18
-rw-r--r--examples/charts/chartsgallery/mainwidget.cpp262
-rw-r--r--examples/charts/chartsgallery/mainwidget.h75
-rw-r--r--examples/charts/chartsgallery/modeldatamodel.cpp92
-rw-r--r--examples/charts/chartsgallery/modeldatamodel.h34
-rw-r--r--examples/charts/chartsgallery/modeldatawidget.cpp95
-rw-r--r--examples/charts/chartsgallery/modeldatawidget.h17
-rw-r--r--examples/charts/chartsgallery/multiaxiswidget.cpp61
-rw-r--r--examples/charts/chartsgallery/multiaxiswidget.h16
-rw-r--r--examples/charts/chartsgallery/nesteddonutswidget.cpp105
-rw-r--r--examples/charts/chartsgallery/nesteddonutswidget.h27
-rw-r--r--examples/charts/chartsgallery/pccbrushtool.cpp83
-rw-r--r--examples/charts/chartsgallery/pccbrushtool.h37
-rw-r--r--examples/charts/chartsgallery/pcccustomslice.cpp27
-rw-r--r--examples/charts/chartsgallery/pcccustomslice.h25
-rw-r--r--examples/charts/chartsgallery/pccpentool.cpp124
-rw-r--r--examples/charts/chartsgallery/pccpentool.h43
-rw-r--r--examples/charts/chartsgallery/pccwidget.cpp398
-rw-r--r--examples/charts/chartsgallery/pccwidget.h80
-rw-r--r--examples/charts/chartsgallery/piedrilldownchart.cpp25
-rw-r--r--examples/charts/chartsgallery/piedrilldownchart.h26
-rw-r--r--examples/charts/chartsgallery/piedrilldownslice.cpp33
-rw-r--r--examples/charts/chartsgallery/piedrilldownslice.h27
-rw-r--r--examples/charts/chartsgallery/piedrilldownwidget.cpp49
-rw-r--r--examples/charts/chartsgallery/piedrilldownwidget.h16
-rw-r--r--examples/charts/chartsgallery/piewidget.cpp40
-rw-r--r--examples/charts/chartsgallery/piewidget.h16
-rw-r--r--examples/charts/chartsgallery/pointconfigurationwidget.cpp160
-rw-r--r--examples/charts/chartsgallery/pointconfigurationwidget.h37
-rw-r--r--examples/charts/chartsgallery/polarchartview.cpp93
-rw-r--r--examples/charts/chartsgallery/polarchartview.h21
-rw-r--r--examples/charts/chartsgallery/polarchartwidget.cpp110
-rw-r--r--examples/charts/chartsgallery/polarchartwidget.h18
-rw-r--r--examples/charts/chartsgallery/scatterinteractionswidget.cpp58
-rw-r--r--examples/charts/chartsgallery/scatterinteractionswidget.h25
-rw-r--r--examples/charts/chartsgallery/scatterwidget.cpp84
-rw-r--r--examples/charts/chartsgallery/scatterwidget.h16
-rw-r--r--examples/charts/chartsgallery/selectedbarwidget.cpp147
-rw-r--r--examples/charts/chartsgallery/selectedbarwidget.h27
-rw-r--r--examples/charts/chartsgallery/splinewidget.cpp38
-rw-r--r--examples/charts/chartsgallery/splinewidget.h16
-rw-r--r--examples/charts/chartsgallery/stackeddrilldownchart.cpp38
-rw-r--r--examples/charts/chartsgallery/stackeddrilldownchart.h33
-rw-r--r--examples/charts/chartsgallery/stackeddrilldownseries.cpp33
-rw-r--r--examples/charts/chartsgallery/stackeddrilldownseries.h29
-rw-r--r--examples/charts/chartsgallery/stackeddrilldownwidget.cpp91
-rw-r--r--examples/charts/chartsgallery/stackeddrilldownwidget.h16
-rw-r--r--examples/charts/chartsgallery/temperaturerecordswidget.cpp65
-rw-r--r--examples/charts/chartsgallery/temperaturerecordswidget.h16
-rw-r--r--examples/charts/chartsgallery/themewidget.cpp353
-rw-r--r--examples/charts/chartsgallery/themewidget.h50
-rw-r--r--examples/charts/chartsgallery/themewidget.ui103
127 files changed, 7633 insertions, 0 deletions
diff --git a/examples/charts/chartsgallery/CMakeLists.txt b/examples/charts/chartsgallery/CMakeLists.txt
new file mode 100644
index 00000000..b4fd03d6
--- /dev/null
+++ b/examples/charts/chartsgallery/CMakeLists.txt
@@ -0,0 +1,135 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(chartsgallery LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/charts/chartsgallery")
+
+find_package(Qt6 REQUIRED COMPONENTS Charts Core Gui Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(chartsgallery
+ areawidget.cpp areawidget.h
+ barmodelmappermodel.cpp barmodelmappermodel.h
+ barmodelmapperwidget.cpp barmodelmapperwidget.h
+ boxplotdatareader.cpp boxplotdatareader.h
+ boxplotwidget.cpp boxplotwidget.h
+ barwidget.cpp barwidget.h
+ barpercentwidget.cpp barpercentwidget.h
+ barstackedwidget.cpp barstackedwidget.h
+ callout.cpp callout.h
+ calloutwidget.cpp calloutwidget.h
+ calloutview.cpp calloutview.h
+ candlestickwidget.cpp candlestickwidget.h
+ candlestickdatareader.cpp candlestickdatareader.h
+ contentwidget.cpp contentwidget.h
+ customchartwidget.cpp customchartwidget.h
+ datetimeaxiswidget.cpp datetimeaxiswidget.h
+ donutbreakdownchart.cpp donutbreakdownchart.h
+ donutbreakdownmainslice.cpp donutbreakdownmainslice.h
+ donutbreakdownwidget.cpp donutbreakdownwidget.h
+ donutwidget.cpp donutwidget.h
+ dynamicsplinewidget.cpp dynamicsplinewidget.h
+ horizontalbarwidget.cpp horizontalbarwidget.h
+ horizontalpercentbarwidget.cpp horizontalpercentbarwidget.h
+ horizontalstackedbarwidget.cpp horizontalstackedbarwidget.h
+ interactionswidget.cpp interactionswidget.h
+ interactionsview.cpp interactionsview.h
+ interactionschart.cpp interactionschart.h
+ legendwidget.cpp legendwidget.h
+ legendmarkerswidget.cpp legendmarkerswidget.h
+ lightmarkerswidget.cpp lightmarkerswidget.h
+ lineandbarwidget.cpp lineandbarwidget.h
+ linewidget.cpp linewidget.h
+ logaxiswidget.cpp logaxiswidget.h
+ modeldatamodel.cpp modeldatamodel.h
+ modeldatawidget.cpp modeldatawidget.h
+ multiaxiswidget.cpp multiaxiswidget.h
+ nesteddonutswidget.cpp nesteddonutswidget.h
+ main.cpp
+ mainwidget.cpp mainwidget.h
+ pccpentool.cpp pccpentool.h
+ pccbrushtool.cpp pccbrushtool.h
+ pcccustomslice.cpp pcccustomslice.h
+ pccwidget.cpp pccwidget.h
+ piedrilldownchart.cpp piedrilldownchart.h
+ piedrilldownslice.cpp piedrilldownslice.h
+ piedrilldownwidget.cpp piedrilldownwidget.h
+ piewidget.cpp piewidget.h
+ pointconfigurationwidget.cpp pointconfigurationwidget.h
+ polarchartview.cpp polarchartview.h
+ polarchartwidget.cpp polarchartwidget.h
+ scatterinteractionswidget.cpp scatterinteractionswidget.h
+ scatterwidget.cpp scatterwidget.h
+ selectedbarwidget.cpp selectedbarwidget.h
+ splinewidget.cpp splinewidget.h
+ stackeddrilldownchart.cpp stackeddrilldownchart.h
+ stackeddrilldownseries.cpp stackeddrilldownseries.h
+ stackeddrilldownwidget.cpp stackeddrilldownwidget.h
+ temperaturerecordswidget.cpp temperaturerecordswidget.h
+ themewidget.cpp themewidget.h themewidget.ui
+)
+
+set_target_properties(chartsgallery PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(chartsgallery PRIVATE
+ Qt::Charts
+ Qt::Core
+ Qt::Gui
+ Qt::Widgets
+)
+
+set_source_files_properties("data/boxplot_a.txt"
+ PROPERTIES QT_RESOURCE_ALIAS "boxplot_a"
+)
+
+set_source_files_properties("data/boxplot_b.txt"
+ PROPERTIES QT_RESOURCE_ALIAS "boxplot_b"
+)
+
+set_source_files_properties("data/candlestick.txt"
+ PROPERTIES QT_RESOURCE_ALIAS "candlestick"
+)
+
+set_source_files_properties("data/sun_spots.txt"
+ PROPERTIES QT_RESOURCE_ALIAS "sun_spots"
+)
+
+set_source_files_properties("data/blue_triangle.png"
+ PROPERTIES QT_RESOURCE_ALIAS "blue_triangle"
+)
+
+set_source_files_properties("data/green_triangle.png"
+ PROPERTIES QT_RESOURCE_ALIAS "green_triangle"
+)
+
+set(chartsgallery_resource_files
+ "data/boxplot_a.txt"
+ "data/boxplot_b.txt"
+ "data/candlestick.txt"
+ "data/sun_spots.txt"
+ "data/blue_triangle.png"
+ "data/green_triangle.png"
+)
+
+qt6_add_resources(chartsgallery "chartsgallery"
+ PREFIX
+ "/"
+ FILES
+ ${chartsgallery_resource_files}
+)
+
+install(TARGETS chartsgallery
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/charts/chartsgallery/areawidget.cpp b/examples/charts/chartsgallery/areawidget.cpp
new file mode 100644
index 00000000..a16ef53d
--- /dev/null
+++ b/examples/charts/chartsgallery/areawidget.cpp
@@ -0,0 +1,51 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "areawidget.h"
+
+#include <QAreaSeries>
+#include <QChart>
+#include <QLineSeries>
+
+AreaWidget::AreaWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto series0 = new QLineSeries;
+ auto series1 = new QLineSeries;
+ //![1]
+
+ //![2]
+ *series0 << QPointF(1, 5) << QPointF(3, 7) << QPointF(7, 6) << QPointF(9, 7) << QPointF(12, 6)
+ << QPointF(16, 7) << QPointF(18, 5);
+ *series1 << QPointF(1, 3) << QPointF(3, 4) << QPointF(7, 3) << QPointF(8, 2) << QPointF(12, 3)
+ << QPointF(16, 4) << QPointF(18, 3);
+ //![2]
+
+ //![3]
+ auto series = new QAreaSeries(series0, series1);
+ series->setName("Batman");
+ QPen pen(0x059605);
+ pen.setWidth(3);
+ series->setPen(pen);
+
+ QLinearGradient gradient(QPointF(0, 0), QPointF(0, 1));
+ gradient.setColorAt(0.0, 0x3cc63c);
+ gradient.setColorAt(1.0, 0x26f626);
+ gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
+ series->setBrush(gradient);
+ //![3]
+
+ //![4]
+ auto chart = new QChart;
+ chart->addSeries(series);
+ chart->setTitle("Simple Area Chart");
+ chart->createDefaultAxes();
+ chart->axes(Qt::Horizontal).first()->setRange(0, 20);
+ chart->axes(Qt::Vertical).first()->setRange(0, 10);
+ //![4]
+
+ //![5]
+ createDefaultChartView(chart);
+ //![5]
+}
diff --git a/examples/charts/chartsgallery/areawidget.h b/examples/charts/chartsgallery/areawidget.h
new file mode 100644
index 00000000..201659c9
--- /dev/null
+++ b/examples/charts/chartsgallery/areawidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef AREAWIDGET_H
+#define AREAWIDGET_H
+
+#include "contentwidget.h"
+
+class AreaWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit AreaWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/barmodelmappermodel.cpp b/examples/charts/chartsgallery/barmodelmappermodel.cpp
new file mode 100644
index 00000000..294d85fe
--- /dev/null
+++ b/examples/charts/chartsgallery/barmodelmappermodel.cpp
@@ -0,0 +1,93 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "barmodelmappermodel.h"
+
+#include <QColor>
+#include <QList>
+#include <QRandomGenerator>
+#include <QRect>
+
+BarModelMapperModel::BarModelMapperModel(QObject *parent) :
+ QAbstractTableModel(parent)
+{
+ m_columnCount = 6;
+ m_rowCount = 12;
+
+ for (int i = 0; i < m_rowCount; i++) {
+ auto dataList = new QList<qreal>(m_columnCount);
+ for (int k = 0; k < dataList->size(); k++) {
+ if (k % 2 == 0)
+ dataList->replace(k, i * 50 + QRandomGenerator::global()->bounded(20));
+ else
+ dataList->replace(k, QRandomGenerator::global()->bounded(100));
+ }
+ m_data.append(dataList);
+ }
+}
+
+BarModelMapperModel::~BarModelMapperModel()
+{
+ qDeleteAll(m_data);
+}
+
+int BarModelMapperModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return m_data.count();
+}
+
+int BarModelMapperModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return m_columnCount;
+}
+
+QVariant BarModelMapperModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ if (orientation == Qt::Horizontal)
+ return QString("201%1").arg(section);
+ else
+ return QString("%1").arg(section + 1);
+}
+
+QVariant BarModelMapperModel::data(const QModelIndex &index, int role) const
+{
+ if (role == Qt::DisplayRole) {
+ return m_data[index.row()]->at(index.column());
+ } else if (role == Qt::EditRole) {
+ return m_data[index.row()]->at(index.column());
+ } else if (role == Qt::BackgroundRole) {
+ for (const QRect &rect : m_mapping) {
+ if (rect.contains(index.column(), index.row()))
+ return QColor(m_mapping.key(rect));
+ }
+
+ // cell not mapped return white color
+ return QColor(Qt::white);
+ }
+ return QVariant();
+}
+
+bool BarModelMapperModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (index.isValid() && role == Qt::EditRole) {
+ m_data[index.row()]->replace(index.column(), value.toDouble());
+ emit dataChanged(index, index);
+ return true;
+ }
+ return false;
+}
+
+Qt::ItemFlags BarModelMapperModel::flags(const QModelIndex &index) const
+{
+ return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
+}
+
+void BarModelMapperModel::addMapping(QString color, QRect area)
+{
+ m_mapping.insert(color, area);
+}
diff --git a/examples/charts/chartsgallery/barmodelmappermodel.h b/examples/charts/chartsgallery/barmodelmappermodel.h
new file mode 100644
index 00000000..84d4664e
--- /dev/null
+++ b/examples/charts/chartsgallery/barmodelmappermodel.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef BARMODELMAPPERMODEL_H
+#define BARMODELMAPPERMODEL_H
+
+#include <QAbstractTableModel>
+#include <QMultiHash>
+#include <QRect>
+
+class BarModelMapperModel : public QAbstractTableModel
+{
+ Q_OBJECT
+public:
+ explicit BarModelMapperModel(QObject *parent = nullptr);
+ virtual ~BarModelMapperModel();
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+
+ void addMapping(QString color, QRect area);
+ void clearMapping() { m_mapping.clear(); }
+
+private:
+ QList<QList<qreal> *> m_data;
+ QMultiHash<QString, QRect> m_mapping;
+ int m_columnCount;
+ int m_rowCount;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/barmodelmapperwidget.cpp b/examples/charts/chartsgallery/barmodelmapperwidget.cpp
new file mode 100644
index 00000000..1d73fe17
--- /dev/null
+++ b/examples/charts/chartsgallery/barmodelmapperwidget.cpp
@@ -0,0 +1,100 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "barmodelmappermodel.h"
+#include "barmodelmapperwidget.h"
+
+#include <QBarCategoryAxis>
+#include <QBarSeries>
+#include <QBarSet>
+#include <QChart>
+#include <QChartView>
+#include <QGraphicsLayout>
+#include <QGridLayout>
+#include <QHeaderView>
+#include <QLineSeries>
+#include <QTableView>
+#include <QValueAxis>
+#include <QVBarModelMapper>
+#include <QVXYModelMapper>
+
+BarModelMapperWidget::BarModelMapperWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ // create simple model for storing user's data
+ //! [1]
+ auto model = new BarModelMapperModel(this);
+ //! [1]
+
+ //! [2]
+ // create table view and add model to it
+ auto tableView = new QTableView(this);
+ tableView->setModel(model);
+ tableView->setMinimumWidth(300);
+ tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+ tableView->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+ model->setParent(tableView);
+ //! [2]
+
+ //! [3]
+ auto chart = new QChart;
+ chart->setAnimationOptions(QChart::AllAnimations);
+ //! [3]
+
+ chart->layout()->setContentsMargins(0, 0, 0, 0);
+
+ // series 1
+ //! [4]
+ auto series = new QBarSeries;
+
+ int first = 3;
+ int count = 5;
+ auto mapper = new QVBarModelMapper(this);
+ mapper->setFirstBarSetColumn(1);
+ mapper->setLastBarSetColumn(4);
+ mapper->setFirstRow(first);
+ mapper->setRowCount(count);
+ mapper->setSeries(series);
+ mapper->setModel(model);
+ chart->addSeries(series);
+ //! [4]
+
+ //! [5]
+ // for storing color hex from the series
+ QString seriesColorHex = "#000000";
+
+ // get the color of the series and use it for showing the mapped area
+ QList<QBarSet *> barsets = series->barSets();
+ for (int i = 0; i < barsets.count(); i++) {
+ seriesColorHex = "#" + QString::number(barsets.at(i)->brush().color().rgb(), 16).right(6).toUpper();
+ model->addMapping(seriesColorHex, QRect(1 + i, first, 1, barsets.at(i)->count()));
+ }
+ //! [5]
+
+ //! [6]
+ QStringList categories {"April", "May", "June", "July", "August"};
+ auto axisX = new QBarCategoryAxis;
+ axisX->append(categories);
+ chart->addAxis(axisX, Qt::AlignBottom);
+ series->attachAxis(axisX);
+ auto axisY = new QValueAxis;
+ chart->addAxis(axisY, Qt::AlignLeft);
+ series->attachAxis(axisY);
+ //! [6]
+
+ //! [7]
+ auto chartView = new QChartView(chart, this);
+ chartView->setRenderHint(QPainter::Antialiasing);
+ //! [7]
+
+ //! [8]
+ // create main layout
+ auto mainLayout = new QGridLayout;
+ mainLayout->setHorizontalSpacing(10);
+ mainLayout->addWidget(tableView, 1, 0);
+ mainLayout->addWidget(chartView, 1, 1);
+ mainLayout->setColumnStretch(1, 1);
+ mainLayout->setColumnStretch(0, 0);
+ setLayout(mainLayout);
+ //! [8]
+}
diff --git a/examples/charts/chartsgallery/barmodelmapperwidget.h b/examples/charts/chartsgallery/barmodelmapperwidget.h
new file mode 100644
index 00000000..17b4eb58
--- /dev/null
+++ b/examples/charts/chartsgallery/barmodelmapperwidget.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef BARMODELMAPPERWIDGET_H
+#define BARMODELMAPPERWIDGET_H
+
+#include "contentwidget.h"
+
+QT_FORWARD_DECLARE_CLASS(QChartView)
+
+class BarModelMapperWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ BarModelMapperWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/barpercentwidget.cpp b/examples/charts/chartsgallery/barpercentwidget.cpp
new file mode 100644
index 00000000..d9f2fcb1
--- /dev/null
+++ b/examples/charts/chartsgallery/barpercentwidget.cpp
@@ -0,0 +1,65 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "barpercentwidget.h"
+
+#include <QBarCategoryAxis>
+#include <QBarSet>
+#include <QChart>
+#include <QLegend>
+#include <QPercentBarSeries>
+#include <QValueAxis>
+
+BarPercentWidget::BarPercentWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto set0 = new QBarSet("Jane");
+ auto set1 = new QBarSet("John");
+ auto set2 = new QBarSet("Axel");
+ auto set3 = new QBarSet("Mary");
+ auto set4 = new QBarSet("Samantha");
+
+ *set0 << 1 << 2 << 3 << 4 << 5 << 6;
+ *set1 << 5 << 0 << 0 << 4 << 0 << 7;
+ *set2 << 3 << 5 << 8 << 13 << 8 << 5;
+ *set3 << 5 << 6 << 7 << 3 << 4 << 5;
+ *set4 << 9 << 7 << 5 << 3 << 1 << 2;
+ //![1]
+
+ //![2]
+ auto series = new QPercentBarSeries;
+ series->append(set0);
+ series->append(set1);
+ series->append(set2);
+ series->append(set3);
+ series->append(set4);
+ //![2]
+
+ //![3]
+ auto chart = new QChart;
+ chart->addSeries(series);
+ chart->setTitle("Simple Percent Bar Chart");
+ chart->setAnimationOptions(QChart::SeriesAnimations);
+ //![3]
+
+ //![4]
+ QStringList categories {"Jan", "Feb", "Mar", "Apr", "May", "Jun"};
+ auto axisX = new QBarCategoryAxis;
+ axisX->append(categories);
+ chart->addAxis(axisX, Qt::AlignBottom);
+ series->attachAxis(axisX);
+ auto axisY = new QValueAxis;
+ chart->addAxis(axisY, Qt::AlignLeft);
+ series->attachAxis(axisY);
+ //![4]
+
+ //![5]
+ chart->legend()->setVisible(true);
+ chart->legend()->setAlignment(Qt::AlignBottom);
+ //![5]
+
+ //![6]
+ createDefaultChartView(chart);
+ //![6]
+}
diff --git a/examples/charts/chartsgallery/barpercentwidget.h b/examples/charts/chartsgallery/barpercentwidget.h
new file mode 100644
index 00000000..4372f278
--- /dev/null
+++ b/examples/charts/chartsgallery/barpercentwidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef BARPERCENTWIDGET_H
+#define BARPERCENTWIDGET_H
+
+#include "contentwidget.h"
+
+class BarPercentWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit BarPercentWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/barstackedwidget.cpp b/examples/charts/chartsgallery/barstackedwidget.cpp
new file mode 100644
index 00000000..6dc377e1
--- /dev/null
+++ b/examples/charts/chartsgallery/barstackedwidget.cpp
@@ -0,0 +1,65 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "barstackedwidget.h"
+
+#include <QBarCategoryAxis>
+#include <QBarSet>
+#include <QChart>
+#include <QLegend>
+#include <QStackedBarSeries>
+#include <QValueAxis>
+
+BarStackedWidget::BarStackedWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto set0 = new QBarSet("Jane");
+ auto set1 = new QBarSet("John");
+ auto set2 = new QBarSet("Axel");
+ auto set3 = new QBarSet("Mary");
+ auto set4 = new QBarSet("Samantha");
+
+ *set0 << 1 << 2 << 3 << 4 << 5 << 6;
+ *set1 << 5 << 0 << 0 << 4 << 0 << 7;
+ *set2 << 3 << 5 << 8 << 13 << 8 << 5;
+ *set3 << 5 << 6 << 7 << 3 << 4 << 5;
+ *set4 << 9 << 7 << 5 << 3 << 1 << 2;
+ //![1]
+
+ //![2]
+ auto series = new QStackedBarSeries;
+ series->append(set0);
+ series->append(set1);
+ series->append(set2);
+ series->append(set3);
+ series->append(set4);
+ //![2]
+
+ //![3]
+ auto chart = new QChart;
+ chart->addSeries(series);
+ chart->setTitle("Simple Stacked Bar Chart");
+ chart->setAnimationOptions(QChart::SeriesAnimations);
+ //![3]
+
+ //![4]
+ QStringList categories {"Jan", "Feb", "Mar", "Apr", "May", "Jun"};
+ auto axisX = new QBarCategoryAxis;
+ axisX->append(categories);
+ chart->addAxis(axisX, Qt::AlignBottom);
+ series->attachAxis(axisX);
+ auto axisY = new QValueAxis;
+ chart->addAxis(axisY, Qt::AlignLeft);
+ series->attachAxis(axisY);
+ //![4]
+
+ //![5]
+ chart->legend()->setVisible(true);
+ chart->legend()->setAlignment(Qt::AlignBottom);
+ //![5]
+
+ //![6]
+ createDefaultChartView(chart);
+ //![6]
+}
diff --git a/examples/charts/chartsgallery/barstackedwidget.h b/examples/charts/chartsgallery/barstackedwidget.h
new file mode 100644
index 00000000..c40941c1
--- /dev/null
+++ b/examples/charts/chartsgallery/barstackedwidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef BARSTACKEDWIDGET_H
+#define BARSTACKEDWIDGET_H
+
+#include "contentwidget.h"
+
+class BarStackedWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit BarStackedWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/barwidget.cpp b/examples/charts/chartsgallery/barwidget.cpp
new file mode 100644
index 00000000..78430cd1
--- /dev/null
+++ b/examples/charts/chartsgallery/barwidget.cpp
@@ -0,0 +1,67 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "barwidget.h"
+
+#include <QBarCategoryAxis>
+#include <QBarSeries>
+#include <QBarSet>
+#include <QChart>
+#include <QLegend>
+#include <QValueAxis>
+
+BarWidget::BarWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto set0 = new QBarSet("Jane");
+ auto set1 = new QBarSet("John");
+ auto set2 = new QBarSet("Axel");
+ auto set3 = new QBarSet("Mary");
+ auto set4 = new QBarSet("Samantha");
+
+ *set0 << 1 << 2 << 3 << 4 << 5 << 6;
+ *set1 << 5 << 0 << 0 << 4 << 0 << 7;
+ *set2 << 3 << 5 << 8 << 13 << 8 << 5;
+ *set3 << 5 << 6 << 7 << 3 << 4 << 5;
+ *set4 << 9 << 7 << 5 << 3 << 1 << 2;
+ //![1]
+
+ //![2]
+ QBarSeries *series = new QBarSeries;
+ series->append(set0);
+ series->append(set1);
+ series->append(set2);
+ series->append(set3);
+ series->append(set4);
+ //![2]
+
+ //![3]
+ auto chart = new QChart;
+ chart->addSeries(series);
+ chart->setTitle("Simple Bar Chart");
+ chart->setAnimationOptions(QChart::SeriesAnimations);
+ //![3]
+
+ //![4]
+ QStringList categories {"Jan", "Feb", "Mar", "Apr", "May", "Jun"};
+ auto axisX = new QBarCategoryAxis;
+ axisX->append(categories);
+ chart->addAxis(axisX, Qt::AlignBottom);
+ series->attachAxis(axisX);
+
+ auto axisY = new QValueAxis;
+ axisY->setRange(0,15);
+ chart->addAxis(axisY, Qt::AlignLeft);
+ series->attachAxis(axisY);
+ //![4]
+
+ //![5]
+ chart->legend()->setVisible(true);
+ chart->legend()->setAlignment(Qt::AlignBottom);
+ //![5]
+
+ //![6]
+ createDefaultChartView(chart);
+ //![6]
+}
diff --git a/examples/charts/chartsgallery/barwidget.h b/examples/charts/chartsgallery/barwidget.h
new file mode 100644
index 00000000..0de1785b
--- /dev/null
+++ b/examples/charts/chartsgallery/barwidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef BARWIDGET_H
+#define BARWIDGET_H
+
+#include "contentwidget.h"
+
+class BarWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit BarWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/boxplotdatareader.cpp b/examples/charts/chartsgallery/boxplotdatareader.cpp
new file mode 100644
index 00000000..47172704
--- /dev/null
+++ b/examples/charts/chartsgallery/boxplotdatareader.cpp
@@ -0,0 +1,71 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "boxplotdatareader.h"
+
+#include <QBoxSet>
+
+#include <algorithm>
+
+BoxPlotDataReader::BoxPlotDataReader(QIODevice *device)
+ : m_textStream(device)
+{
+}
+
+void BoxPlotDataReader::readFile(QIODevice *device)
+{
+ m_textStream.setDevice(device);
+}
+
+bool BoxPlotDataReader::atEnd() const
+{
+ return m_textStream.atEnd();
+}
+
+QBoxSet *BoxPlotDataReader::readBox()
+{
+ //! [1]
+ QString line = m_textStream.readLine();
+ if (line.startsWith("#"))
+ return nullptr;
+ //! [1]
+
+ //! [2]
+ QStringList strList = line.split(QLatin1Char(' '), Qt::SkipEmptyParts);
+ //! [2]
+
+ //! [3]
+ m_sortedList.clear();
+ for (int i = 1; i < strList.count(); i++)
+ m_sortedList.append(strList.at(i).toDouble());
+
+ std::sort(m_sortedList.begin(), m_sortedList.end());
+ //! [3]
+
+ int count = m_sortedList.count();
+
+ //! [4]
+ auto box = new QBoxSet(strList.first());
+ box->setValue(QBoxSet::LowerExtreme, m_sortedList.first());
+ box->setValue(QBoxSet::UpperExtreme, m_sortedList.last());
+ box->setValue(QBoxSet::Median, findMedian(0, count));
+ box->setValue(QBoxSet::LowerQuartile, findMedian(0, count / 2));
+ box->setValue(QBoxSet::UpperQuartile, findMedian(count / 2 + (count % 2), count));
+ //! [4]
+
+ return box;
+}
+
+qreal BoxPlotDataReader::findMedian(int begin, int end)
+{
+ //! [5]
+ int count = end - begin;
+ if (count % 2) {
+ return m_sortedList.at(count / 2 + begin);
+ } else {
+ qreal right = m_sortedList.at(count / 2 + begin);
+ qreal left = m_sortedList.at(count / 2 - 1 + begin);
+ return (right + left) / 2.0;
+ }
+ //! [5]
+}
diff --git a/examples/charts/chartsgallery/boxplotdatareader.h b/examples/charts/chartsgallery/boxplotdatareader.h
new file mode 100644
index 00000000..253b05ee
--- /dev/null
+++ b/examples/charts/chartsgallery/boxplotdatareader.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef BOXPLOTDATAREADER_H
+#define BOXPLOTDATAREADER_H
+
+#include <QList>
+#include <QTextStream>
+
+QT_FORWARD_DECLARE_CLASS(QBoxSet)
+
+class BoxPlotDataReader
+{
+public:
+ explicit BoxPlotDataReader(QIODevice *device);
+
+ QBoxSet *readBox();
+ void readFile(QIODevice *device);
+ bool atEnd() const;
+
+protected:
+ qreal findMedian(int begin, int end);
+
+private:
+ QList<qreal> m_sortedList;
+ QTextStream m_textStream;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/boxplotwidget.cpp b/examples/charts/chartsgallery/boxplotwidget.cpp
new file mode 100644
index 00000000..c2ca2936
--- /dev/null
+++ b/examples/charts/chartsgallery/boxplotwidget.cpp
@@ -0,0 +1,84 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "boxplotdatareader.h"
+#include "boxplotwidget.h"
+
+#include <QBarCategoryAxis>
+#include <QBoxPlotSeries>
+#include <QBoxSet>
+#include <QChart>
+#include <QFile>
+#include <QLegend>
+
+BoxPlotWidget::BoxPlotWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+}
+
+bool BoxPlotWidget::doLoad()
+{
+ //! [1]
+ auto acmeSeries = new QBoxPlotSeries;
+ acmeSeries->setName("Acme Ltd");
+
+ auto boxWhiskSeries = new QBoxPlotSeries;
+ boxWhiskSeries->setName("BoxWhisk Inc");
+ //! [1]
+
+ //! [2]
+ QFile acmeData(":boxplot_a");
+ const QString errorTemplate = QStringLiteral("Failed to load '%1' file.");
+ if (!acmeData.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ m_loadError = errorTemplate.arg(acmeData.fileName());
+ return false;
+ }
+
+ BoxPlotDataReader dataReader(&acmeData);
+ while (!dataReader.atEnd()) {
+ QBoxSet *set = dataReader.readBox();
+ if (set)
+ acmeSeries->append(set);
+ }
+ //! [2]
+
+ //! [3]
+ QFile boxwhiskData(":boxplot_b");
+ if (!boxwhiskData.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ m_loadError = errorTemplate.arg(acmeData.fileName());
+ return false;
+ }
+
+ dataReader.readFile(&boxwhiskData);
+ while (!dataReader.atEnd()) {
+ QBoxSet *set = dataReader.readBox();
+ if (set)
+ boxWhiskSeries->append(set);
+ }
+ //! [3]
+
+ //! [4]
+ auto chart = new QChart;
+ chart->addSeries(acmeSeries);
+ chart->addSeries(boxWhiskSeries);
+ chart->setTitle("Acme Ltd. and BoxWhisk Inc. share deviation in 2012");
+ chart->setAnimationOptions(QChart::SeriesAnimations);
+ //! [4]
+
+ //! [5]
+ chart->createDefaultAxes();
+ chart->axes(Qt::Vertical).first()->setMin(15.0);
+ chart->axes(Qt::Horizontal).first()->setMax(34.0);
+ //! [5]
+
+ //! [6]
+ chart->legend()->setVisible(true);
+ chart->legend()->setAlignment(Qt::AlignBottom);
+ //! [6]
+
+ //! [7]
+ createDefaultChartView(chart);
+ //! [7]
+
+ return true;
+}
diff --git a/examples/charts/chartsgallery/boxplotwidget.h b/examples/charts/chartsgallery/boxplotwidget.h
new file mode 100644
index 00000000..b498d438
--- /dev/null
+++ b/examples/charts/chartsgallery/boxplotwidget.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef BOXPLOTWIDGET_H
+#define BOXPLOTWIDGET_H
+
+#include "contentwidget.h"
+
+class BoxPlotWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit BoxPlotWidget(QWidget *parent = nullptr);
+
+protected:
+ bool doLoad() override;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/callout.cpp b/examples/charts/chartsgallery/callout.cpp
new file mode 100644
index 00000000..2169286c
--- /dev/null
+++ b/examples/charts/chartsgallery/callout.cpp
@@ -0,0 +1,111 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "callout.h"
+
+#include <QChart>
+#include <QFontMetrics>
+#include <QGraphicsSceneMouseEvent>
+#include <QMouseEvent>
+#include <QPainter>
+
+Callout::Callout(QChart *chart)
+ : QGraphicsItem(chart)
+ , m_chart(chart)
+{
+}
+
+QRectF Callout::boundingRect() const
+{
+ QPointF anchor = mapFromParent(m_chart->mapToPosition(m_anchor));
+ QRectF rect;
+ rect.setLeft(qMin(m_rect.left(), anchor.x()));
+ rect.setRight(qMax(m_rect.right(), anchor.x()));
+ rect.setTop(qMin(m_rect.top(), anchor.y()));
+ rect.setBottom(qMax(m_rect.bottom(), anchor.y()));
+ return rect;
+}
+
+void Callout::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+ QPainterPath path;
+ path.addRoundedRect(m_rect, 5, 5);
+
+ QPointF anchor = mapFromParent(m_chart->mapToPosition(m_anchor));
+ if (!m_rect.contains(anchor) && !m_anchor.isNull()) {
+ QPointF point1, point2;
+
+ // establish the position of the anchor point in relation to m_rect
+ bool above = anchor.y() <= m_rect.top();
+ bool aboveCenter = anchor.y() > m_rect.top() && anchor.y() <= m_rect.center().y();
+ bool belowCenter = anchor.y() > m_rect.center().y() && anchor.y() <= m_rect.bottom();
+ bool below = anchor.y() > m_rect.bottom();
+
+ bool onLeft = anchor.x() <= m_rect.left();
+ bool leftOfCenter = anchor.x() > m_rect.left() && anchor.x() <= m_rect.center().x();
+ bool rightOfCenter = anchor.x() > m_rect.center().x() && anchor.x() <= m_rect.right();
+ bool onRight = anchor.x() > m_rect.right();
+
+ // get the nearest m_rect corner.
+ qreal x = (onRight + rightOfCenter) * m_rect.width();
+ qreal y = (below + belowCenter) * m_rect.height();
+ bool cornerCase = (above && onLeft) || (above && onRight) || (below && onLeft) || (below && onRight);
+ bool vertical = qAbs(anchor.x() - x) > qAbs(anchor.y() - y);
+
+ qreal x1 = x + leftOfCenter * 10 - rightOfCenter * 20 + cornerCase * !vertical * (onLeft * 10 - onRight * 20);
+ qreal y1 = y + aboveCenter * 10 - belowCenter * 20 + cornerCase * vertical * (above * 10 - below * 20);;
+ point1.setX(x1);
+ point1.setY(y1);
+
+ qreal x2 = x + leftOfCenter * 20 - rightOfCenter * 10 + cornerCase * !vertical * (onLeft * 20 - onRight * 10);;
+ qreal y2 = y + aboveCenter * 20 - belowCenter * 10 + cornerCase * vertical * (above * 20 - below * 10);;
+ point2.setX(x2);
+ point2.setY(y2);
+
+ path.moveTo(point1);
+ path.lineTo(anchor);
+ path.lineTo(point2);
+ path = path.simplified();
+ }
+ painter->setBrush(QColor(255, 255, 255));
+ painter->drawPath(path);
+ painter->drawText(m_textRect, m_text);
+}
+
+void Callout::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ event->setAccepted(true);
+}
+
+void Callout::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (event->buttons() & Qt::LeftButton){
+ setPos(mapToParent(event->pos() - event->buttonDownPos(Qt::LeftButton)));
+ event->setAccepted(true);
+ } else {
+ event->setAccepted(false);
+ }
+}
+
+void Callout::setText(const QString &text)
+{
+ m_text = text;
+ QFontMetrics metrics(m_font);
+ m_textRect = metrics.boundingRect(QRect(0, 0, 150, 150), Qt::AlignLeft, m_text);
+ m_textRect.translate(5, 5);
+ prepareGeometryChange();
+ m_rect = m_textRect.adjusted(-5, -5, 5, 5);
+}
+
+void Callout::setAnchor(QPointF point)
+{
+ m_anchor = point;
+}
+
+void Callout::updateGeometry()
+{
+ prepareGeometryChange();
+ setPos(m_chart->mapToPosition(m_anchor) + QPoint(10, -50));
+}
diff --git a/examples/charts/chartsgallery/callout.h b/examples/charts/chartsgallery/callout.h
new file mode 100644
index 00000000..27ef57cb
--- /dev/null
+++ b/examples/charts/chartsgallery/callout.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef CALLOUT_H
+#define CALLOUT_H
+
+#include <QFont>
+#include <QGraphicsItem>
+
+QT_FORWARD_DECLARE_CLASS(QChart)
+QT_FORWARD_DECLARE_CLASS(QGraphicsSceneMouseEvent)
+
+class Callout : public QGraphicsItem
+{
+public:
+ Callout(QChart *parent);
+
+ void setText(const QString &text);
+ void setAnchor(QPointF point);
+ void updateGeometry();
+
+ QRectF boundingRect() const override;
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
+
+protected:
+ void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
+
+private:
+ QString m_text;
+ QRectF m_textRect;
+ QRectF m_rect;
+ QPointF m_anchor;
+ QFont m_font;
+ QChart *m_chart = nullptr;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/calloutview.cpp b/examples/charts/chartsgallery/calloutview.cpp
new file mode 100644
index 00000000..3ea4ef39
--- /dev/null
+++ b/examples/charts/chartsgallery/calloutview.cpp
@@ -0,0 +1,113 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "callout.h"
+#include "calloutview.h"
+
+#include <QChart>
+#include <QGraphicsLayout>
+#include <QGraphicsScene>
+#include <QGraphicsTextItem>
+#include <QGraphicsView>
+#include <QLineSeries>
+#include <QMouseEvent>
+#include <QSplineSeries>
+#include <QResizeEvent>
+
+CalloutView::CalloutView(QWidget *parent)
+ : QGraphicsView(new QGraphicsScene, parent)
+{
+ setDragMode(QGraphicsView::NoDrag);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setFrameShape(QFrame::NoFrame);
+ setBackgroundRole(QPalette::Window);
+ setRenderHint(QPainter::Antialiasing);
+ setMouseTracking(true);
+
+ m_chart = new QChart;
+ m_chart->setTitle("Hover the line to show callout. Click the line to make it stay.");
+ m_chart->legend()->hide();
+
+ auto series = new QLineSeries;
+ series->append(1, 3);
+ series->append(4, 5);
+ series->append(5, 4.5);
+ series->append(7, 1);
+ series->append(11, 2);
+ m_chart->addSeries(series);
+
+ auto series2 = new QSplineSeries;
+ series2->append(1.6, 1.4);
+ series2->append(2.4, 3.5);
+ series2->append(3.7, 2.5);
+ series2->append(7, 4);
+ series2->append(10, 2);
+ m_chart->addSeries(series2);
+
+ m_chart->createDefaultAxes();
+ m_chart->setAcceptHoverEvents(true);
+
+ scene()->addItem(m_chart);
+
+ m_coordX = new QGraphicsSimpleTextItem(m_chart);
+ m_coordX->setText("X: ");
+ m_coordY = new QGraphicsSimpleTextItem(m_chart);
+ m_coordY->setText("Y: ");
+
+ connect(series, &QLineSeries::clicked, this, &CalloutView::keepCallout);
+ connect(series, &QLineSeries::hovered, this, &CalloutView::tooltip);
+
+ connect(series2, &QSplineSeries::clicked, this, &CalloutView::keepCallout);
+ connect(series2, &QSplineSeries::hovered, this, &CalloutView::tooltip);
+}
+
+CalloutView::~CalloutView()
+{
+ delete scene();
+}
+
+void CalloutView::resizeEvent(QResizeEvent *event)
+{
+ if (scene()) {
+ scene()->setSceneRect(QRect(QPoint(0, 0), event->size()));
+ m_chart->resize(event->size());
+ m_coordX->setPos(m_chart->size().width() / 2 - 70, m_chart->size().height() - 24);
+ m_coordY->setPos(m_chart->size().width() / 2 + 30, m_chart->size().height() - 24);
+ const auto callouts = m_callouts;
+ for (Callout *callout : callouts)
+ callout->updateGeometry();
+ }
+
+ resize(size());
+}
+
+void CalloutView::mouseMoveEvent(QMouseEvent *event)
+{
+ m_coordX->setText(QString("X: %1").arg(m_chart->mapToValue(event->pos()).x()));
+ m_coordY->setText(QString("Y: %1").arg(m_chart->mapToValue(event->pos()).y()));
+
+ QGraphicsView::mouseMoveEvent(event);
+}
+
+void CalloutView::keepCallout()
+{
+ m_callouts.append(m_tooltip);
+ m_tooltip = new Callout(m_chart);
+}
+
+void CalloutView::tooltip(QPointF point, bool state)
+{
+ if (!m_tooltip)
+ m_tooltip = new Callout(m_chart);
+
+ if (state) {
+ m_tooltip->setText(QString("X: %1 \nY: %2 ").arg(point.x()).arg(point.y()));
+ m_tooltip->setAnchor(point);
+ m_tooltip->setZValue(11);
+ m_tooltip->updateGeometry();
+ m_tooltip->show();
+ } else {
+ m_tooltip->hide();
+ }
+}
diff --git a/examples/charts/chartsgallery/calloutview.h b/examples/charts/chartsgallery/calloutview.h
new file mode 100644
index 00000000..866846a6
--- /dev/null
+++ b/examples/charts/chartsgallery/calloutview.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef CALLOUTVIEW_H
+#define CALLOUTVIEW_H
+
+#include <QGraphicsView>
+
+QT_FORWARD_DECLARE_CLASS(QChart)
+QT_FORWARD_DECLARE_CLASS(QGraphicsScene)
+QT_FORWARD_DECLARE_CLASS(QGraphicsSimpleTextItem)
+QT_FORWARD_DECLARE_CLASS(QGraphicsView)
+QT_FORWARD_DECLARE_CLASS(QMouseEvent)
+QT_FORWARD_DECLARE_CLASS(QResizeEvent)
+
+class Callout;
+
+class CalloutView : public QGraphicsView
+{
+ Q_OBJECT
+public:
+ CalloutView(QWidget *parent = nullptr);
+ ~CalloutView();
+
+protected:
+ void resizeEvent(QResizeEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+
+public slots:
+ void keepCallout();
+ void tooltip(QPointF point, bool state);
+
+private:
+ QGraphicsSimpleTextItem *m_coordX = nullptr;
+ QGraphicsSimpleTextItem *m_coordY = nullptr;
+ QChart *m_chart = nullptr;
+ Callout *m_tooltip = nullptr;
+ QList<Callout *> m_callouts;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/calloutwidget.cpp b/examples/charts/chartsgallery/calloutwidget.cpp
new file mode 100644
index 00000000..e3571f15
--- /dev/null
+++ b/examples/charts/chartsgallery/calloutwidget.cpp
@@ -0,0 +1,19 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "calloutview.h"
+#include "calloutwidget.h"
+
+CalloutWidget::CalloutWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ // To make mouse tracking work, we need to subclass the QGraphicsView instead of just having
+ // it as member of this class
+ m_view = new CalloutView(this);
+ m_view->resize(size());
+}
+
+void CalloutWidget::resizeEvent(QResizeEvent *)
+{
+ m_view->resize(size());
+}
diff --git a/examples/charts/chartsgallery/calloutwidget.h b/examples/charts/chartsgallery/calloutwidget.h
new file mode 100644
index 00000000..0040f4eb
--- /dev/null
+++ b/examples/charts/chartsgallery/calloutwidget.h
@@ -0,0 +1,24 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef CALLOUTWIDGET_H
+#define CALLOUTWIDGET_H
+
+#include "contentwidget.h"
+
+class CalloutView;
+
+class CalloutWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ CalloutWidget(QWidget *parent = nullptr);
+
+protected:
+ void resizeEvent(QResizeEvent *) override;
+
+private:
+ CalloutView *m_view;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/candlestickdatareader.cpp b/examples/charts/chartsgallery/candlestickdatareader.cpp
new file mode 100644
index 00000000..3913e3bd
--- /dev/null
+++ b/examples/charts/chartsgallery/candlestickdatareader.cpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "candlestickdatareader.h"
+
+#include <QCandlestickSet>
+
+CandlestickDataReader::CandlestickDataReader(QIODevice *device)
+ : m_textStream(device)
+{
+}
+
+CandlestickDataReader::~CandlestickDataReader()
+{
+}
+
+void CandlestickDataReader::readFile(QIODevice *device)
+{
+ m_textStream.setDevice(device);
+}
+
+QCandlestickSet *CandlestickDataReader::readCandlestickSet()
+{
+ //! [1]
+ QString line = m_textStream.readLine();
+ if (line.startsWith("#") || line.isEmpty())
+ return nullptr;
+ //! [1]
+
+ //! [2]
+ QStringList strList = line.split(QLatin1Char(' '), Qt::SkipEmptyParts);
+ if (strList.count() != 5)
+ return nullptr;
+ //! [2]
+
+ //! [3]
+ const qreal timestamp = strList.at(0).toDouble();
+ const qreal open = strList.at(1).toDouble();
+ const qreal high = strList.at(2).toDouble();
+ const qreal low = strList.at(3).toDouble();
+ const qreal close = strList.at(4).toDouble();
+ //! [3]
+
+ //! [4]
+ auto candlestickSet = new QCandlestickSet(timestamp);
+ candlestickSet->setOpen(open);
+ candlestickSet->setHigh(high);
+ candlestickSet->setLow(low);
+ candlestickSet->setClose(close);
+ //! [4]
+
+ return candlestickSet;
+}
+
+bool CandlestickDataReader::atEnd() const
+{
+ return m_textStream.atEnd();
+}
diff --git a/examples/charts/chartsgallery/candlestickdatareader.h b/examples/charts/chartsgallery/candlestickdatareader.h
new file mode 100644
index 00000000..f7ee316d
--- /dev/null
+++ b/examples/charts/chartsgallery/candlestickdatareader.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef CANDLESTICKDATAREADER_H
+#define CANDLESTICKDATAREADER_H
+
+#include <QTextStream>
+
+QT_FORWARD_DECLARE_CLASS(QCandlestickSet)
+
+class CandlestickDataReader
+{
+public:
+ explicit CandlestickDataReader(QIODevice *device);
+ ~CandlestickDataReader();
+
+ void readFile(QIODevice *device);
+ QCandlestickSet *readCandlestickSet();
+ bool atEnd() const;
+
+private:
+ QTextStream m_textStream;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/candlestickwidget.cpp b/examples/charts/chartsgallery/candlestickwidget.cpp
new file mode 100644
index 00000000..f21037c9
--- /dev/null
+++ b/examples/charts/chartsgallery/candlestickwidget.cpp
@@ -0,0 +1,77 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "candlestickdatareader.h"
+#include "candlestickwidget.h"
+
+#include <QBarCategoryAxis>
+#include <QCandlestickSeries>
+#include <QCandlestickSet>
+#include <QChart>
+#include <QDateTime>
+#include <QFile>
+#include <QLegend>
+#include <QValueAxis>
+
+CandleStickWidget::CandleStickWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+}
+
+bool CandleStickWidget::doLoad()
+{
+ //! [1]
+ auto acmeSeries = new QCandlestickSeries;
+ acmeSeries->setName("Acme Ltd");
+ acmeSeries->setIncreasingColor(QColor(Qt::green));
+ acmeSeries->setDecreasingColor(QColor(Qt::red));
+ //! [1]
+
+ //! [2]
+ QFile acmeData(":candlestick");
+ if (!acmeData.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ m_loadError = QStringLiteral("Failed to load '%1' file.").arg(acmeData.fileName());
+ return false;
+ }
+
+ QStringList categories;
+
+ CandlestickDataReader dataReader(&acmeData);
+ while (!dataReader.atEnd()) {
+ QCandlestickSet *set = dataReader.readCandlestickSet();
+ if (set) {
+ acmeSeries->append(set);
+ categories << QDateTime::fromMSecsSinceEpoch(set->timestamp()).toString("dd");
+ }
+ }
+ //! [2]
+
+ //! [3]
+ auto chart = new QChart;
+ chart->addSeries(acmeSeries);
+ chart->setTitle("Acme Ltd. Historical Data (July 2015)");
+ chart->setAnimationOptions(QChart::SeriesAnimations);
+ //! [3]
+
+ //! [4]
+ chart->createDefaultAxes();
+
+ auto axisX = qobject_cast<QBarCategoryAxis *>(chart->axes(Qt::Horizontal).at(0));
+ axisX->setCategories(categories);
+
+ auto axisY = qobject_cast<QValueAxis *>(chart->axes(Qt::Vertical).at(0));
+ axisY->setMax(axisY->max() * 1.01);
+ axisY->setMin(axisY->min() * 0.99);
+ //! [4]
+
+ //! [5]
+ chart->legend()->setVisible(true);
+ chart->legend()->setAlignment(Qt::AlignBottom);
+ //! [5]
+
+ //! [6]
+ createDefaultChartView(chart);
+ //! [6]
+
+ return true;
+}
diff --git a/examples/charts/chartsgallery/candlestickwidget.h b/examples/charts/chartsgallery/candlestickwidget.h
new file mode 100644
index 00000000..05bfac4e
--- /dev/null
+++ b/examples/charts/chartsgallery/candlestickwidget.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef CANDLESTICKWIDGET_H
+#define CANDLESTICKWIDGET_H
+
+#include "contentwidget.h"
+
+class CandleStickWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit CandleStickWidget(QWidget *parent = nullptr);
+
+protected:
+ bool doLoad() override;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/chartsgallery.pro b/examples/charts/chartsgallery/chartsgallery.pro
new file mode 100644
index 00000000..b362ffad
--- /dev/null
+++ b/examples/charts/chartsgallery/chartsgallery.pro
@@ -0,0 +1,129 @@
+QT += charts
+
+HEADERS += \
+ areawidget.h \
+ barmodelmappermodel.h \
+ barmodelmapperwidget.h \
+ boxplotdatareader.h \
+ boxplotwidget.h \
+ barwidget.h \
+ barpercentwidget.h \
+ barstackedwidget.h \
+ callout.h \
+ calloutwidget.h \
+ calloutview.h \
+ candlestickwidget.h \
+ candlestickdatareader.h \
+ contentwidget.h \
+ customchartwidget.h \
+ datetimeaxiswidget.h \
+ donutbreakdownchart.h \
+ donutbreakdownmainslice.h \
+ donutbreakdownwidget.h \
+ donutwidget.h \
+ dynamicsplinewidget.h \
+ horizontalbarwidget.h \
+ horizontalpercentbarwidget.h \
+ horizontalstackedbarwidget.h \
+ interactionswidget.h \
+ interactionsview.h \
+ interactionschart.h \
+ legendwidget.h \
+ legendmarkerswidget.h \
+ lightmarkerswidget.h \
+ lineandbarwidget.h \
+ linewidget.h \
+ logaxiswidget.h \
+ modeldatamodel.h \
+ modeldatawidget.h \
+ multiaxiswidget.h \
+ nesteddonutswidget.h \
+ mainwidget.h \
+ pccpentool.h \
+ pccbrushtool.h \
+ pcccustomslice.h \
+ pccwidget.h \
+ piedrilldownchart.h \
+ piedrilldownslice.h \
+ piedrilldownwidget.h \
+ piewidget.h \
+ pointconfigurationwidget.h \
+ polarchartview.h \
+ polarchartwidget.h \
+ scatterinteractionswidget.h \
+ scatterwidget.h \
+ selectedbarwidget.h \
+ splinewidget.h \
+ stackeddrilldownchart.h \
+ stackeddrilldownseries.h \
+ stackeddrilldownwidget.h \
+ temperaturerecordswidget.h \
+ themewidget.h
+
+SOURCES += \
+ areawidget.cpp \
+ barmodelmappermodel.cpp \
+ barmodelmapperwidget.cpp \
+ boxplotdatareader.cpp \
+ boxplotwidget.cpp \
+ barwidget.cpp \
+ barpercentwidget.cpp \
+ barstackedwidget.cpp \
+ callout.cpp \
+ calloutwidget.cpp \
+ calloutview.cpp \
+ candlestickwidget.cpp \
+ candlestickdatareader.cpp \
+ contentwidget.cpp \
+ customchartwidget.cpp \
+ datetimeaxiswidget.cpp \
+ donutbreakdownchart.cpp \
+ donutbreakdownmainslice.cpp \
+ donutbreakdownwidget.cpp \
+ donutwidget.cpp \
+ dynamicsplinewidget.cpp \
+ horizontalbarwidget.cpp \
+ horizontalpercentbarwidget.cpp \
+ horizontalstackedbarwidget.cpp \
+ interactionswidget.cpp \
+ interactionsview.cpp \
+ interactionschart.cpp \
+ legendwidget.cpp \
+ legendmarkerswidget.cpp \
+ lightmarkerswidget.cpp \
+ lineandbarwidget.cpp \
+ linewidget.cpp \
+ logaxiswidget.cpp \
+ main.cpp \
+ modeldatamodel.cpp \
+ modeldatawidget.cpp \
+ multiaxiswidget.cpp \
+ nesteddonutswidget.cpp \
+ mainwidget.cpp \
+ pccpentool.cpp \
+ pccbrushtool.cpp \
+ pcccustomslice.cpp \
+ pccwidget.cpp \
+ piedrilldownchart.cpp \
+ piedrilldownslice.cpp \
+ piedrilldownwidget.cpp \
+ piewidget.cpp \
+ pointconfigurationwidget.cpp \
+ polarchartview.cpp \
+ polarchartwidget.cpp \
+ scatterinteractionswidget.cpp \
+ scatterwidget.cpp \
+ selectedbarwidget.cpp \
+ splinewidget.cpp \
+ stackeddrilldownchart.cpp \
+ stackeddrilldownseries.cpp \
+ stackeddrilldownwidget.cpp \
+ temperaturerecordswidget.cpp \
+ themewidget.cpp
+
+RESOURCES += chartsgallery.qrc
+
+FORMS += themewidget.ui
+
+target.path = $$[QT_INSTALL_EXAMPLES]/charts/chartsgallery
+INSTALLS += target
diff --git a/examples/charts/chartsgallery/chartsgallery.qrc b/examples/charts/chartsgallery/chartsgallery.qrc
new file mode 100644
index 00000000..016e2241
--- /dev/null
+++ b/examples/charts/chartsgallery/chartsgallery.qrc
@@ -0,0 +1,10 @@
+<RCC>
+ <qresource prefix="/">
+ <file alias="boxplot_a">data/boxplot_a.txt</file>
+ <file alias="boxplot_b">data/boxplot_b.txt</file>
+ <file alias="candlestick">data/candlestick.txt</file>
+ <file alias="sun_spots">data/sun_spots.txt</file>
+ <file alias="blue_triangle">data/blue_triangle.png</file>
+ <file alias="green_triangle">data/green_triangle.png</file>
+ </qresource>
+</RCC>
diff --git a/examples/charts/chartsgallery/contentwidget.cpp b/examples/charts/chartsgallery/contentwidget.cpp
new file mode 100644
index 00000000..06ea8314
--- /dev/null
+++ b/examples/charts/chartsgallery/contentwidget.cpp
@@ -0,0 +1,62 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "contentwidget.h"
+
+#include <QChart>
+#include <QChartView>
+#include <QFont>
+#include <QLabel>
+#include <QVBoxLayout>
+
+ContentWidget::ContentWidget(QWidget *parent)
+ : QWidget(parent)
+{
+}
+
+void ContentWidget::load()
+{
+ if (m_loaded || layout())
+ return;
+
+ if (!doLoad()) {
+ auto errorLabel = new QLabel(this);
+ auto errorLayout = new QVBoxLayout(this);
+ errorLabel->setText(tr("Error loading the example:\n%1").arg(m_loadError));
+ QFont font = errorLabel->font();
+ font.setPointSize(20);
+ errorLabel->setFont(font);
+ errorLabel->setAlignment(Qt::AlignCenter);
+ errorLayout->addWidget(errorLabel);
+ setLayout(errorLayout);
+ }
+
+ m_loaded = true;
+}
+
+bool ContentWidget::doLoad()
+{
+ // Most examples do their initialization in constructor.
+ // Only those that can fail and show error message need to reimplement this method.
+ return true;
+}
+
+void ContentWidget::resizeEvent(QResizeEvent *)
+{
+ if (m_defaultChartView)
+ m_defaultChartView->resize(size());
+}
+
+// Most examples are simple and need only basic chart view widget, so provide it in this base class
+// to avoid duplicating code
+void ContentWidget::createDefaultChartView(QChart *chart)
+{
+ m_defaultChartView = new QChartView(chart, this);
+ m_defaultChartView->setRenderHint(QPainter::Antialiasing);
+}
+
+void ContentWidget::setDefaultChartView(QChartView *view)
+{
+ m_defaultChartView = view;
+ m_defaultChartView->setRenderHint(QPainter::Antialiasing);
+}
diff --git a/examples/charts/chartsgallery/contentwidget.h b/examples/charts/chartsgallery/contentwidget.h
new file mode 100644
index 00000000..780877a5
--- /dev/null
+++ b/examples/charts/chartsgallery/contentwidget.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef CONTENTWIDGET_H
+#define CONTENTWIDGET_H
+
+#include <QWidget>
+
+QT_FORWARD_DECLARE_CLASS(QChart)
+QT_FORWARD_DECLARE_CLASS(QChartView)
+
+class ContentWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit ContentWidget(QWidget *parent = nullptr);
+
+ void load();
+
+protected:
+ virtual bool doLoad();
+ void resizeEvent(QResizeEvent *) override;
+ void createDefaultChartView(QChart *chart);
+ QChartView *defaultChartView() const { return m_defaultChartView; }
+ void setDefaultChartView(QChartView *view);
+
+ QString m_loadError;
+
+private:
+ QChartView *m_defaultChartView = nullptr;
+ bool m_loaded = false;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/customchartwidget.cpp b/examples/charts/chartsgallery/customchartwidget.cpp
new file mode 100644
index 00000000..dbe4ba6b
--- /dev/null
+++ b/examples/charts/chartsgallery/customchartwidget.cpp
@@ -0,0 +1,103 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "customchartwidget.h"
+
+#include <QCategoryAxis>
+#include <QChart>
+#include <QLineSeries>
+
+CustomChartWidget::CustomChartWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto series = new QLineSeries;
+ *series << QPointF(0, 6) << QPointF(9, 4) << QPointF(15, 20) << QPointF(25, 12) << QPointF(29, 26);
+ auto chart = new QChart;
+ chart->legend()->hide();
+ chart->addSeries(series);
+ //![1]
+
+ //![2]
+ // Customize series
+ QPen pen(QRgb(0xfdb157));
+ pen.setWidth(5);
+ series->setPen(pen);
+
+ // Customize chart title
+ QFont font;
+ font.setPixelSize(18);
+ chart->setTitleFont(font);
+ chart->setTitleBrush(QBrush(Qt::white));
+ chart->setTitle("Custom Chart");
+
+ // Customize chart background
+ QLinearGradient backgroundGradient;
+ backgroundGradient.setStart(QPointF(0, 0));
+ backgroundGradient.setFinalStop(QPointF(0, 1));
+ backgroundGradient.setColorAt(0.0, QRgb(0xd2d0d1));
+ backgroundGradient.setColorAt(1.0, QRgb(0x4c4547));
+ backgroundGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
+ chart->setBackgroundBrush(backgroundGradient);
+
+ // Customize plot area background
+ QLinearGradient plotAreaGradient;
+ plotAreaGradient.setStart(QPointF(0, 1));
+ plotAreaGradient.setFinalStop(QPointF(1, 0));
+ plotAreaGradient.setColorAt(0.0, QRgb(0x555555));
+ plotAreaGradient.setColorAt(1.0, QRgb(0x55aa55));
+ plotAreaGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
+ chart->setPlotAreaBackgroundBrush(plotAreaGradient);
+ chart->setPlotAreaBackgroundVisible(true);
+ //![2]
+
+ //![3]
+ auto axisX = new QCategoryAxis;
+ auto axisY = new QCategoryAxis;
+
+ // Customize axis label font
+ QFont labelsFont;
+ labelsFont.setPixelSize(12);
+ axisX->setLabelsFont(labelsFont);
+ axisY->setLabelsFont(labelsFont);
+
+ // Customize axis colors
+ QPen axisPen(QRgb(0xd18952));
+ axisPen.setWidth(2);
+ axisX->setLinePen(axisPen);
+ axisY->setLinePen(axisPen);
+
+ // Customize axis label colors
+ QBrush axisBrush(Qt::white);
+ axisX->setLabelsBrush(axisBrush);
+ axisY->setLabelsBrush(axisBrush);
+
+ // Customize grid lines and shades
+ axisX->setGridLineVisible(false);
+ axisY->setGridLineVisible(false);
+ axisY->setShadesPen(Qt::NoPen);
+ axisY->setShadesBrush(QBrush(QColor(0x99, 0xcc, 0xcc, 0x55)));
+ axisY->setShadesVisible(true);
+ //![3]
+
+ //![4]
+ axisX->append("low", 10);
+ axisX->append("optimal", 20);
+ axisX->append("high", 30);
+ axisX->setRange(0, 30);
+
+ axisY->append("slow", 10);
+ axisY->append("med", 20);
+ axisY->append("fast", 30);
+ axisY->setRange(0, 30);
+
+ chart->addAxis(axisX, Qt::AlignBottom);
+ chart->addAxis(axisY, Qt::AlignLeft);
+ series->attachAxis(axisX);
+ series->attachAxis(axisY);
+ //![4]
+
+ //![5]
+ createDefaultChartView(chart);
+ //![5]
+}
diff --git a/examples/charts/chartsgallery/customchartwidget.h b/examples/charts/chartsgallery/customchartwidget.h
new file mode 100644
index 00000000..dd8db49d
--- /dev/null
+++ b/examples/charts/chartsgallery/customchartwidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef CUSTOMCHARTWIDGET_H
+#define CUSTOMCHARTWIDGET_H
+
+#include "contentwidget.h"
+
+class CustomChartWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit CustomChartWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/data/blue_triangle.png b/examples/charts/chartsgallery/data/blue_triangle.png
new file mode 100644
index 00000000..7790453c
--- /dev/null
+++ b/examples/charts/chartsgallery/data/blue_triangle.png
Binary files differ
diff --git a/examples/charts/chartsgallery/data/boxplot_a.txt b/examples/charts/chartsgallery/data/boxplot_a.txt
new file mode 100644
index 00000000..9511418d
--- /dev/null
+++ b/examples/charts/chartsgallery/data/boxplot_a.txt
@@ -0,0 +1,13 @@
+# Acme Ltd share deviation in 2012
+Jan 27.74 27.28 27.86 28.05 28.64 27.47 28.30 28.22 28.72 26.50 26.62 26.50 26.15 26.47 26.41 25.78 24.82 24.89 24.88 24.60 23.85
+Feb 31.79 30.62 30.67 31.37 31.16 31.22 32.02 32.70 31.60 31.24 30.98 30.79 31.10 30.79 31.53 30.92 30.00 30.58 30.37 29.40 28.60
+Mar 28.64 28.34 29.13 29.43 30.75 29.77 29.72 30.52 31.12 33.05 32.51 32.69 31.83 32.47 31.41 31.39 31.78 30.08 29.46 31.58 31.39 31.41
+Apr 25.96 26.62 26.19 30.37 28.78 27.50 28.90 28.40 28.86 28.90 27.91 27.32 27.99 26.86 26.68 27.57 27.50 28.96 28.50
+May 20.85 21.08 21.98 21.61 21.45 21.73 21.71 22.27 21.14 20.65 21.95 22.23 23.17 24.26 24.17 22.97 23.53 24.49 24.51 25.46 25.65
+Jun 18.08 17.19 17.36 17.21 17.31 18.19 18.30 17.53 17.35 17.80 17.17 16.95 18.25 20.52 20.61 21.40 20.45 19.43 19.11 19.74
+Jul 17.75 18.24 17.57 16.53 15.98 16.06 16.64 17.69 17.91 18.00 18.03 18.14 18.10 17.86 18.12 18.53 18.43 18.30 19.03 18.76 18.79 18.33
+Aug 18.69 18.54 18.39 18.49 18.96 18.72 19.25 19.70 20.13 19.74 19.27 18.25 17.72 18.02 18.20 18.24 18.60 18.22 18.60 17.98 17.27 16.70 17.19
+Sep 18.35 18.82 18.96 19.96 19.75 20.55 20.68 21.19 21.14 21.48 21.45 20.74 20.97 20.18 19.66 19.54 18.89 18.39 18.26 18.86
+Oct 16.95 16.80 16.45 16.89 17.38 17.12 16.85 17.59 17.65 17.46 17.43 17.30 17.87 18.61 18.55 18.59 19.27 19.54 20.02 19.23 18.05 18.52 18.71
+Now 19.36 19.29 18.22 18.74 19.05 19.13 18.67 18.19 17.94 18.04 17.49 17.53 17.64 18.00 18.21 18.19 18.30 18.11 18.17 17.76 17.80 17.52
+Dec 19.95 20.19 20.15 20.42 20.39 20.65 20.39 19.86 19.48 19.70 19.94 19.82 20.25 20.21 19.63 19.55
diff --git a/examples/charts/chartsgallery/data/boxplot_b.txt b/examples/charts/chartsgallery/data/boxplot_b.txt
new file mode 100644
index 00000000..f1d49cf0
--- /dev/null
+++ b/examples/charts/chartsgallery/data/boxplot_b.txt
@@ -0,0 +1,13 @@
+# BoxWhisk Inc share deviation in 2012
+Jan 25.74 25.28 25.86 26.05 26.64 28.47 28.30 29.22 29.72 27.50 25.62 25.50 25.15 26.47 27.41 25.78 24.82 24.89 24.88 24.60 23.85
+Feb 30.79 29.62 29.67 30.37 30.16 30.22 31.02 33.70 32.60 32.24 31.98 31.79 31.10 30.79 31.53 30.92 29.00 29.58 30.37 29.40 28.60
+Mar 29.64 29.34 30.13 30.43 31.75 30.77 30.72 31.52 32.12 33.75 33.51 33.69 32.83 32.47 32.41 32.39 32.78 31.08 29.46 31.58 31.39 31.41
+Apr 24.96 25.62 25.19 28.37 28.78 26.50 25.90 26.40 26.86 26.90 27.91 27.32 27.99 26.86 26.68 27.57 27.50 26.96 26.50
+May 21.85 21.08 22.98 22.61 22.45 21.73 21.71 23.27 22.14 19.65 22.95 21.23 23.17 24.26 24.17 21.97 22.53 25.49 25.51 26.46 26.65
+Jun 15.08 15.19 15.36 15.21 15.31 18.19 18.30 15.53 15.35 15.80 15.17 16.95 18.25 20.52 20.61 20.40 20.45 19.43 19.11 19.74
+Jul 17.75 18.24 17.57 16.53 15.98 16.06 16.64 17.69 17.91 19.00 19.03 19.14 19.10 17.86 19.12 19.53 19.43 19.30 19.03 19.76 18.79 18.33
+Aug 19.69 19.54 19.39 19.49 19.96 19.72 20.25 20.70 21.13 20.74 20.27 19.25 18.72 19.02 19.20 19.24 19.60 19.22 19.60 18.98 18.27 17.70 18.19
+Sep 19.35 19.82 19.96 20.96 20.75 21.55 21.68 22.19 22.14 22.48 22.45 21.74 21.97 21.18 20.66 20.54 19.89 19.39 19.26 19.86
+Oct 17.95 17.80 17.45 17.89 18.38 18.12 17.85 18.59 18.65 18.46 18.43 18.30 18.87 19.61 19.55 19.59 20.27 20.54 21.02 20.23 19.05 19.52 19.71
+Now 20.36 20.29 19.22 19.74 20.05 20.13 19.67 19.19 18.94 19.04 18.49 18.53 18.64 19.00 19.21 19.19 19.30 19.11 19.17 18.76 18.80 18.52
+Dec 22.95 22.19 22.15 21.42 21.39 21.65 22.39 20.86 20.48 20.70 20.94 20.82 19.25 21.21 19.63 20.55
diff --git a/examples/charts/chartsgallery/data/candlestick.txt b/examples/charts/chartsgallery/data/candlestick.txt
new file mode 100644
index 00000000..eaac318c
--- /dev/null
+++ b/examples/charts/chartsgallery/data/candlestick.txt
@@ -0,0 +1,24 @@
+# Acme Ltd Historical Data (July 2015)
+# timestamp, open, high, low, close
+1435708800000 126.90 126.94 125.99 126.60
+1435795200000 126.69 126.69 126.69 126.69
+1436140800000 124.85 126.23 124.85 126.00
+1436227200000 125.89 126.15 123.77 125.69
+1436313600000 124.64 124.64 122.54 122.54
+1436400000000 123.85 124.06 119.22 120.07
+1436486400000 121.94 123.85 121.21 123.28
+1436745600000 125.03 125.76 124.32 125.66
+1436832000000 126.04 126.37 125.04 125.61
+1436918400000 125.72 127.15 125.58 126.82
+1437004800000 127.74 128.57 127.35 128.51
+1437091200000 129.08 129.62 128.31 129.62
+1437350400000 130.97 132.97 130.70 132.07
+1437436800000 132.85 132.92 130.32 130.75
+1437523200000 121.99 125.50 121.99 125.22
+1437609600000 126.20 127.09 125.06 125.16
+1437696000000 125.32 125.74 123.90 124.50
+1437955200000 123.09 123.61 122.12 122.77
+1438041600000 123.38 123.91 122.55 123.38
+1438128000000 123.15 123.50 122.27 122.99
+1438214400000 122.32 122.57 121.71 122.37
+1438300800000 122.60 122.64 120.91 121.30
diff --git a/examples/charts/chartsgallery/data/green_triangle.png b/examples/charts/chartsgallery/data/green_triangle.png
new file mode 100644
index 00000000..29ae043f
--- /dev/null
+++ b/examples/charts/chartsgallery/data/green_triangle.png
Binary files differ
diff --git a/examples/charts/chartsgallery/data/sun_spots.txt b/examples/charts/chartsgallery/data/sun_spots.txt
new file mode 100644
index 00000000..91ef5982
--- /dev/null
+++ b/examples/charts/chartsgallery/data/sun_spots.txt
@@ -0,0 +1,284 @@
+:Recent_Solar_Indices: RecentIndices.txt
+:Created: 2012 Aug 06 0759 UTC
+# Prepared by the U.S. Dept. of Commerce, NOAA, Space Weather Prediction Center (SWPC).
+# Please send comments and suggestions to swpc.webmaster@noaa.gov
+#
+# Source SWO: SWPC Space Weather Operations (SWO).
+# Source RI: S.I.D.C. Brussels International Sunspot Number.
+# Source 10.7cm radio flux values (sfu): Penticton, B.C., Canada.
+#
+# Source Ap: GeoForschungsZentrum, Postdam, Germany
+# Prior to January 1997, Institut fur Geophysik, Gottingen, Germany
+# Source Ap for final month is NOAA/SWPC estimated Ap.
+#
+# Data not yet available or not calculable: -1.0
+#
+# Values for most recent 6 months are considered preliminary.
+# Final values from National Geophysical Data Center www.ngdc.noaa.gov
+#
+# Recent Solar Indices
+# of Observed Monthly Mean Values
+#
+# -----------Sunspot Numbers--------- ----Radio Flux--- ---Geomagnetic---
+# ---Observed---- Ratio --Smoothed- Observed Smoothed Observed Smoothed
+# YR MO SWO RI RI/SW SWO RI 10.7cm 10.7cm Ap Ap
+#-------------------------------------------------------------------------------
+1991 01 213.5 136.9 0.64 220.5 147.6 229.4 205.5 8 17.4
+1991 02 270.2 167.5 0.62 221.5 147.6 243.0 206.3 10 18.4
+1991 03 227.9 141.9 0.62 220.7 146.6 230.0 205.9 27 19.1
+1991 04 215.9 140.0 0.65 220.7 146.5 198.8 206.8 17 20.0
+1991 05 182.5 121.3 0.66 219.6 145.5 190.3 207.1 18 21.7
+1991 06 231.8 169.7 0.73 218.9 145.2 206.8 207.4 44 23.0
+1991 07 245.7 173.7 0.71 219.5 146.3 212.0 207.7 27 23.6
+1991 08 251.5 176.3 0.70 218.3 146.6 210.3 206.8 30 24.7
+1991 09 185.8 125.3 0.67 214.2 144.9 180.6 203.9 20 25.0
+1991 10 220.1 144.1 0.65 208.4 141.7 201.3 199.7 31 24.3
+1991 11 169.0 108.2 0.64 202.2 138.1 172.0 195.4 33 24.1
+1991 12 217.7 144.4 0.66 193.7 131.7 223.9 188.9 15 23.0
+1992 01 217.9 150.0 0.69 183.3 123.7 217.6 181.8 14 21.1
+1992 02 238.2 161.1 0.68 171.8 115.4 232.1 174.8 31 19.8
+1992 03 160.5 106.7 0.66 161.6 108.2 171.3 168.5 14 19.4
+1992 04 144.0 99.8 0.69 154.3 103.3 158.5 162.9 11 18.9
+1992 05 106.3 73.8 0.69 148.9 100.3 125.4 158.9 21 17.5
+1992 06 104.7 65.2 0.62 143.3 97.1 116.7 154.3 15 16.6
+1992 07 121.4 85.7 0.71 134.3 90.7 132.2 146.7 10 16.6
+1992 08 99.5 64.5 0.65 124.4 84.0 122.1 138.9 15 16.1
+1992 09 93.8 63.9 0.68 117.5 79.5 116.8 133.8 25 15.9
+1992 10 136.2 88.7 0.65 113.4 76.4 131.7 130.5 15 16.7
+1992 11 124.3 91.8 0.74 110.4 74.4 145.2 128.2 14 16.6
+1992 12 127.4 82.6 0.65 107.7 73.2 139.1 127.4 13 16.1
+1993 01 92.1 59.3 0.64 104.5 71.4 121.0 125.7 17 16.0
+1993 02 126.1 91.0 0.72 101.2 69.3 142.6 123.1 16 15.9
+1993 03 107.4 69.8 0.65 97.0 66.6 136.4 120.7 24 15.3
+1993 04 98.6 62.2 0.63 91.9 63.6 115.9 118.1 19 14.9
+1993 05 79.1 61.3 0.77 86.2 59.9 112.4 114.8 12 14.9
+1993 06 68.5 49.8 0.73 81.0 56.1 109.3 111.3 12 15.0
+1993 07 81.6 57.9 0.71 78.7 54.7 99.0 109.6 10 14.9
+1993 08 59.4 42.2 0.71 75.7 52.3 93.7 107.6 12 15.4
+1993 09 33.5 22.4 0.67 70.7 48.4 87.0 103.9 15 16.0
+1993 10 73.5 56.4 0.77 65.5 44.9 100.3 100.4 14 16.4
+1993 11 51.0 35.6 0.70 60.8 41.2 95.9 97.5 15 17.4
+1993 12 75.9 48.9 0.64 57.9 38.4 104.8 94.8 14 18.1
+1994 01 86.4 57.8 0.67 55.6 36.6 115.0 92.7 15 18.2
+1994 02 60.5 35.5 0.59 53.5 34.8 99.6 91.2 30 18.1
+1994 03 52.4 31.7 0.60 52.9 34.1 90.4 90.2 24 17.8
+1994 04 29.3 16.1 0.55 53.0 33.7 79.1 89.3 29 18.0
+1994 05 35.4 17.8 0.50 51.9 32.5 79.9 88.1 26 18.3
+1994 06 42.6 28.0 0.66 49.6 30.8 77.3 86.4 14 18.2
+1994 07 52.7 35.1 0.67 46.1 28.5 80.5 83.9 11 18.1
+1994 08 38.4 22.5 0.59 43.8 26.8 76.1 82.0 8 17.5
+1994 09 40.5 25.7 0.63 43.4 26.6 79.0 81.2 12 16.5
+1994 10 67.1 44.0 0.66 43.2 26.5 87.7 80.9 22 15.5
+1994 11 33.0 18.0 0.55 42.5 26.2 80.9 80.6 14 14.7
+1994 12 38.7 26.2 0.68 41.4 25.6 77.4 80.4 13 14.2
+1995 01 39.8 24.2 0.61 39.6 24.2 82.7 80.1 14 14.0
+1995 02 51.3 29.9 0.58 37.8 23.0 85.6 79.7 15 13.9
+1995 03 51.9 31.1 0.60 36.3 22.1 85.1 79.3 15 14.0
+1995 04 23.6 14.0 0.59 33.8 20.6 77.7 78.6 16 13.8
+1995 05 24.6 14.5 0.59 31.6 19.2 75.5 77.9 18 13.3
+1995 06 27.8 15.6 0.56 29.9 18.2 75.7 77.4 11 12.9
+1995 07 23.8 14.5 0.61 28.1 17.0 73.9 76.9 8 12.5
+1995 08 25.1 14.3 0.57 25.4 15.4 73.8 76.0 9 12.1
+1995 09 16.5 11.8 0.72 22.0 13.4 72.0 74.8 13 11.8
+1995 10 31.6 21.1 0.67 19.7 12.1 77.9 73.8 16 11.4
+1995 11 15.7 9.0 0.57 18.5 11.3 74.2 73.2 9 10.7
+1995 12 16.2 10.0 0.62 17.6 10.8 72.6 72.8 9 10.0
+1996 01 17.6 11.5 0.65 16.8 10.4 74.5 72.4 9 9.7
+1996 02 9.1 4.4 0.48 16.2 10.1 71.5 72.2 10 9.7
+1996 03 12.1 9.2 0.76 15.4 9.7 70.7 72.1 11 9.8
+1996 04 8.5 4.8 0.56 13.6 8.4 69.3 71.6 11 9.7
+1996 05 11.8 5.5 0.47 12.9 8.0 70.1 71.4 7 9.5
+1996 06 18.8 11.8 0.63 13.5 8.5 69.6 71.8 5 9.4
+1996 07 13.2 8.2 0.62 13.4 8.4 71.2 72.0 7 9.3
+1996 08 20.5 14.4 0.70 13.1 8.3 72.4 72.1 9 9.4
+1996 09 2.9 1.6 0.55 13.3 8.4 69.4 72.3 15 9.3
+1996 10 2.3 0.9 0.39 14.0 8.8 69.2 72.6 13 9.1
+1996 11 26.7 17.9 0.67 15.4 9.8 78.7 73.0 8 9.1
+1996 12 21.1 13.3 0.63 16.2 10.4 77.8 73.3 7 9.3
+1997 01 9.0 5.7 0.63 16.5 10.5 74.0 73.4 9 9.3
+1997 02 11.3 7.6 0.67 17.4 11.0 73.8 73.7 11 9.2
+1997 03 14.4 8.7 0.60 20.4 13.5 73.5 75.1 8 8.9
+1997 04 24.5 15.5 0.63 24.0 16.5 74.5 76.8 10 8.5
+1997 05 28.6 18.5 0.65 26.4 18.4 74.6 78.4 8 8.5
+1997 06 22.1 12.7 0.57 29.0 20.4 71.7 80.1 7 8.5
+1997 07 17.0 10.4 0.61 32.4 22.7 71.1 81.8 6 8.4
+1997 08 36.7 24.4 0.66 35.9 25.1 79.0 83.4 7 8.2
+1997 09 58.2 51.3 0.88 40.5 28.4 96.2 85.7 10 8.3
+1997 10 33.6 23.8 0.71 45.4 31.9 84.9 88.6 10 8.5
+1997 11 53.5 39.0 0.73 49.3 35.0 99.5 91.3 11 8.9
+1997 12 57.9 41.2 0.71 54.2 39.0 98.8 94.2 4 9.5
+1998 01 51.8 31.9 0.62 60.6 43.8 93.4 97.5 8 9.8
+1998 02 54.4 40.3 0.74 67.4 49.0 93.4 101.7 8 10.5
+1998 03 81.8 54.8 0.67 73.3 53.5 109.1 105.8 13 11.0
+1998 04 73.6 53.4 0.73 77.7 56.6 108.3 108.9 10 11.3
+1998 05 74.3 56.3 0.76 81.4 59.4 106.7 112.0 18 11.6
+1998 06 93.6 70.7 0.76 85.9 62.5 108.4 115.8 10 12.0
+1998 07 98.3 66.6 0.68 90.3 65.5 114.0 120.0 11 12.3
+1998 08 118.6 92.2 0.78 93.7 67.8 136.0 124.1 18 12.5
+1998 09 119.0 92.9 0.78 96.1 69.5 138.3 126.8 13 12.7
+1998 10 77.0 55.5 0.72 97.7 70.5 117.3 127.9 13 12.8
+1998 11 99.5 74.0 0.74 101.3 73.0 140.2 130.0 16 12.5
+1998 12 120.8 81.9 0.68 108.8 77.9 150.1 134.3 8 12.0
+1999 01 94.3 62.0 0.66 116.5 82.6 142.6 139.0 10 11.8
+1999 02 93.4 66.3 0.71 120.2 84.6 142.0 142.6 12 11.6
+1999 03 100.5 68.8 0.68 120.5 83.8 126.3 144.0 14 11.8
+1999 04 92.9 63.7 0.69 123.8 85.5 117.2 145.8 12 12.3
+1999 05 140.5 106.4 0.76 131.7 90.5 148.6 149.9 8 12.4
+1999 06 208.3 137.7 0.66 136.0 93.1 169.8 152.9 7 12.4
+1999 07 169.2 113.5 0.67 138.0 94.3 165.6 154.4 10 12.6
+1999 08 136.1 93.7 0.69 142.8 97.5 170.8 156.3 15 12.9
+1999 09 107.4 71.5 0.67 150.0 102.3 135.7 161.0 19 12.9
+1999 10 167.7 116.7 0.70 158.5 107.8 164.8 167.2 19 12.8
+1999 11 199.3 133.2 0.67 164.7 111.0 191.5 171.5 14 13.2
+1999 12 123.5 84.6 0.69 165.9 111.1 169.8 173.4 10 13.8
+2000 01 140.8 90.1 0.64 168.0 112.9 158.1 175.5 13 14.6
+2000 02 161.9 112.9 0.70 172.1 116.8 173.2 176.8 16 15.1
+2000 03 203.6 138.5 0.68 175.4 119.9 208.2 178.4 9 15.1
+2000 04 193.4 125.5 0.65 176.3 120.8 184.2 180.5 15 15.0
+2000 05 188.8 121.6 0.64 173.1 119.0 184.5 180.0 15 15.1
+2000 06 190.3 124.9 0.66 172.0 118.7 179.8 179.7 15 15.1
+2000 07 236.7 170.1 0.72 173.0 119.8 204.7 180.2 21 14.8
+2000 08 166.6 130.5 0.78 171.8 118.6 163.1 179.4 16 14.2
+2000 09 157.9 109.7 0.69 169.0 116.3 182.1 177.1 18 14.3
+2000 10 138.9 99.4 0.72 166.2 114.5 167.7 175.5 18 15.0
+2000 11 149.9 106.8 0.71 162.7 112.7 178.8 173.8 17 15.1
+2000 12 146.4 104.4 0.71 160.8 112.0 173.6 172.0 7 14.7
+2001 01 142.7 95.6 0.67 156.3 108.7 166.6 168.7 8 14.0
+2001 02 131.0 80.6 0.62 151.4 104.0 146.7 165.6 7 13.3
+2001 03 166.7 113.5 0.68 154.0 104.8 177.7 167.8 20 12.9
+2001 04 163.6 107.7 0.66 159.4 107.5 178.1 171.6 22 12.8
+2001 05 135.1 96.6 0.72 163.1 108.6 147.9 174.7 10 12.8
+2001 06 196.7 134.0 0.68 167.2 109.8 173.7 178.7 10 12.8
+2001 07 124.6 81.8 0.66 172.1 111.7 131.3 183.8 9 12.9
+2001 08 159.4 106.4 0.67 176.7 113.6 163.1 188.8 11 13.0
+2001 09 229.1 150.7 0.66 178.8 114.1 233.8 191.3 13 12.8
+2001 10 197.4 125.5 0.64 179.5 114.0 208.1 191.9 20 12.1
+2001 11 178.6 106.5 0.60 183.7 115.5 212.7 193.7 16 12.0
+2001 12 217.5 132.2 0.61 184.5 114.6 235.6 193.9 9 12.0
+2002 01 189.0 114.1 0.60 184.8 113.5 227.3 194.6 8 11.9
+2002 02 194.5 107.4 0.55 188.6 114.6 205.0 197.2 10 12.1
+2002 03 153.1 98.4 0.64 188.9 113.3 180.3 195.7 10 12.3
+2002 04 194.9 120.7 0.62 186.2 110.5 189.8 191.5 17 12.5
+2002 05 204.1 120.8 0.59 183.6 108.8 178.4 188.0 12 12.7
+2002 06 146.0 88.3 0.60 179.9 106.2 148.7 182.9 7 12.9
+2002 07 183.5 99.6 0.54 175.4 102.7 173.5 176.2 11 13.3
+2002 08 191.0 116.4 0.61 169.2 98.7 183.9 169.3 14 13.8
+2002 09 206.4 109.6 0.53 163.4 94.6 175.8 164.0 13 14.5
+2002 10 153.9 97.5 0.63 158.8 90.5 167.0 159.3 25 15.1
+2002 11 159.8 95.5 0.60 150.9 85.2 168.7 154.1 17 15.8
+2002 12 147.9 80.8 0.55 145.0 82.0 157.2 150.7 13 17.1
+2003 01 149.3 79.7 0.53 141.7 80.8 144.0 148.0 13 18.2
+2003 02 87.0 46.0 0.53 136.4 78.3 124.5 143.5 17 18.9
+2003 03 119.7 61.1 0.51 128.1 74.0 132.2 138.3 21 19.5
+2003 04 119.7 60.0 0.50 121.5 70.1 126.3 135.0 20 20.1
+2003 05 89.6 54.6 0.61 118.3 67.6 116.2 133.1 26 21.0
+2003 06 118.4 77.4 0.65 113.6 65.0 129.3 130.2 24 21.5
+2003 07 132.8 83.3 0.63 106.9 61.8 127.7 127.2 19 22.0
+2003 08 114.3 72.7 0.64 102.8 60.0 122.1 125.2 23 22.3
+2003 09 82.6 48.7 0.59 100.7 59.5 112.2 123.7 18 21.8
+2003 10 118.9 65.5 0.55 96.6 58.2 151.3 121.8 35 21.1
+2003 11 118.9 67.3 0.57 93.6 56.7 140.8 120.1 28 20.0
+2003 12 75.4 46.5 0.62 91.4 54.8 115.0 118.0 16 18.6
+2004 01 62.3 37.3 0.60 87.9 52.0 114.1 116.3 22 18.1
+2004 02 75.6 45.8 0.61 84.2 49.3 107.0 115.5 13 17.7
+2004 03 81.0 49.1 0.61 80.9 47.1 112.0 114.6 14 16.7
+2004 04 59.3 39.3 0.66 77.9 45.5 101.2 112.4 11 15.2
+2004 05 77.3 41.5 0.54 74.1 43.8 99.8 109.3 8 14.0
+2004 06 78.9 43.2 0.55 70.4 41.6 97.4 107.4 8 13.6
+2004 07 87.8 51.1 0.58 68.3 40.2 118.5 106.1 23 13.5
+2004 08 69.5 40.9 0.59 66.6 39.2 111.0 105.2 9 13.5
+2004 09 50.0 27.7 0.55 63.7 37.5 103.0 103.8 9 13.3
+2004 10 77.9 48.0 0.62 61.3 35.9 105.9 102.3 8 13.3
+2004 11 70.5 43.5 0.62 60.0 35.3 113.7 101.6 25 13.7
+2004 12 34.7 17.9 0.52 58.8 35.2 95.0 101.5 11 14.3
+2005 01 52.0 31.3 0.60 57.3 34.6 102.2 100.4 24 14.1
+2005 02 45.4 29.2 0.64 56.4 33.9 97.2 98.6 11 14.0
+2005 03 41.0 24.5 0.60 55.8 33.5 89.9 97.3 12 14.6
+2005 04 41.5 24.2 0.58 52.6 31.6 86.0 95.5 11 15.1
+2005 05 65.4 42.7 0.65 48.3 28.9 99.5 93.2 19 14.4
+2005 06 59.8 39.3 0.66 47.9 28.8 93.7 91.9 12 13.6
+2005 07 71.0 40.1 0.56 48.1 29.1 96.5 90.9 14 12.8
+2005 08 65.6 36.4 0.55 45.4 27.4 90.5 89.2 14 11.8
+2005 09 39.2 21.9 0.56 42.9 25.8 91.1 87.8 20 11.4
+2005 10 13.0 8.7 0.67 42.6 25.5 76.6 87.3 8 11.3
+2005 11 32.2 18.0 0.56 42.1 24.9 86.2 86.7 8 10.8
+2005 12 62.6 41.1 0.66 40.1 23.0 90.7 85.2 9 10.0
+2006 01 28.0 15.3 0.55 37.2 20.8 83.4 83.6 6 9.5
+2006 02 5.3 4.9 0.92 33.4 18.6 76.5 82.3 6 9.0
+2006 03 21.3 10.6 0.50 31.0 17.4 75.5 81.2 8 8.3
+2006 04 55.2 30.2 0.55 30.6 17.1 89.0 80.6 11 7.8
+2006 05 39.6 22.3 0.56 30.7 17.3 80.9 80.5 7 7.9
+2006 06 37.7 13.9 0.37 28.9 16.3 76.5 80.2 7 8.2
+2006 07 22.6 12.2 0.54 27.2 15.2 75.8 80.0 6 8.6
+2006 08 22.8 12.9 0.57 27.6 15.6 79.4 80.1 9 8.8
+2006 09 25.2 14.4 0.57 27.7 15.5 77.8 80.0 8 8.8
+2006 10 15.7 10.5 0.67 25.2 14.2 74.3 79.1 9 8.8
+2006 11 31.5 21.4 0.68 22.3 12.6 86.3 78.2 9 8.7
+2006 12 22.2 13.6 0.61 20.7 12.1 84.5 77.8 15 8.7
+2007 01 26.6 16.8 0.63 19.7 11.9 83.5 77.5 10 8.7
+2007 02 17.2 10.7 0.62 18.9 11.5 77.7 76.9 7 8.6
+2007 03 9.7 4.5 0.46 17.5 10.7 72.2 76.0 8 8.5
+2007 04 6.9 3.4 0.49 16.0 9.8 72.4 75.3 9 8.5
+2007 05 19.4 11.7 0.60 14.2 8.6 74.4 74.3 8 8.3
+2007 06 20.0 12.1 0.61 12.8 7.6 73.7 73.3 6 7.9
+2007 07 15.6 9.7 0.62 11.6 6.9 71.6 72.7 7 7.4
+2007 08 9.9 6.0 0.61 10.2 6.0 69.1 72.1 6 7.5
+2007 09 4.8 2.4 0.50 9.9 5.9 67.0 71.8 9 7.8
+2007 10 1.3 0.9 0.69 10.0 6.0 67.5 71.8 7 7.9
+2007 11 2.5 1.7 0.68 9.4 5.7 69.6 71.4 7 7.8
+2007 12 16.2 10.1 0.62 8.1 4.9 78.5 70.8 6 7.8
+2008 01 5.1 3.3 0.65 6.9 4.2 74.3 70.3 8 7.8
+2008 02 3.8 2.1 0.55 5.9 3.6 71.1 69.9 11 7.6
+2008 03 15.9 9.3 0.58 5.3 3.3 72.9 69.8 11 7.5
+2008 04 4.9 2.9 0.59 5.3 3.4 70.2 69.8 9 7.3
+2008 05 5.7 3.2 0.56 5.7 3.5 68.4 69.8 6 7.2
+2008 06 4.2 3.4 0.81 5.2 3.3 65.9 69.4 7 7.0
+2008 07 1.0 0.8 0.80 4.5 2.8 65.7 68.8 5 6.8
+2008 08 0.0 0.5 -1.00 4.4 2.7 66.3 68.6 5 6.3
+2008 09 1.5 1.1 0.73 3.7 2.3 67.1 68.4 6 5.8
+2008 10 5.2 2.9 0.56 2.9 1.8 68.3 68.2 7 5.4
+2008 11 6.8 4.1 0.60 2.7 1.7 68.6 68.3 4 5.1
+2008 12 1.3 0.8 0.62 2.7 1.7 69.2 68.5 4 4.9
+2009 01 2.8 1.3 0.46 3.0 1.8 69.8 68.7 4 4.7
+2009 02 2.5 1.4 0.56 3.1 1.9 70.0 68.8 5 4.7
+2009 03 0.7 0.7 1.00 3.4 2.0 69.2 69.0 5 4.6
+2009 04 1.2 0.8 1.00 3.7 2.2 69.7 69.3 4 4.3
+2009 05 3.9 2.9 0.74 3.8 2.3 70.5 69.7 4 4.1
+2009 06 6.6 2.9 0.39 4.4 2.7 68.6 70.2 4 4.0
+2009 07 5.0 3.2 0.70 5.8 3.6 68.2 71.0 4 3.9
+2009 08 0.3 0.0 0.00 7.7 4.8 67.4 72.1 5 3.8
+2009 09 6.6 4.3 0.64 9.9 6.2 70.5 73.3 4 3.8
+2009 10 7.0 4.8 0.66 11.3 7.1 72.3 74.1 3 4.1
+2009 11 7.7 4.1 0.55 12.4 7.6 73.6 74.5 3 4.5
+2009 12 15.7 10.8 0.68 13.6 8.3 76.8 74.9 2 4.8
+2010 01 21.3 13.2 0.62 14.8 9.3 81.1 75.5 3 5.0
+2010 02 31.0 18.8 0.60 16.7 10.6 84.7 76.5 5 5.1
+2010 03 24.7 15.4 0.62 19.1 12.3 83.3 77.5 5 5.3
+2010 04 11.2 8.0 0.71 21.4 14.0 75.9 78.3 10 5.5
+2010 05 19.9 8.7 0.44 23.8 15.5 73.8 79.0 8 5.7
+2010 06 17.9 13.6 0.75 25.2 16.4 72.6 79.7 7 5.8
+2010 07 23.1 16.1 0.70 25.9 16.7 79.9 80.1 5 6.0
+2010 08 28.2 19.6 0.70 27.3 17.4 79.7 80.7 8 6.2
+2010 09 35.6 25.2 0.71 30.6 19.6 81.1 82.4 5 6.3
+2010 10 35.0 23.5 0.67 35.9 23.2 81.6 85.3 6 6.4
+2010 11 36.1 21.5 0.60 40.5 26.5 82.5 87.7 5 6.4
+2010 12 22.0 14.4 0.66 43.8 28.8 84.3 89.6 4 6.5
+2011 01 32.1 18.8 0.59 47.2 30.9 83.7 91.2 6 6.7
+2011 02 53.2 29.6 0.55 50.6 33.4 94.5 92.7 6 6.8
+2011 03 81.0 55.8 0.69 55.2 36.9 115.3 95.8 7 7.2
+2011 04 81.7 54.4 0.67 61.5 41.8 112.6 100.4 9 7.5
+2011 05 61.4 41.5 0.68 69.0 47.6 95.9 105.6 9 7.5
+2011 06 55.5 37.0 0.67 76.5 53.2 95.8 110.9 8 7.4
+2011 07 67.0 43.8 0.66 82.5 57.2 94.2 115.4 9 7.3
+2011 08 66.1 50.6 0.77 84.9 59.0 101.7 117.9 8 7.4
+2011 09 106.4 78.0 0.73 84.6 59.5 134.5 118.4 13 7.7
+2011 10 116.8 88.0 0.75 84.6 59.9 137.2 118.4 7 8.0
+2011 11 133.1 96.7 0.73 86.3 61.1 153.1 119.5 3 8.0
+2011 12 106.3 73.0 0.69 89.2 63.4 141.2 121.6 3 8.0
+2012 01 91.3 58.3 0.64 92.0 65.5 133.1 124.4 6 8.3
+2012 02 50.1 32.9 0.66 -1.0 -1.0 106.7 -1.0 7 -1.0
+2012 03 77.9 64.3 0.82 -1.0 -1.0 115.1 -1.0 14 -1.0
+2012 04 84.4 55.2 0.65 -1.0 -1.0 113.1 -1.0 9 -1.0
+2012 05 99.5 69.0 0.69 -1.0 -1.0 121.5 -1.0 8 -1.0
+2012 06 88.6 64.5 0.73 -1.0 -1.0 120.5 -1.0 10 -1.0
+2012 07 99.6 66.5 0.67 -1.0 -1.0 135.6 -1.0 13 -1.0
diff --git a/examples/charts/chartsgallery/datetimeaxiswidget.cpp b/examples/charts/chartsgallery/datetimeaxiswidget.cpp
new file mode 100644
index 00000000..c71e7291
--- /dev/null
+++ b/examples/charts/chartsgallery/datetimeaxiswidget.cpp
@@ -0,0 +1,75 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "datetimeaxiswidget.h"
+
+#include <QChart>
+#include <QDateTime>
+#include <QDateTimeAxis>
+#include <QFile>
+#include <QLineSeries>
+#include <QTextStream>
+#include <QValueAxis>
+
+DateTimeAxisWidget::DateTimeAxisWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+}
+
+bool DateTimeAxisWidget::doLoad()
+{
+ //![1]
+ auto series = new QLineSeries;
+ //![1]
+
+ //![2]
+ // data from http://www.swpc.noaa.gov/ftpdir/weekly/RecentIndices.txt
+ // http://www.swpc.noaa.gov/ftpdir/weekly/README
+ // http://www.weather.gov/disclaimer
+ QFile sunSpots(":sun_spots");
+ if (!sunSpots.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ m_loadError = QStringLiteral("Failed to load '%1' file.").arg(sunSpots.fileName());
+ return false;
+ }
+
+ QTextStream stream(&sunSpots);
+ while (!stream.atEnd()) {
+ QString line = stream.readLine();
+ if (line.startsWith("#") || line.startsWith(":"))
+ continue;
+ QStringList values = line.split(QLatin1Char(' '), Qt::SkipEmptyParts);
+ QDateTime momentInTime;
+ momentInTime.setDate(QDate(values[0].toInt(), values[1].toInt() , 15));
+ series->append(momentInTime.toMSecsSinceEpoch(), values[2].toDouble());
+ }
+ sunSpots.close();
+ //![2]
+
+ //![3]
+ auto chart = new QChart;
+ chart->addSeries(series);
+ chart->legend()->hide();
+ chart->setTitle("Sunspots count (by Space Weather Prediction Center)");
+ //![3]
+
+ //![4]
+ auto axisX = new QDateTimeAxis;
+ axisX->setTickCount(10);
+ axisX->setFormat("MMM yyyy");
+ axisX->setTitleText("Date");
+ chart->addAxis(axisX, Qt::AlignBottom);
+ series->attachAxis(axisX);
+
+ auto axisY = new QValueAxis;
+ axisY->setLabelFormat("%i");
+ axisY->setTitleText("Sunspots count");
+ chart->addAxis(axisY, Qt::AlignLeft);
+ series->attachAxis(axisY);
+ //![4]
+
+ //![5]
+ createDefaultChartView(chart);
+ //![5]
+
+ return true;
+}
diff --git a/examples/charts/chartsgallery/datetimeaxiswidget.h b/examples/charts/chartsgallery/datetimeaxiswidget.h
new file mode 100644
index 00000000..1baf6df9
--- /dev/null
+++ b/examples/charts/chartsgallery/datetimeaxiswidget.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef DATETIMEAXISWIDGET_H
+#define DATETIMEAXISWIDGET_H
+
+#include "contentwidget.h"
+
+class DateTimeAxisWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit DateTimeAxisWidget(QWidget *parent = nullptr);
+
+protected:
+ bool doLoad() override;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/donutbreakdownchart.cpp b/examples/charts/chartsgallery/donutbreakdownchart.cpp
new file mode 100644
index 00000000..7faf09e4
--- /dev/null
+++ b/examples/charts/chartsgallery/donutbreakdownchart.cpp
@@ -0,0 +1,100 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "donutbreakdownchart.h"
+#include "donutbreakdownmainslice.h"
+
+#include <QPieLegendMarker>
+#include <QPieSeries>
+#include <QPieSlice>
+
+QT_USE_NAMESPACE
+
+//![1]
+DonutBreakdownChart::DonutBreakdownChart(QGraphicsItem *parent, Qt::WindowFlags wFlags)
+ : QChart(QChart::ChartTypeCartesian, parent, wFlags)
+{
+ // create the series for main center pie
+ m_mainSeries = new QPieSeries;
+ m_mainSeries->setPieSize(0.7);
+ QChart::addSeries(m_mainSeries);
+}
+//![1]
+
+//![2]
+void DonutBreakdownChart::addBreakdownSeries(QPieSeries *breakdownSeries, QColor color)
+{
+ QFont font("Arial", 8);
+
+ // add breakdown series as a slice to center pie
+ auto mainSlice = new DonutBreakdownMainSlice(breakdownSeries);
+ mainSlice->setName(breakdownSeries->name());
+ mainSlice->setValue(breakdownSeries->sum());
+ m_mainSeries->append(mainSlice);
+
+ // customize the slice
+ mainSlice->setBrush(color);
+ mainSlice->setLabelVisible();
+ mainSlice->setLabelColor(Qt::white);
+ mainSlice->setLabelPosition(QPieSlice::LabelInsideHorizontal);
+ mainSlice->setLabelFont(font);
+
+ // position and customize the breakdown series
+ breakdownSeries->setPieSize(0.8);
+ breakdownSeries->setHoleSize(0.7);
+ breakdownSeries->setLabelsVisible();
+ const auto slices = breakdownSeries->slices();
+ for (QPieSlice *slice : slices) {
+ color = color.lighter(115);
+ slice->setBrush(color);
+ slice->setLabelFont(font);
+ }
+
+ // add the series to the chart
+ QChart::addSeries(breakdownSeries);
+
+ // recalculate breakdown donut segments
+ recalculateAngles();
+
+ // update customize legend markers
+ updateLegendMarkers();
+}
+//![2]
+
+//![3]
+void DonutBreakdownChart::recalculateAngles()
+{
+ qreal angle = 0;
+ const auto slices = m_mainSeries->slices();
+ for (QPieSlice *slice : slices) {
+ QPieSeries *breakdownSeries = qobject_cast<DonutBreakdownMainSlice *>(slice)->breakdownSeries();
+ breakdownSeries->setPieStartAngle(angle);
+ angle += slice->percentage() * 360.0; // full pie is 360.0
+ breakdownSeries->setPieEndAngle(angle);
+ }
+}
+//![3]
+
+//![4]
+void DonutBreakdownChart::updateLegendMarkers()
+{
+ // go through all markers
+ const auto allseries = series();
+ for (QAbstractSeries *series : allseries) {
+ const auto markers = legend()->markers(series);
+ for (QLegendMarker *marker : markers) {
+ auto pieMarker = qobject_cast<QPieLegendMarker *>(marker);
+ if (series == m_mainSeries) {
+ // hide markers from main series
+ pieMarker->setVisible(false);
+ } else {
+ // modify markers from breakdown series
+ pieMarker->setLabel(QString("%1 %2%")
+ .arg(pieMarker->slice()->label())
+ .arg(pieMarker->slice()->percentage() * 100, 0, 'f', 2));
+ pieMarker->setFont(QFont("Arial", 8));
+ }
+ }
+ }
+}
+//![4]
diff --git a/examples/charts/chartsgallery/donutbreakdownchart.h b/examples/charts/chartsgallery/donutbreakdownchart.h
new file mode 100644
index 00000000..5cfc574e
--- /dev/null
+++ b/examples/charts/chartsgallery/donutbreakdownchart.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef DONUTBREAKDOWNCHART_H
+#define DONUTBREAKDOWNCHART_H
+
+#include <QChart>
+
+QT_FORWARD_DECLARE_CLASS(QPieSeries)
+
+class DonutBreakdownChart : public QChart
+{
+public:
+ DonutBreakdownChart(QGraphicsItem *parent = nullptr, Qt::WindowFlags wFlags = {});
+ void addBreakdownSeries(QPieSeries *series, QColor color);
+
+private:
+ void recalculateAngles();
+ void updateLegendMarkers();
+
+private:
+ QPieSeries *m_mainSeries = nullptr;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/donutbreakdownmainslice.cpp b/examples/charts/chartsgallery/donutbreakdownmainslice.cpp
new file mode 100644
index 00000000..eb0dd4cb
--- /dev/null
+++ b/examples/charts/chartsgallery/donutbreakdownmainslice.cpp
@@ -0,0 +1,36 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "donutbreakdownmainslice.h"
+
+//![1]
+DonutBreakdownMainSlice::DonutBreakdownMainSlice(QPieSeries *breakdownSeries, QObject *parent)
+ : QPieSlice(parent),
+ m_breakdownSeries(breakdownSeries)
+{
+ connect(this, &DonutBreakdownMainSlice::percentageChanged,
+ this, &DonutBreakdownMainSlice::updateLabel);
+}
+//![1]
+
+QPieSeries *DonutBreakdownMainSlice::breakdownSeries() const
+{
+ return m_breakdownSeries;
+}
+
+void DonutBreakdownMainSlice::setName(const QString &name)
+{
+ m_name = name;
+}
+
+QString DonutBreakdownMainSlice::name() const
+{
+ return m_name;
+}
+
+//![2]
+void DonutBreakdownMainSlice::updateLabel()
+{
+ setLabel(QString("%1 %2%").arg(m_name).arg(percentage() * 100, 0, 'f', 2));
+}
+//![2]
diff --git a/examples/charts/chartsgallery/donutbreakdownmainslice.h b/examples/charts/chartsgallery/donutbreakdownmainslice.h
new file mode 100644
index 00000000..f0088400
--- /dev/null
+++ b/examples/charts/chartsgallery/donutbreakdownmainslice.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef DONUTBREAKDOWNMAINSLICE_H
+#define DONUTBREAKDOWNMAINSLICE_H
+
+#include <QPieSlice>
+
+QT_FORWARD_DECLARE_CLASS(QPieSeries)
+
+class DonutBreakdownMainSlice : public QPieSlice
+{
+ Q_OBJECT
+public:
+ DonutBreakdownMainSlice(QPieSeries *breakdownSeries, QObject *parent = nullptr);
+
+ QPieSeries *breakdownSeries() const;
+
+ void setName(const QString &name);
+ QString name() const;
+
+public slots:
+ void updateLabel();
+
+private:
+ QPieSeries *m_breakdownSeries = nullptr;
+ QString m_name;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/donutbreakdownwidget.cpp b/examples/charts/chartsgallery/donutbreakdownwidget.cpp
new file mode 100644
index 00000000..63181601
--- /dev/null
+++ b/examples/charts/chartsgallery/donutbreakdownwidget.cpp
@@ -0,0 +1,51 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "donutbreakdownchart.h"
+#include "donutbreakdownwidget.h"
+
+#include <QChart>
+#include <QPieSeries>
+
+DonutBreakdownWidget::DonutBreakdownWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ // Graph is based on data of 'Total consumption of energy increased by 10 per cent in 2010'
+ // Statistics Finland, 13 December 2011
+ // http://www.stat.fi/til/ekul/2010/ekul_2010_2011-12-13_tie_001_en.html
+
+ auto series1 = new QPieSeries;
+ series1->setName("Fossil fuels");
+ series1->append("Oil", 353295);
+ series1->append("Coal", 188500);
+ series1->append("Natural gas", 148680);
+ series1->append("Peat", 94545);
+
+ auto series2 = new QPieSeries;
+ series2->setName("Renewables");
+ series2->append("Wood fuels", 319663);
+ series2->append("Hydro power", 45875);
+ series2->append("Wind power", 1060);
+
+ auto series3 = new QPieSeries;
+ series3->setName("Others");
+ series3->append("Nuclear energy", 238789);
+ series3->append("Import energy", 37802);
+ series3->append("Other", 32441);
+ //![1]
+
+ //![2]
+ auto donutBreakdown = new DonutBreakdownChart;
+ donutBreakdown->setAnimationOptions(QChart::AllAnimations);
+ donutBreakdown->setTitle("Total consumption of energy in Finland 2010");
+ donutBreakdown->legend()->setAlignment(Qt::AlignRight);
+ donutBreakdown->addBreakdownSeries(series1, Qt::red);
+ donutBreakdown->addBreakdownSeries(series2, Qt::darkGreen);
+ donutBreakdown->addBreakdownSeries(series3, Qt::darkBlue);
+ //![2]
+
+ //![3]
+ createDefaultChartView(donutBreakdown);
+ //![3]
+}
diff --git a/examples/charts/chartsgallery/donutbreakdownwidget.h b/examples/charts/chartsgallery/donutbreakdownwidget.h
new file mode 100644
index 00000000..4b2f9b43
--- /dev/null
+++ b/examples/charts/chartsgallery/donutbreakdownwidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef DONUTBREAKDOWNWIDGET_H
+#define DONUTBREAKDOWNWIDGET_H
+
+#include "contentwidget.h"
+
+class DonutBreakdownWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit DonutBreakdownWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/donutwidget.cpp b/examples/charts/chartsgallery/donutwidget.cpp
new file mode 100644
index 00000000..2bee9974
--- /dev/null
+++ b/examples/charts/chartsgallery/donutwidget.cpp
@@ -0,0 +1,34 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "donutwidget.h"
+
+#include <QChart>
+#include <QPieSeries>
+#include <QPieSlice>
+
+DonutWidget::DonutWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto series = new QPieSeries;
+ series->setHoleSize(0.35);
+ series->append("Protein 4.2%", 4.2);
+ QPieSlice *slice = series->append("Fat 15.6%", 15.6);
+ slice->setExploded();
+ slice->setLabelVisible();
+ series->append("Other 23.8%", 23.8);
+ series->append("Carbs 56.4%", 56.4);
+ //![1]
+
+ //![2]
+ auto chart = new QChart;
+ chart->setTitle("Donut with a lemon glaze (100g)");
+ chart->addSeries(series);
+ chart->legend()->setAlignment(Qt::AlignBottom);
+ chart->setTheme(QChart::ChartThemeBlueCerulean);
+ chart->legend()->setFont(QFont("Arial", 7));
+
+ createDefaultChartView(chart);
+ //![2]
+}
diff --git a/examples/charts/chartsgallery/donutwidget.h b/examples/charts/chartsgallery/donutwidget.h
new file mode 100644
index 00000000..cf27c2ae
--- /dev/null
+++ b/examples/charts/chartsgallery/donutwidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef DONUTWIDGET_H
+#define DONUTWIDGET_H
+
+#include "contentwidget.h"
+
+class DonutWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit DonutWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/dynamicsplinewidget.cpp b/examples/charts/chartsgallery/dynamicsplinewidget.cpp
new file mode 100644
index 00000000..fce79d79
--- /dev/null
+++ b/examples/charts/chartsgallery/dynamicsplinewidget.cpp
@@ -0,0 +1,57 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "dynamicsplinewidget.h"
+
+#include <QChart>
+#include <QChartView>
+#include <QRandomGenerator>
+#include <QSplineSeries>
+#include <QValueAxis>
+
+DynamicSplineWidget::DynamicSplineWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ auto chart = new QChart;
+ chart->setTitle("Dynamic Spline Chart");
+ chart->legend()->hide();
+ chart->setAnimationOptions(QChart::AllAnimations);
+
+ m_axisX = new QValueAxis;
+ m_axisY = new QValueAxis;
+
+ QObject::connect(&m_timer, &QTimer::timeout, this, &DynamicSplineWidget::handleTimeout);
+ m_timer.setInterval(1000);
+
+ m_series = new QSplineSeries;
+ QPen green(Qt::red);
+ green.setWidth(3);
+ m_series->setPen(green);
+ m_series->append(m_x, m_y);
+
+ chart->addSeries(m_series);
+
+ chart->addAxis(m_axisX,Qt::AlignBottom);
+ chart->addAxis(m_axisY,Qt::AlignLeft);
+ m_series->attachAxis(m_axisX);
+ m_series->attachAxis(m_axisY);
+ m_axisX->setTickCount(5);
+ m_axisX->setRange(0, 10);
+ m_axisY->setRange(-5, 10);
+
+ createDefaultChartView(chart);
+
+ m_timer.start();
+}
+
+void DynamicSplineWidget::handleTimeout()
+{
+ qreal x = defaultChartView()->chart()->plotArea().width() / m_axisX->tickCount();
+ qreal y = (m_axisX->max() - m_axisX->min()) / m_axisX->tickCount();
+ m_x += y;
+ m_y = QRandomGenerator::global()->bounded(5) - 2.5;
+ m_series->append(m_x, m_y);
+ defaultChartView()->chart()->scroll(x, 0);
+ if (m_x >= 100)
+ m_timer.stop();
+}
diff --git a/examples/charts/chartsgallery/dynamicsplinewidget.h b/examples/charts/chartsgallery/dynamicsplinewidget.h
new file mode 100644
index 00000000..1389280b
--- /dev/null
+++ b/examples/charts/chartsgallery/dynamicsplinewidget.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef DYNAMICSPLINEWIDGET_H
+#define DYNAMICSPLINEWIDGET_H
+
+#include "contentwidget.h"
+
+#include <QTimer>
+
+QT_FORWARD_DECLARE_CLASS(QSplineSeries)
+QT_FORWARD_DECLARE_CLASS(QValueAxis)
+
+class DynamicSplineWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit DynamicSplineWidget(QWidget *parent = nullptr);
+
+public slots:
+ void handleTimeout();
+
+private:
+ QSplineSeries *m_series = nullptr;
+ QValueAxis *m_axisX = nullptr;
+ QValueAxis *m_axisY = nullptr;
+ QTimer m_timer;
+ QStringList m_titles;
+ qreal m_step = 0.;
+ qreal m_x = 5;
+ qreal m_y = 1;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/horizontalbarwidget.cpp b/examples/charts/chartsgallery/horizontalbarwidget.cpp
new file mode 100644
index 00000000..5a903335
--- /dev/null
+++ b/examples/charts/chartsgallery/horizontalbarwidget.cpp
@@ -0,0 +1,67 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "horizontalbarwidget.h"
+
+#include <QBarCategoryAxis>
+#include <QBarSeries>
+#include <QBarSet>
+#include <QChart>
+#include <QHorizontalBarSeries>
+#include <QLegend>
+#include <QValueAxis>
+
+HorizontalBarWidget::HorizontalBarWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto set0 = new QBarSet("Jane");
+ auto set1 = new QBarSet("John");
+ auto set2 = new QBarSet("Axel");
+ auto set3 = new QBarSet("Mary");
+ auto set4 = new QBarSet("Samantha");
+
+ *set0 << 1 << 2 << 3 << 4 << 5 << 6;
+ *set1 << 5 << 0 << 0 << 4 << 0 << 7;
+ *set2 << 3 << 5 << 8 << 13 << 8 << 5;
+ *set3 << 5 << 6 << 7 << 3 << 4 << 5;
+ *set4 << 9 << 7 << 5 << 3 << 1 << 2;
+ //![1]
+
+ //![2]
+ auto series = new QHorizontalBarSeries;
+ series->append(set0);
+ series->append(set1);
+ series->append(set2);
+ series->append(set3);
+ series->append(set4);
+ //![2]
+
+ //![3]
+ auto chart = new QChart;
+ chart->addSeries(series);
+ chart->setTitle("Simple Horizontal Bar Chart");
+ chart->setAnimationOptions(QChart::SeriesAnimations);
+ //![3]
+
+ //![4]
+ QStringList categories {"Jan", "Feb", "Mar", "Apr", "May", "Jun"};
+ auto axisY = new QBarCategoryAxis;
+ axisY->append(categories);
+ chart->addAxis(axisY, Qt::AlignLeft);
+ series->attachAxis(axisY);
+ auto axisX = new QValueAxis;
+ chart->addAxis(axisX, Qt::AlignBottom);
+ series->attachAxis(axisX);
+ axisX->applyNiceNumbers();
+ //![4]
+
+ //![5]
+ chart->legend()->setVisible(true);
+ chart->legend()->setAlignment(Qt::AlignBottom);
+ //![5]
+
+ //![6]
+ createDefaultChartView(chart);
+ //![6]
+}
diff --git a/examples/charts/chartsgallery/horizontalbarwidget.h b/examples/charts/chartsgallery/horizontalbarwidget.h
new file mode 100644
index 00000000..cd459050
--- /dev/null
+++ b/examples/charts/chartsgallery/horizontalbarwidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef HORIZONTALBARWIDGET_H
+#define HORIZONTALBARWIDGET_H
+
+#include "contentwidget.h"
+
+class HorizontalBarWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit HorizontalBarWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/horizontalpercentbarwidget.cpp b/examples/charts/chartsgallery/horizontalpercentbarwidget.cpp
new file mode 100644
index 00000000..374b3dd4
--- /dev/null
+++ b/examples/charts/chartsgallery/horizontalpercentbarwidget.cpp
@@ -0,0 +1,66 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "horizontalpercentbarwidget.h"
+
+#include <QBarCategoryAxis>
+#include <QBarSeries>
+#include <QBarSet>
+#include <QChart>
+#include <QHorizontalPercentBarSeries>
+#include <QLegend>
+#include <QValueAxis>
+
+HorizontalPercentBarWidget::HorizontalPercentBarWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto set0 = new QBarSet("Jane");
+ auto set1 = new QBarSet("John");
+ auto set2 = new QBarSet("Axel");
+ auto set3 = new QBarSet("Mary");
+ auto set4 = new QBarSet("Samantha");
+
+ *set0 << 1 << 2 << 3 << 4 << 5 << 6;
+ *set1 << 5 << 0 << 0 << 4 << 0 << 7;
+ *set2 << 3 << 5 << 8 << 13 << 8 << 5;
+ *set3 << 5 << 6 << 7 << 3 << 4 << 5;
+ *set4 << 9 << 7 << 5 << 3 << 1 << 2;
+ //![1]
+
+ //![2]
+ auto series = new QHorizontalPercentBarSeries;
+ series->append(set0);
+ series->append(set1);
+ series->append(set2);
+ series->append(set3);
+ series->append(set4);
+ //![2]
+
+ //![3]
+ auto chart = new QChart;
+ chart->addSeries(series);
+ chart->setTitle("Simple Horizontal Percent Bar Chart");
+ chart->setAnimationOptions(QChart::SeriesAnimations);
+ //![3]
+
+ //![4]
+ QStringList categories {"Jan", "Feb", "Mar", "Apr", "May", "Jun"};
+ auto axisY = new QBarCategoryAxis;
+ axisY->append(categories);
+ chart->addAxis(axisY, Qt::AlignLeft);
+ series->attachAxis(axisY);
+ auto axisX = new QValueAxis;
+ chart->addAxis(axisX, Qt::AlignBottom);
+ series->attachAxis(axisX);
+ //![4]
+
+ //![5]
+ chart->legend()->setVisible(true);
+ chart->legend()->setAlignment(Qt::AlignBottom);
+ //![5]
+
+ //![6]
+ createDefaultChartView(chart);
+ //![6]
+}
diff --git a/examples/charts/chartsgallery/horizontalpercentbarwidget.h b/examples/charts/chartsgallery/horizontalpercentbarwidget.h
new file mode 100644
index 00000000..33f7eb8f
--- /dev/null
+++ b/examples/charts/chartsgallery/horizontalpercentbarwidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef HORIZONTALPERCENTBARWIDGET_H
+#define HORIZONTALPERCENTBARWIDGET_H
+
+#include "contentwidget.h"
+
+class HorizontalPercentBarWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit HorizontalPercentBarWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/horizontalstackedbarwidget.cpp b/examples/charts/chartsgallery/horizontalstackedbarwidget.cpp
new file mode 100644
index 00000000..647e0e34
--- /dev/null
+++ b/examples/charts/chartsgallery/horizontalstackedbarwidget.cpp
@@ -0,0 +1,67 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "horizontalstackedbarwidget.h"
+
+#include <QBarCategoryAxis>
+#include <QBarSeries>
+#include <QBarSet>
+#include <QChart>
+#include <QHorizontalStackedBarSeries>
+#include <QLegend>
+#include <QValueAxis>
+
+HorizontalStackedBarWidget::HorizontalStackedBarWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto set0 = new QBarSet("Jane");
+ auto set1 = new QBarSet("John");
+ auto set2 = new QBarSet("Axel");
+ auto set3 = new QBarSet("Mary");
+ auto set4 = new QBarSet("Samantha");
+
+ *set0 << 1 << 2 << 3 << 4 << 5 << 6;
+ *set1 << 5 << 0 << 0 << 4 << 0 << 7;
+ *set2 << 3 << 5 << 8 << 13 << 8 << 5;
+ *set3 << 5 << 6 << 7 << 3 << 4 << 5;
+ *set4 << 9 << 7 << 5 << 3 << 1 << 2;
+ //![1]
+
+ //![2]
+ auto series = new QHorizontalStackedBarSeries;
+ series->append(set0);
+ series->append(set1);
+ series->append(set2);
+ series->append(set3);
+ series->append(set4);
+
+ //![2]
+
+ //![3]
+ auto chart = new QChart;
+ chart->addSeries(series);
+ chart->setTitle("Simple Horizontal Stacked Bar Chart");
+ chart->setAnimationOptions(QChart::SeriesAnimations);
+ //![3]
+
+ //![4]
+ QStringList categories {"Jan", "Feb", "Mar", "Apr", "May", "Jun"};
+ auto axisY = new QBarCategoryAxis;
+ axisY->append(categories);
+ chart->addAxis(axisY, Qt::AlignLeft);
+ series->attachAxis(axisY);
+ auto axisX = new QValueAxis;
+ chart->addAxis(axisX, Qt::AlignBottom);
+ series->attachAxis(axisX);
+ //![4]
+
+ //![5]
+ chart->legend()->setVisible(true);
+ chart->legend()->setAlignment(Qt::AlignBottom);
+ //![5]
+
+ //![6]
+ createDefaultChartView(chart);
+ //![6]
+}
diff --git a/examples/charts/chartsgallery/horizontalstackedbarwidget.h b/examples/charts/chartsgallery/horizontalstackedbarwidget.h
new file mode 100644
index 00000000..e36d9687
--- /dev/null
+++ b/examples/charts/chartsgallery/horizontalstackedbarwidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef HORIZONTALSTACKEDBARWIDGET_H
+#define HORIZONTALSTACKEDBARWIDGET_H
+
+#include "contentwidget.h"
+
+class HorizontalStackedBarWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit HorizontalStackedBarWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/interactionschart.cpp b/examples/charts/chartsgallery/interactionschart.cpp
new file mode 100644
index 00000000..740c9f64
--- /dev/null
+++ b/examples/charts/chartsgallery/interactionschart.cpp
@@ -0,0 +1,77 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "interactionschart.h"
+
+#include <QLineSeries>
+#include <QtMath>
+#include <QValueAxis>
+
+InteractionsChart::InteractionsChart(QGraphicsItem *parent, Qt::WindowFlags wFlags, QLineSeries *series)
+ : QChart(QChart::ChartTypeCartesian, parent, wFlags), m_series(series)
+{
+}
+
+void InteractionsChart::clickPoint(const QPointF &point)
+{
+ // Find the closest data point
+ m_movingPoint = QPoint();
+ m_clicked = false;
+ const auto points = m_series->points();
+ for (QPointF p : points) {
+ if (distance(p, point) < distance(m_movingPoint, point)) {
+ m_movingPoint = p;
+ m_clicked = true;
+ }
+ }
+}
+
+qreal InteractionsChart::distance(const QPointF &p1, const QPointF &p2)
+{
+ return qSqrt((p1.x() - p2.x()) * (p1.x() - p2.x())
+ + (p1.y() - p2.y()) * (p1.y() - p2.y()));
+}
+
+void InteractionsChart::setPointClicked(bool clicked)
+{
+ m_clicked = clicked;
+}
+
+void InteractionsChart::handlePointMove(const QPoint &point)
+{
+ if (m_clicked) {
+ // Map the point clicked from the ChartView to the area occupied by the chart
+ QPoint mappedPoint = point;
+ mappedPoint.setX(point.x() - this->plotArea().x());
+ mappedPoint.setY(point.y() - this->plotArea().y());
+
+ // Get the x and y axis to be able to convert the mapped coordinate point to the chart scale
+ QAbstractAxis *axisx = axes(Qt::Horizontal).first();
+ QValueAxis *haxis = nullptr;
+ if (axisx->type() == QAbstractAxis::AxisTypeValue)
+ haxis = qobject_cast<QValueAxis *>(axisx);
+
+ QAbstractAxis *axisy = axes(Qt::Vertical).first();
+ QValueAxis *vaxis = nullptr;
+ if (axisy->type() == QAbstractAxis::AxisTypeValue)
+ vaxis = qobject_cast<QValueAxis *>(axisy);
+
+ if (haxis && vaxis) {
+ // Calculate the "unit" between points on the x y axis
+ double xUnit = this->plotArea().width() / haxis->max();
+ double yUnit = this->plotArea().height() / vaxis->max();
+
+ // Convert the mappedPoint to the actual chart scale
+ double x = mappedPoint.x() / xUnit;
+ double y = vaxis->max() - mappedPoint.y() / yUnit;
+
+ // Replace the old point with the new one
+ m_series->replace(m_movingPoint, QPointF(x, y));
+
+ // Update the m_movingPoint so we are able to do the replace also during mousemoveEvent
+ m_movingPoint.setX(x);
+ m_movingPoint.setY(y);
+ }
+ }
+}
+
diff --git a/examples/charts/chartsgallery/interactionschart.h b/examples/charts/chartsgallery/interactionschart.h
new file mode 100644
index 00000000..dd087156
--- /dev/null
+++ b/examples/charts/chartsgallery/interactionschart.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef INTERACTIONSCHART_H
+#define INTERACTIONSCHART_H
+
+#include <QChart>
+
+QT_FORWARD_DECLARE_CLASS(QLineSeries)
+
+class InteractionsChart : public QChart
+{
+ Q_OBJECT
+public:
+ explicit InteractionsChart(QGraphicsItem *parent = nullptr, Qt::WindowFlags wFlags = {}, QLineSeries *series = nullptr);
+
+public slots:
+ void clickPoint(const QPointF &point);
+
+public:
+ void handlePointMove(const QPoint &point);
+ void setPointClicked(bool clicked);
+
+private:
+ qreal distance(const QPointF &p1, const QPointF &p2);
+
+ QLineSeries *m_series = nullptr;
+ QPointF m_movingPoint;
+
+ // Boolean value to determine if an actual point in the series is clicked
+ bool m_clicked = false;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/interactionsview.cpp b/examples/charts/chartsgallery/interactionsview.cpp
new file mode 100644
index 00000000..0bac0b77
--- /dev/null
+++ b/examples/charts/chartsgallery/interactionsview.cpp
@@ -0,0 +1,34 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "interactionschart.h"
+#include "interactionsview.h"
+
+#include <QMouseEvent>
+
+InteractionsView::InteractionsView(InteractionsChart *chart, QWidget *parent) :
+ QChartView(chart, parent)
+{
+ m_chart = chart;
+}
+
+void InteractionsView::mousePressEvent(QMouseEvent *event)
+{
+ m_mousePos = event->pos();
+ QChartView::mousePressEvent(event);
+}
+
+void InteractionsView::mouseMoveEvent(QMouseEvent *event)
+{
+ m_chart->handlePointMove(event->pos());
+ QChartView::mouseMoveEvent(event);
+}
+
+void InteractionsView::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (event->pos() != m_mousePos) {
+ m_chart->handlePointMove(event->pos());
+ m_chart->setPointClicked(false);
+ }
+ QChartView::mouseReleaseEvent(event);
+}
diff --git a/examples/charts/chartsgallery/interactionsview.h b/examples/charts/chartsgallery/interactionsview.h
new file mode 100644
index 00000000..04a27b41
--- /dev/null
+++ b/examples/charts/chartsgallery/interactionsview.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef INTERACTIONSVIEW_H
+#define INTERACTIONSVIEW_H
+
+#include <QChartView>
+#include <QPoint>
+
+class InteractionsChart;
+
+class InteractionsView : public QChartView
+{
+public:
+ InteractionsView(InteractionsChart *chart, QWidget *parent = nullptr);
+
+protected:
+ void mousePressEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+
+private:
+ InteractionsChart *m_chart = nullptr;
+ QPoint m_mousePos;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/interactionswidget.cpp b/examples/charts/chartsgallery/interactionswidget.cpp
new file mode 100644
index 00000000..6be473ac
--- /dev/null
+++ b/examples/charts/chartsgallery/interactionswidget.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "interactionschart.h"
+#include "interactionsview.h"
+#include "interactionswidget.h"
+
+#include <QChart>
+#include <QLineSeries>
+#include <QValueAxis>
+
+InteractionsWidget::InteractionsWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ auto series = new QLineSeries;
+
+ series->append(0, 6);
+ series->append(1, 3);
+ series->append(2, 4);
+ series->append(3, 8);
+ series->append(7, 13);
+ series->append(10, 5);
+ *series << QPointF(11, 1) << QPointF(13, 3) << QPointF(17, 6) << QPointF(18, 3) << QPointF(20, 2);
+
+ auto chart = new InteractionsChart(0, {}, series);
+ chart->legend()->hide();
+ chart->addSeries(series);
+ QPen p = series->pen();
+ p.setWidth(5);
+ series->setPen(p);
+ chart->setTitle("Drag and drop data points to move them");
+
+ auto axisX = new QValueAxis;
+ chart->addAxis(axisX, Qt::AlignBottom);
+ axisX->setRange(0, 20);
+ series->attachAxis(axisX);
+
+ auto axisY = new QValueAxis;
+ chart->addAxis(axisY, Qt::AlignLeft);
+ axisY->setRange(0, 13);
+ series->attachAxis(axisY);
+
+ QObject::connect(series, &QLineSeries::pressed, chart, &InteractionsChart::clickPoint);
+
+ auto view = new InteractionsView(chart, this);
+ setDefaultChartView(view);
+}
diff --git a/examples/charts/chartsgallery/interactionswidget.h b/examples/charts/chartsgallery/interactionswidget.h
new file mode 100644
index 00000000..bc378a10
--- /dev/null
+++ b/examples/charts/chartsgallery/interactionswidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef INTERACTIONSWIDGET_H
+#define INTERACTIONSWIDGET_H
+
+#include "contentwidget.h"
+
+class InteractionsWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit InteractionsWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/legendmarkerswidget.cpp b/examples/charts/chartsgallery/legendmarkerswidget.cpp
new file mode 100644
index 00000000..0d739bb1
--- /dev/null
+++ b/examples/charts/chartsgallery/legendmarkerswidget.cpp
@@ -0,0 +1,161 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "legendmarkerswidget.h"
+
+#include <QChart>
+#include <QChartView>
+#include <QGraphicsLayout>
+#include <QGridLayout>
+#include <QLegend>
+#include <QLegendMarker>
+#include <QLineSeries>
+#include <QtMath>
+#include <QXYLegendMarker>
+
+LegendMarkersWidget::LegendMarkersWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ // Create chart view with the chart
+ m_chart = new QChart;
+ m_chartView = new QChartView(m_chart, this);
+
+ // Create layout for grid and detached legend
+ m_mainLayout = new QGridLayout;
+ m_mainLayout->addWidget(m_chartView, 0, 1, 3, 1);
+ setLayout(m_mainLayout);
+
+ // Add few series
+ addSeries();
+ addSeries();
+ addSeries();
+ addSeries();
+
+ connectMarkers();
+
+ // Set the title and show legend
+ m_chart->setTitle("Legend Markers (Click on legend to interact)");
+ m_chart->legend()->setVisible(true);
+ m_chart->legend()->setAlignment(Qt::AlignBottom);
+
+ m_chartView->setRenderHint(QPainter::Antialiasing);
+ m_chart->layout()->setContentsMargins(0, 0, 0, 0);
+}
+
+void LegendMarkersWidget::addSeries()
+{
+ auto series = new QLineSeries;
+ m_series.append(series);
+
+ series->setName(QString("line " + QString::number(m_series.count())));
+
+ // Make some sine wave for data
+ QList<QPointF> data;
+ int offset = m_chart->series().count();
+ for (int i = 0; i < 360; i++) {
+ qreal x = offset * 20 + i;
+ data.append(QPointF(i, qSin(qDegreesToRadians(x))));
+ }
+
+ series->append(data);
+ m_chart->addSeries(series);
+
+ if (m_series.count() == 1)
+ m_chart->createDefaultAxes();
+}
+
+void LegendMarkersWidget::removeSeries()
+{
+ // Remove last series from chart
+ if (m_series.count() > 0) {
+ QLineSeries *series = m_series.last();
+ m_chart->removeSeries(series);
+ m_series.removeLast();
+ delete series;
+ }
+}
+
+void LegendMarkersWidget::connectMarkers()
+{
+//![1]
+ // Connect all markers to handler
+ const auto markers = m_chart->legend()->markers();
+ for (QLegendMarker *marker : markers) {
+ // Disconnect possible existing connection to avoid multiple connections
+ QObject::disconnect(marker, &QLegendMarker::clicked,
+ this, &LegendMarkersWidget::handleMarkerClicked);
+ QObject::connect(marker, &QLegendMarker::clicked,
+ this, &LegendMarkersWidget::handleMarkerClicked);
+ }
+//![1]
+}
+
+void LegendMarkersWidget::disconnectMarkers()
+{
+//![2]
+ const auto markers = m_chart->legend()->markers();
+ for (QLegendMarker *marker : markers) {
+ QObject::disconnect(marker, &QLegendMarker::clicked,
+ this, &LegendMarkersWidget::handleMarkerClicked);
+ }
+//![2]
+}
+
+void LegendMarkersWidget::handleMarkerClicked()
+{
+//![3]
+ auto marker = qobject_cast<QLegendMarker *>(sender());
+ Q_ASSERT(marker);
+//![3]
+
+//![4]
+ switch (marker->type())
+//![4]
+ {
+ case QLegendMarker::LegendMarkerTypeXY:
+ {
+//![5]
+ // Toggle visibility of series
+ marker->series()->setVisible(!marker->series()->isVisible());
+
+ // Turn legend marker back to visible, since hiding series also hides the marker
+ // and we don't want it to happen now.
+ marker->setVisible(true);
+//![5]
+
+//![6]
+ // Dim the marker, if series is not visible
+ qreal alpha = 1.0;
+
+ if (!marker->series()->isVisible())
+ alpha = 0.5;
+
+ QColor color;
+ QBrush brush = marker->labelBrush();
+ color = brush.color();
+ color.setAlphaF(alpha);
+ brush.setColor(color);
+ marker->setLabelBrush(brush);
+
+ brush = marker->brush();
+ color = brush.color();
+ color.setAlphaF(alpha);
+ brush.setColor(color);
+ marker->setBrush(brush);
+
+ QPen pen = marker->pen();
+ color = pen.color();
+ color.setAlphaF(alpha);
+ pen.setColor(color);
+ marker->setPen(pen);
+
+//![6]
+ break;
+ }
+ default:
+ {
+ qDebug("Unknown marker type");
+ break;
+ }
+ }
+}
diff --git a/examples/charts/chartsgallery/legendmarkerswidget.h b/examples/charts/chartsgallery/legendmarkerswidget.h
new file mode 100644
index 00000000..78b26623
--- /dev/null
+++ b/examples/charts/chartsgallery/legendmarkerswidget.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef LEGENDMARKERSWIDGET_H
+#define LEGENDMARKERSWIDGET_H
+
+#include "contentwidget.h"
+
+QT_FORWARD_DECLARE_CLASS(QChart)
+QT_FORWARD_DECLARE_CLASS(QChartView)
+QT_FORWARD_DECLARE_CLASS(QGridLayout)
+QT_FORWARD_DECLARE_CLASS(QLineSeries)
+
+class LegendMarkersWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit LegendMarkersWidget(QWidget *parent = nullptr);
+
+public slots:
+ void addSeries();
+ void removeSeries();
+ void connectMarkers();
+ void disconnectMarkers();
+ void handleMarkerClicked();
+
+private:
+ QChart *m_chart = nullptr;
+ QChartView *m_chartView = nullptr;
+ QGridLayout *m_mainLayout = nullptr;
+ QGridLayout *m_fontLayout = nullptr;
+ QList<QLineSeries *> m_series;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/legendwidget.cpp b/examples/charts/chartsgallery/legendwidget.cpp
new file mode 100644
index 00000000..da5d3587
--- /dev/null
+++ b/examples/charts/chartsgallery/legendwidget.cpp
@@ -0,0 +1,285 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "legendwidget.h"
+
+#include <QBarSet>
+#include <QBarSeries>
+#include <QChart>
+#include <QChartView>
+#include <QCheckBox>
+#include <QDoubleSpinBox>
+#include <QFormLayout>
+#include <QGraphicsLayout>
+#include <QGridLayout>
+#include <QGroupBox>
+#include <QLegend>
+#include <QPushButton>
+
+LegendWidget::LegendWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ // Create chart view with the chart
+ m_chart = new QChart;
+ m_chartView = new QChartView(m_chart, this);
+
+ m_chart->setTitle("Legend Options");
+
+ createUi();
+
+ connect(m_toggleAttachedButton, &QPushButton::clicked, this, &LegendWidget::toggleAttached);
+ connect(m_interactiveButton, &QPushButton::clicked, this, &LegendWidget::toggleInteractive);
+ connect(m_boldButton, &QPushButton::clicked, this, &LegendWidget::toggleBold);
+ connect(m_italicButton, &QPushButton::clicked, this, &LegendWidget::toggleItalic);
+ connect(m_addSetButton, &QPushButton::clicked, this, &LegendWidget::addBarset);
+ connect(m_removeSetButton, &QPushButton::clicked, this, &LegendWidget::removeBarset);
+ connect(m_alignmentButton, &QPushButton::clicked, this, &LegendWidget::setLegendAlignment);
+ connect(m_fontSize,
+ static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
+ this, &LegendWidget::fontSizeChanged);
+ connect(m_legendPosX,
+ static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
+ this, &LegendWidget::updateLegendLayout);
+ connect(m_legendPosY,
+ static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
+ this, &LegendWidget::updateLegendLayout);
+ connect(m_legendWidth,
+ static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
+ this, &LegendWidget::updateLegendLayout);
+ connect(m_legendHeight,
+ static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
+ this, &LegendWidget::updateLegendLayout);
+
+ QLegend *legend = m_chart->legend();
+ legend->setShowToolTips(true);
+ legend->setBrush(QBrush(QColor(128, 128, 128, 128)));
+ legend->setPen(QPen(QColor(192, 192, 192, 192)));
+ //![5]
+ legend->setInteractive(true);
+ //![5]
+
+ //![4]
+ connect(legend, &QLegend::attachedToChartChanged, [legend, this](bool attachedToChart) {
+ m_toggleAttachedButton->setChecked(attachedToChart);
+ legend->setBackgroundVisible(!attachedToChart);
+ m_geometrySettings->setDisabled(attachedToChart);
+ });
+ //![4]
+ connect(legend, &QGraphicsWidget::geometryChanged, this, &LegendWidget::updateLegendSpinbox);
+
+ createSeries();
+ m_chart->createDefaultAxes();
+
+ //![1]
+ m_chart->legend()->setVisible(true);
+ m_chart->legend()->setAlignment(Qt::AlignBottom);
+ //![1]
+
+ m_chartView->setRenderHint(QPainter::Antialiasing);
+ m_chart->layout()->setContentsMargins(0, 0, 0, 0);
+}
+
+void LegendWidget::resizeEvent(QResizeEvent *)
+{
+ QRectF chartViewRect = m_chartView->rect();
+ m_legendPosX->setMaximum(chartViewRect.width());
+ m_legendPosY->setMaximum(chartViewRect.height());
+ m_legendWidth->setMaximum(chartViewRect.width());
+ m_legendHeight->setMaximum(chartViewRect.height());
+}
+
+void LegendWidget::createUi()
+{
+ QLegend *legend = m_chart->legend();
+ // Create buttons for ui
+ auto buttonLayout = new QGridLayout;
+ m_toggleAttachedButton = new QCheckBox("Attached", this);
+ m_toggleAttachedButton->setChecked(true);
+ buttonLayout->addWidget(m_toggleAttachedButton, 0, 0);
+
+ m_interactiveButton = new QCheckBox("Interactive", this);
+ m_interactiveButton->setChecked(true);
+ buttonLayout->addWidget(m_interactiveButton, 1, 0);
+
+ m_boldButton = new QCheckBox("Bold", this);
+ buttonLayout->addWidget(m_boldButton, 2, 0);
+
+ m_italicButton = new QCheckBox("Italic", this);
+ buttonLayout->addWidget(m_italicButton, 3, 0);
+
+ m_addSetButton = new QPushButton("Add Barset", this);
+ buttonLayout->addWidget(m_addSetButton, 4, 0);
+
+ m_removeSetButton = new QPushButton("Remove Barset", this);
+ buttonLayout->addWidget(m_removeSetButton, 5, 0);
+
+ m_alignmentButton = new QPushButton("Align (Bottom)", this);
+ buttonLayout->addWidget(m_alignmentButton, 6, 0);
+
+ buttonLayout->setRowStretch(7, 1);
+
+ m_legendPosX = new QDoubleSpinBox(this);
+ m_legendPosY = new QDoubleSpinBox(this);
+ m_legendWidth = new QDoubleSpinBox(this);
+ m_legendHeight = new QDoubleSpinBox(this);
+
+ auto legendLayout = new QFormLayout;
+ legendLayout->addRow("HPos", m_legendPosX);
+ legendLayout->addRow("VPos", m_legendPosY);
+ legendLayout->addRow("Width", m_legendWidth);
+ legendLayout->addRow("Height", m_legendHeight);
+ m_geometrySettings = new QGroupBox("Detached legend", this);
+ m_geometrySettings->setLayout(legendLayout);
+ buttonLayout->addWidget(m_geometrySettings, 8, 0);
+ m_geometrySettings->setDisabled(true);
+
+ // Create spinbox to modify font size
+ m_fontSize = new QDoubleSpinBox(this);
+ QFont lfont = legend->font();
+ lfont.setPointSizeF(12.0);
+ legend->setFont(lfont);
+ m_fontSize->setValue(legend->font().pointSizeF());
+ m_fontSize->setMinimum(1.);
+
+ auto fontLayout = new QFormLayout;
+ fontLayout->addRow("Legend font size", m_fontSize);
+
+ // Create layout for grid and detached legend
+ auto mainLayout = new QGridLayout;
+ mainLayout->setHorizontalSpacing(10);
+ mainLayout->addLayout(buttonLayout, 0, 0);
+ mainLayout->addLayout(fontLayout, 1, 0);
+ mainLayout->addWidget(m_chartView, 0, 1, 3, 1);
+ setLayout(mainLayout);
+}
+
+void LegendWidget::createSeries()
+{
+ m_series = new QBarSeries;
+ addBarset();
+ addBarset();
+ addBarset();
+ addBarset();
+
+ m_chart->addSeries(m_series);
+}
+
+void LegendWidget::updateLegendSpinbox()
+{
+ QLegend *legend = m_chart->legend();
+ double newPosX = legend->x();
+ double newPosY = legend->y();
+ QSizeF newSize = legend->size();
+ if (!qFuzzyCompare(m_legendPosX->value(), newPosX))
+ m_legendPosX->setValue(newPosX);
+ if (!qFuzzyCompare(m_legendPosY->value(), newPosY))
+ m_legendPosY->setValue(newPosY);
+ if (!qFuzzyCompare(m_legendWidth->value(), newSize.width()))
+ m_legendWidth->setValue(newSize.width());
+ if (!qFuzzyCompare(m_legendHeight->value(), newSize.height()))
+ m_legendHeight->setValue(newSize.height());
+}
+
+
+void LegendWidget::toggleAttached()
+{
+ QLegend *legend = m_chart->legend();
+ if (legend->isAttachedToChart()) {
+ //![2]
+ legend->detachFromChart();
+ //![2]
+ } else {
+ //![3]
+ legend->attachToChart();
+ //![3]
+ }
+ update();
+}
+
+void LegendWidget::toggleInteractive()
+{
+ m_chart->legend()->setInteractive(!m_chart->legend()->isInteractive());
+}
+
+void LegendWidget::toggleBold()
+{
+ QFont font = m_chart->legend()->font();
+ font.setBold(!font.bold());
+ m_chart->legend()->setFont(font);
+}
+
+void LegendWidget::toggleItalic()
+{
+ QFont font = m_chart->legend()->font();
+ font.setItalic(!font.italic());
+ m_chart->legend()->setFont(font);
+}
+
+void LegendWidget::addBarset()
+{
+ auto barSet = new QBarSet(QString("set ") + QString::number(m_series->count()));
+ qreal delta = m_series->count() * 0.1;
+ *barSet << 1 + delta << 2 + delta << 3 + delta << 4 + delta;
+ m_series->append(barSet);
+}
+
+void LegendWidget::removeBarset()
+{
+ QList<QBarSet *> sets = m_series->barSets();
+ if (sets.count() > 0) {
+ m_series->remove(sets.at(sets.count() - 1));
+ }
+}
+
+void LegendWidget::setLegendAlignment()
+{
+ auto button = qobject_cast<QPushButton *>(sender());
+
+ switch (m_chart->legend()->alignment()) {
+ case Qt::AlignTop:
+ m_chart->legend()->setAlignment(Qt::AlignLeft);
+ if (button)
+ button->setText("Align (Left)");
+ break;
+ case Qt::AlignLeft:
+ m_chart->legend()->setAlignment(Qt::AlignBottom);
+ if (button)
+ button->setText("Align (Bottom)");
+ break;
+ case Qt::AlignBottom:
+ m_chart->legend()->setAlignment(Qt::AlignRight);
+ if (button)
+ button->setText("Align (Right)");
+ break;
+ default:
+ if (button)
+ button->setText("Align (Top)");
+ m_chart->legend()->setAlignment(Qt::AlignTop);
+ break;
+ }
+}
+
+void LegendWidget::fontSizeChanged()
+{
+ QFont font = m_chart->legend()->font();
+ font.setPointSizeF(m_fontSize->value());
+ m_chart->legend()->setFont(font);
+}
+
+void LegendWidget::updateLegendLayout()
+{
+//![6]
+ QRectF geom = m_chart->legend()->geometry();
+ if (qFuzzyCompare(geom.x(), m_legendPosX->value())
+ && qFuzzyCompare(geom.y(), m_legendPosY->value())
+ && qFuzzyCompare(geom.width(), m_legendWidth->value())
+ && qFuzzyCompare(geom.height(), m_legendHeight->value()))
+ return;
+
+ m_chart->legend()->setGeometry(QRectF(m_legendPosX->value(),
+ m_legendPosY->value(),
+ m_legendWidth->value(),
+ m_legendHeight->value()));
+ m_chart->legend()->update();
+//![6]
+}
diff --git a/examples/charts/chartsgallery/legendwidget.h b/examples/charts/chartsgallery/legendwidget.h
new file mode 100644
index 00000000..2ca128be
--- /dev/null
+++ b/examples/charts/chartsgallery/legendwidget.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef LEGENDWIDGET_H
+#define LEGENDWIDGET_H
+
+#include "contentwidget.h"
+
+#include <QBarSeries>
+#include <QChart>
+#include <QChartView>
+#include <QCheckBox>
+#include <QDoubleSpinBox>
+#include <QGroupBox>
+#include <QPushButton>
+
+class LegendWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit LegendWidget(QWidget *parent = nullptr);
+ void createUi();
+ void createSeries();
+ void updateLegendSpinbox();
+
+public slots:
+ void toggleAttached();
+ void toggleInteractive();
+ void toggleBold();
+ void toggleItalic();
+ void addBarset();
+ void removeBarset();
+ void setLegendAlignment();
+ void fontSizeChanged();
+ void updateLegendLayout();
+
+protected:
+ void resizeEvent(QResizeEvent *) override;
+
+private:
+ QChart *m_chart;
+ QChartView *m_chartView;
+ QBarSeries *m_series;
+
+ QCheckBox *m_toggleAttachedButton;
+ QCheckBox *m_interactiveButton;
+ QCheckBox *m_boldButton;
+ QCheckBox *m_italicButton;
+ QPushButton *m_addSetButton;
+ QPushButton *m_removeSetButton;
+ QPushButton *m_alignmentButton;
+ QDoubleSpinBox *m_fontSize;
+
+ QGroupBox *m_geometrySettings;
+ QDoubleSpinBox *m_legendPosX;
+ QDoubleSpinBox *m_legendPosY;
+ QDoubleSpinBox *m_legendWidth;
+ QDoubleSpinBox *m_legendHeight;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/lightmarkerswidget.cpp b/examples/charts/chartsgallery/lightmarkerswidget.cpp
new file mode 100644
index 00000000..ddb9b759
--- /dev/null
+++ b/examples/charts/chartsgallery/lightmarkerswidget.cpp
@@ -0,0 +1,211 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "lightmarkerswidget.h"
+
+#include <QBrush>
+#include <QChart>
+#include <QChartView>
+#include <QCheckBox>
+#include <QComboBox>
+#include <QGraphicsLayout>
+#include <QGridLayout>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QList>
+#include <QPainter>
+#include <QPainterPath>
+#include <QSplineSeries>
+
+LightMarkersWidget::LightMarkersWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ constexpr qreal marker_size = 20.;
+
+ auto series = new QSplineSeries;
+ series->append({QPointF(0., 0.),
+ QPointF(0.5, 2.27),
+ QPointF(1.5, 2.2),
+ QPointF(3.3, 1.7),
+ QPointF(4.23, 3.1),
+ QPointF(5.3, 2.3),
+ QPointF(6.47, 4.1)
+ });
+ series->setMarkerSize(marker_size);
+ series->setLightMarker(rectangle(marker_size, Qt::red));
+ series->setSelectedLightMarker(blueTriangle(marker_size));
+
+ QObject::connect(series, &QXYSeries::clicked, series, [=](const QPointF &point) {
+ int index = series->points().indexOf(point);
+ if (index != -1)
+ series->toggleSelection({index});
+ });
+ //![1]
+
+ //![2]
+ auto chart = new QChart;
+ chart->addSeries(series);
+ chart->createDefaultAxes();
+ chart->legend()->setVisible(false);
+ chart->layout()->setContentsMargins(0, 0, 0, 0);
+ chart->setTitle("Select points with mouse click");
+
+ auto chartView = new QChartView(chart, this);
+ chartView->setRenderHint(QPainter::Antialiasing);
+
+ auto controlWidget = new QWidget(this);
+ auto controlLayout = new QGridLayout(controlWidget);
+ //![2]
+
+ //![3]
+ auto charPointCombobox = new QComboBox(controlWidget);
+ auto charPointSelectedCombobox = new QComboBox(controlWidget);
+ auto lineColorCombobox = new QComboBox(controlWidget);
+ auto showUnselectedPointsCheckbox = new QCheckBox(controlWidget);
+ //![3]
+
+ //![4]
+ auto charPoint = new QLabel(tr("Char point: "), controlWidget);
+ charPointCombobox->addItems({tr("Red rectangle"),
+ tr("Green triangle"),
+ tr("Orange circle")
+ });
+ QObject::connect(charPointCombobox, &QComboBox::currentIndexChanged, series, [=](const int index) {
+ if (showUnselectedPointsCheckbox->isChecked())
+ series->setLightMarker(getPointRepresentation(PointType(index), marker_size));
+ });
+ //![4]
+
+ //![5]
+ auto charPointSelected = new QLabel(tr("Char point selected: "), controlWidget);
+ charPointSelectedCombobox->addItems({tr("Blue triangle"),
+ tr("Yellow rectangle"),
+ tr("Lavender circle")
+ });
+ QObject::connect(charPointSelectedCombobox, &QComboBox::currentIndexChanged, series, [=](const int index) {
+ series->setSelectedLightMarker(getSelectedPointRepresentation(SelectedPointType(index), marker_size));
+ });
+
+ auto lineColorLabel = new QLabel(tr("Line color: "), controlWidget);
+ lineColorCombobox->addItems({tr("Blue"),
+ tr("Black"),
+ tr("Mint")
+ });
+ QObject::connect(lineColorCombobox, &QComboBox::currentIndexChanged, series, [=](const int index) {
+ series->setColor(makeLineColor(LineColor(index)));
+ });
+ //![5]
+
+ //![6]
+ auto showUnselectedPointsLabel = new QLabel(tr("Display unselected points: "), controlWidget);
+ showUnselectedPointsCheckbox->setChecked(true);
+ QObject::connect(showUnselectedPointsCheckbox, &QCheckBox::stateChanged, series, [=](const int state) {
+ if (state)
+ series->setLightMarker(getPointRepresentation(PointType(charPointCombobox->currentIndex()), marker_size));
+ else
+ series->setLightMarker(QImage());
+ });
+ //![6]
+
+ //![7]
+ controlLayout->addWidget(charPoint, 0, 0);
+ controlLayout->addWidget(charPointCombobox, 0, 1);
+
+ controlLayout->addWidget(charPointSelected, 1, 0);
+ controlLayout->addWidget(charPointSelectedCombobox, 1, 1);
+
+ controlLayout->addWidget(lineColorLabel, 2, 0);
+ controlLayout->addWidget(lineColorCombobox, 2, 1);
+
+ controlLayout->addWidget(showUnselectedPointsLabel, 3, 0);
+ controlLayout->addWidget(showUnselectedPointsCheckbox, 3, 1, 1, 2);
+
+ m_mainWidget = new QWidget(this);
+ auto mainLayout = new QHBoxLayout(m_mainWidget);
+ mainLayout->addWidget(chartView);
+ mainLayout->addWidget(controlWidget);
+ //![7]
+}
+
+void LightMarkersWidget::resizeEvent(QResizeEvent *)
+{
+ m_mainWidget->resize(size());
+}
+
+QImage LightMarkersWidget::rectangle(qreal imageSize, const QColor &color)
+{
+ QImage image(imageSize, imageSize, QImage::Format_RGB32);
+ QPainter painter;
+ painter.begin(&image);
+ painter.fillRect(0, 0, imageSize, imageSize, color);
+ painter.end();
+ return image;
+}
+
+QImage LightMarkersWidget::circle(qreal imageSize, const QColor &color)
+{
+ QImage image(imageSize, imageSize, QImage::Format_ARGB32);
+ image.fill(QColor(0, 0, 0, 0));
+ QPainter paint;
+ paint.begin(&image);
+ paint.setBrush(color);
+ QPen pen = paint.pen();
+ pen.setWidth(0);
+ paint.setPen(pen);
+ paint.drawEllipse(0, 0, imageSize * 0.9, imageSize * 0.9);
+ paint.end();
+ return image;
+}
+
+QImage LightMarkersWidget::blueTriangle(qreal imageSize)
+{
+ return QImage(":/blue_triangle").scaled(imageSize, imageSize);
+}
+
+QImage LightMarkersWidget::greenTriangle(qreal imageSize)
+{
+ return QImage(":/green_triangle").scaled(imageSize, imageSize);
+}
+
+QImage LightMarkersWidget::getPointRepresentation(PointType pointType, int imageSize)
+{
+ switch (pointType) {
+ case PointType::RedRectangle:
+ return rectangle(imageSize, Qt::red);
+ case PointType::GreenTriangle:
+ return greenTriangle(imageSize);
+ case PointType::OrangeCircle:
+ return circle(imageSize, QColor(255, 127, 80));
+ default:
+ return rectangle(imageSize, Qt::red);
+ }
+}
+
+QImage LightMarkersWidget::getSelectedPointRepresentation(SelectedPointType pointType, int imageSize)
+{
+ switch (pointType) {
+ case SelectedPointType::BlueTriangle:
+ return blueTriangle(imageSize);
+ case SelectedPointType::YellowRectangle:
+ return rectangle(imageSize, Qt::yellow);
+ case SelectedPointType::LavenderCircle:
+ return circle(imageSize, QColor(147, 112, 219));
+ default:
+ return blueTriangle(imageSize);
+ }
+}
+
+QColor LightMarkersWidget::makeLineColor(LineColor lineColor)
+{
+ switch (lineColor) {
+ case LineColor::Blue:
+ return QColor(65, 105, 225);
+ case LineColor::Black:
+ return QColor(0, 0, 0);
+ case LineColor::Mint:
+ return QColor(70, 203, 155);
+ default:
+ return QColor(0, 0, 0);
+ }
+}
diff --git a/examples/charts/chartsgallery/lightmarkerswidget.h b/examples/charts/chartsgallery/lightmarkerswidget.h
new file mode 100644
index 00000000..9add2b77
--- /dev/null
+++ b/examples/charts/chartsgallery/lightmarkerswidget.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef LIGHTMARKERSWIDGET_H
+#define LIGHTMARKERSWIDGET_H
+
+#include "contentwidget.h"
+
+#include <QColor>
+#include <QImage>
+
+QT_FORWARD_DECLARE_CLASS(QChartView)
+
+class LightMarkersWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit LightMarkersWidget(QWidget *parent = nullptr);
+
+protected:
+ void resizeEvent(QResizeEvent *) override;
+
+private:
+ enum class PointType {
+ RedRectangle,
+ GreenTriangle,
+ OrangeCircle
+ };
+
+ enum class SelectedPointType {
+ BlueTriangle,
+ YellowRectangle,
+ LavenderCircle
+ };
+
+ enum class LineColor {
+ Blue,
+ Black,
+ Mint
+ };
+
+ QImage rectangle(qreal imageSize, const QColor &color);
+ QImage circle(qreal imageSize, const QColor &color);
+ QImage blueTriangle(qreal imageSize);
+ QImage greenTriangle(qreal imageSize);
+ QImage getPointRepresentation(PointType pointType, int imageSize);
+ QImage getSelectedPointRepresentation(SelectedPointType pointType, int imageSize);
+ QColor makeLineColor(LineColor lineColor);
+
+ QWidget *m_mainWidget = nullptr;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/lineandbarwidget.cpp b/examples/charts/chartsgallery/lineandbarwidget.cpp
new file mode 100644
index 00000000..49d1cfa1
--- /dev/null
+++ b/examples/charts/chartsgallery/lineandbarwidget.cpp
@@ -0,0 +1,83 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "lineandbarwidget.h"
+
+#include <QBarCategoryAxis>
+#include <QBarSeries>
+#include <QBarSet>
+#include <QChart>
+#include <QLegend>
+#include <QLineSeries>
+#include <QValueAxis>
+
+LineAndBarWidget::LineAndBarWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto set0 = new QBarSet("Jane");
+ auto set1 = new QBarSet("John");
+ auto set2 = new QBarSet("Axel");
+ auto set3 = new QBarSet("Mary");
+ auto set4 = new QBarSet("Sam");
+
+ *set0 << 1 << 2 << 3 << 4 << 5 << 6;
+ *set1 << 5 << 0 << 0 << 4 << 0 << 7;
+ *set2 << 3 << 5 << 8 << 13 << 8 << 5;
+ *set3 << 5 << 6 << 7 << 3 << 4 << 5;
+ *set4 << 9 << 7 << 5 << 3 << 1 << 2;
+ //![1]
+
+ //![2]
+ auto barseries = new QBarSeries;
+ barseries->append(set0);
+ barseries->append(set1);
+ barseries->append(set2);
+ barseries->append(set3);
+ barseries->append(set4);
+ //![2]
+
+ //![8]
+ auto lineseries = new QLineSeries;
+ lineseries->setName("trend");
+ lineseries->append(QPoint(0, 4));
+ lineseries->append(QPoint(1, 15));
+ lineseries->append(QPoint(2, 20));
+ lineseries->append(QPoint(3, 4));
+ lineseries->append(QPoint(4, 12));
+ lineseries->append(QPoint(5, 17));
+ //![8]
+
+ //![3]
+ auto chart = new QChart;
+ chart->addSeries(barseries);
+ chart->addSeries(lineseries);
+ chart->setTitle("Line and Bar Chart");
+ //![3]
+
+ //![4]
+ QStringList categories;
+ categories << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "Jun";
+ auto axisX = new QBarCategoryAxis;
+ axisX->append(categories);
+ chart->addAxis(axisX, Qt::AlignBottom);
+ lineseries->attachAxis(axisX);
+ barseries->attachAxis(axisX);
+ axisX->setRange(QString("Jan"), QString("Jun"));
+
+ auto axisY = new QValueAxis;
+ chart->addAxis(axisY, Qt::AlignLeft);
+ lineseries->attachAxis(axisY);
+ barseries->attachAxis(axisY);
+ axisY->setRange(0, 20);
+ //![4]
+
+ //![5]
+ chart->legend()->setVisible(true);
+ chart->legend()->setAlignment(Qt::AlignBottom);
+ //![5]
+
+ //![6]
+ createDefaultChartView(chart);
+ //![6]
+}
diff --git a/examples/charts/chartsgallery/lineandbarwidget.h b/examples/charts/chartsgallery/lineandbarwidget.h
new file mode 100644
index 00000000..53f64bee
--- /dev/null
+++ b/examples/charts/chartsgallery/lineandbarwidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef LINEANDBARWIDGET_H
+#define LINEANDBARWIDGET_H
+
+#include "contentwidget.h"
+
+class LineAndBarWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit LineAndBarWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/linewidget.cpp b/examples/charts/chartsgallery/linewidget.cpp
new file mode 100644
index 00000000..5bbc9304
--- /dev/null
+++ b/examples/charts/chartsgallery/linewidget.cpp
@@ -0,0 +1,36 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "linewidget.h"
+
+#include <QChart>
+#include <QLineSeries>
+
+LineWidget::LineWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto series = new QLineSeries;
+ //![1]
+
+ //![2]
+ series->append(0, 6);
+ series->append(2, 4);
+ series->append(3, 8);
+ series->append(7, 4);
+ series->append(10, 5);
+ *series << QPointF(11, 1) << QPointF(13, 3) << QPointF(17, 6) << QPointF(18, 3) << QPointF(20, 2);
+ //![2]
+
+ //![3]
+ auto chart = new QChart;
+ chart->legend()->hide();
+ chart->addSeries(series);
+ chart->createDefaultAxes();
+ chart->setTitle("Simple Line Chart");
+ //![3]
+
+ //![4]
+ createDefaultChartView(chart);
+ //![4]
+}
diff --git a/examples/charts/chartsgallery/linewidget.h b/examples/charts/chartsgallery/linewidget.h
new file mode 100644
index 00000000..a4022463
--- /dev/null
+++ b/examples/charts/chartsgallery/linewidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef LINEWIDGET_H
+#define LINEWIDGET_H
+
+#include "contentwidget.h"
+
+class LineWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit LineWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/logaxiswidget.cpp b/examples/charts/chartsgallery/logaxiswidget.cpp
new file mode 100644
index 00000000..ce72b2ce
--- /dev/null
+++ b/examples/charts/chartsgallery/logaxiswidget.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "logaxiswidget.h"
+
+#include <QChart>
+#include <QLineSeries>
+#include <QLogValueAxis>
+#include <QValueAxis>
+
+LogAxisWidget::LogAxisWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto series = new QLineSeries;
+ *series << QPointF(1.0, 1.0) << QPointF(2.0, 73.0) << QPointF(3.0, 268.0) << QPointF(4.0, 17.0)
+ << QPointF(5.0, 4325.0) << QPointF(6.0, 723.0);
+ //![1]
+
+ //![2]
+ auto chart = new QChart;
+ chart->addSeries(series);
+ chart->legend()->hide();
+ chart->setTitle("Logarithmic Axis");
+ //![2]
+
+ //![3]
+ auto axisX = new QValueAxis;
+ axisX->setTitleText("Data point");
+ axisX->setLabelFormat("%i");
+ axisX->setTickCount(series->count());
+ chart->addAxis(axisX, Qt::AlignBottom);
+ series->attachAxis(axisX);
+
+ auto axisY = new QLogValueAxis;
+ axisY->setTitleText("Values");
+ axisY->setLabelFormat("%g");
+ axisY->setBase(8.0);
+ axisY->setMinorTickCount(-1);
+ chart->addAxis(axisY, Qt::AlignLeft);
+ series->attachAxis(axisY);
+ //![3]
+
+ //![4]
+ createDefaultChartView(chart);
+ //![4]
+}
diff --git a/examples/charts/chartsgallery/logaxiswidget.h b/examples/charts/chartsgallery/logaxiswidget.h
new file mode 100644
index 00000000..860107ee
--- /dev/null
+++ b/examples/charts/chartsgallery/logaxiswidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef LOGAXISWIDGET_H
+#define LOGAXISWIDGET_H
+
+#include "contentwidget.h"
+
+class LogAxisWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit LogAxisWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/main.cpp b/examples/charts/chartsgallery/main.cpp
new file mode 100644
index 00000000..b6f7acae
--- /dev/null
+++ b/examples/charts/chartsgallery/main.cpp
@@ -0,0 +1,18 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "mainwidget.h"
+
+#include <QApplication>
+#include <QListView>
+#include <QStringListModel>
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+
+ MainWidget w;
+ w.show();
+
+ return a.exec();
+}
diff --git a/examples/charts/chartsgallery/mainwidget.cpp b/examples/charts/chartsgallery/mainwidget.cpp
new file mode 100644
index 00000000..cb535217
--- /dev/null
+++ b/examples/charts/chartsgallery/mainwidget.cpp
@@ -0,0 +1,262 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+
+#include "areawidget.h"
+#include "boxplotwidget.h"
+#include "barmodelmapperwidget.h"
+#include "barwidget.h"
+#include "barpercentwidget.h"
+#include "barstackedwidget.h"
+#include "calloutwidget.h"
+#include "candlestickwidget.h"
+#include "contentwidget.h"
+#include "customchartwidget.h"
+#include "datetimeaxiswidget.h"
+#include "donutbreakdownwidget.h"
+#include "donutwidget.h"
+#include "dynamicsplinewidget.h"
+#include "horizontalbarwidget.h"
+#include "horizontalpercentbarwidget.h"
+#include "horizontalstackedbarwidget.h"
+#include "interactionswidget.h"
+#include "legendwidget.h"
+#include "legendmarkerswidget.h"
+#include "lightmarkerswidget.h"
+#include "lineandbarwidget.h"
+#include "linewidget.h"
+#include "logaxiswidget.h"
+#include "mainwidget.h"
+#include "modeldatawidget.h"
+#include "multiaxiswidget.h"
+#include "nesteddonutswidget.h"
+#include "pccwidget.h"
+#include "piewidget.h"
+#include "piedrilldownwidget.h"
+#include "pointconfigurationwidget.h"
+#include "polarchartwidget.h"
+#include "scatterwidget.h"
+#include "scatterinteractionswidget.h"
+#include "selectedbarwidget.h"
+#include "splinewidget.h"
+#include "stackeddrilldownwidget.h"
+#include "temperaturerecordswidget.h"
+#include "themewidget.h"
+
+#include <QApplication>
+#include <QHBoxLayout>
+#include <QListView>
+#include <QModelIndex>
+#include <QStringListModel>
+
+#include <algorithm>
+
+MainWidget::MainWidget(QWidget *parent)
+ : QWidget(parent)
+ , m_listView(new QListView(this))
+ , m_listModel(new QStringListModel(this))
+ , m_contentArea(new QWidget(this))
+{
+ m_exampleMap.insert(tr("Area Chart"), AreaChart);
+ m_exampleMap.insert(tr("Bar Model Mapper"), BarModelMapper);
+ m_exampleMap.insert(tr("Bar Chart"), BarChart);
+ m_exampleMap.insert(tr("Bar Chart Percent"), BarChartPercent);
+ m_exampleMap.insert(tr("Bar Chart Stacked"), BarChartStacked);
+ m_exampleMap.insert(tr("Bar Chart Horizontal"), BarChartHorizontal);
+ m_exampleMap.insert(tr("Bar Chart Percent Horizontal"), BarChartHorizontalPercent);
+ m_exampleMap.insert(tr("Bar Chart Stacked Horizontal"), BarChartHorizontalStacked);
+ m_exampleMap.insert(tr("Box Plot Chart"), BoxPlotChart);
+ m_exampleMap.insert(tr("Callout"), Callout);
+ m_exampleMap.insert(tr("Candlestick Chart"), CandleStickChart);
+ m_exampleMap.insert(tr("Chart Interactions"), ChartInteractions);
+ m_exampleMap.insert(tr("Chart Themes"), ChartThemes);
+ m_exampleMap.insert(tr("Custom Chart"), CustomChart);
+ m_exampleMap.insert(tr("Datetime Axis"), DateTimeAxis);
+ m_exampleMap.insert(tr("Donut"), Donut);
+ m_exampleMap.insert(tr("Donut Breakdown"), DonutBreakdown);
+ m_exampleMap.insert(tr("Drilldown Bar Chart"), StackedDrilldown);
+ m_exampleMap.insert(tr("Drilldown Pie Chart"), PieDrilldown);
+ m_exampleMap.insert(tr("Dynamic Spline Chart"), DynamicSplineChart);
+ m_exampleMap.insert(tr("Legend"), Legend);
+ m_exampleMap.insert(tr("Legend Markers"), LegendMarkers);
+ m_exampleMap.insert(tr("Light Markers and Point Selection"), LightMarkersPointSelection);
+ m_exampleMap.insert(tr("Line and Bar Chart"), LineAndBarChart);
+ m_exampleMap.insert(tr("Line Chart"), LineChart);
+ m_exampleMap.insert(tr("Log Axis"), LogAxis);
+ m_exampleMap.insert(tr("Model Data"), ModelData);
+ m_exampleMap.insert(tr("Multiple Axes"), MultiAxis);
+ m_exampleMap.insert(tr("Nested Donuts"), NestedDonuts);
+ m_exampleMap.insert(tr("Pie Chart Customization"), PieChartCustomization);
+ m_exampleMap.insert(tr("Pie Chart"), PieChart);
+ m_exampleMap.insert(tr("Point Configuration"), PointConfiguration);
+ m_exampleMap.insert(tr("Polar Chart"), PolarChart);
+ m_exampleMap.insert(tr("Scatter Interactions"), ScatterInteractions);
+ m_exampleMap.insert(tr("Scatter Chart"), ScatterChart);
+ m_exampleMap.insert(tr("Selected Bar"), SelectedBar);
+ m_exampleMap.insert(tr("Spline Chart"), SplineChart);
+ m_exampleMap.insert(tr("Temperature Records"), TemperatureRecords);
+
+ QStringList examples = m_exampleMap.keys();
+ std::sort(examples.begin(), examples.end());
+ m_listModel->setStringList(examples);
+
+ m_listView->setMaximumWidth(220);
+ m_listView->setModel(m_listModel);
+ m_listView->setCurrentIndex(m_listModel->index(0));
+ m_listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+ setMinimumSize(800, 400);
+ resize(1200, 600);
+
+ auto layout = new QHBoxLayout(this);
+ layout->addWidget(m_listView);
+ layout->addWidget(m_contentArea);
+ setLayout(layout);
+
+ connect(m_listView->selectionModel(), &QItemSelectionModel::currentChanged, this,
+ [this](const QModelIndex &index) {
+ setActiveExample(m_exampleMap[m_listModel->data(index).toString()]);
+ });
+
+ setActiveExample(m_exampleMap[examples[0]]);
+
+ setMouseTracking(true);
+
+ qApp->setApplicationDisplayName(tr("Qt Charts Example Gallery"));
+}
+
+void MainWidget::resizeEvent(QResizeEvent *)
+{
+ m_activeWidget->resize(m_contentArea->size());
+}
+
+void MainWidget::setActiveExample(Example example)
+{
+ // We only keep one example alive at the time to save resources.
+ // This also allows resetting the example by switching to another example and back.
+ if (m_activeWidget) {
+ m_activeWidget->setVisible(false);
+ m_activeWidget->deleteLater();
+ }
+
+ switch (example) {
+ case AreaChart:
+ m_activeWidget = new AreaWidget(m_contentArea);
+ break;
+ case BarModelMapper:
+ m_activeWidget = new BarModelMapperWidget(m_contentArea);
+ break;
+ case BarChart:
+ m_activeWidget = new BarWidget(m_contentArea);
+ break;
+ case BarChartPercent:
+ m_activeWidget = new BarPercentWidget(m_contentArea);
+ break;
+ case BarChartStacked:
+ m_activeWidget = new BarStackedWidget(m_contentArea);
+ break;
+ case BarChartHorizontal:
+ m_activeWidget = new HorizontalBarWidget(m_contentArea);
+ break;
+ case BarChartHorizontalPercent:
+ m_activeWidget = new HorizontalPercentBarWidget(m_contentArea);
+ break;
+ case BarChartHorizontalStacked:
+ m_activeWidget = new HorizontalStackedBarWidget(m_contentArea);
+ break;
+ case BoxPlotChart:
+ m_activeWidget = new BoxPlotWidget(m_contentArea);
+ break;
+ case Callout:
+ m_activeWidget = new CalloutWidget(m_contentArea);
+ break;
+ case CandleStickChart:
+ m_activeWidget = new CandleStickWidget(m_contentArea);
+ break;
+ case ChartInteractions:
+ m_activeWidget = new InteractionsWidget(m_contentArea);
+ break;
+ case ChartThemes:
+ m_activeWidget = new ThemeWidget(m_contentArea);
+ break;
+ case CustomChart:
+ m_activeWidget = new CustomChartWidget(m_contentArea);
+ break;
+ case DateTimeAxis:
+ m_activeWidget = new DateTimeAxisWidget(m_contentArea);
+ break;
+ case Donut:
+ m_activeWidget = new DonutWidget(m_contentArea);
+ break;
+ case DonutBreakdown:
+ m_activeWidget = new DonutBreakdownWidget(m_contentArea);
+ break;
+ case DynamicSplineChart:
+ m_activeWidget = new DynamicSplineWidget(m_contentArea);
+ break;
+ case Legend:
+ m_activeWidget = new LegendWidget(m_contentArea);
+ break;
+ case LegendMarkers:
+ m_activeWidget = new LegendMarkersWidget(m_contentArea);
+ break;
+ case LightMarkersPointSelection:
+ m_activeWidget = new LightMarkersWidget(m_contentArea);
+ break;
+ case LineAndBarChart:
+ m_activeWidget = new LineAndBarWidget(m_contentArea);
+ break;
+ case LineChart:
+ m_activeWidget = new LineWidget(m_contentArea);
+ break;
+ case LogAxis:
+ m_activeWidget = new LogAxisWidget(m_contentArea);
+ break;
+ case ModelData:
+ m_activeWidget = new ModelDataWidget(m_contentArea);
+ break;
+ case MultiAxis:
+ m_activeWidget = new MultiAxisWidget(m_contentArea);
+ break;
+ case NestedDonuts:
+ m_activeWidget = new NestedDonutsWidget(m_contentArea);
+ break;
+ case PieChartCustomization:
+ m_activeWidget = new PccWidget(m_contentArea);
+ break;
+ case PieDrilldown:
+ m_activeWidget = new PieDrilldownWidget(m_contentArea);
+ break;
+ case PieChart:
+ m_activeWidget = new PieWidget(m_contentArea);
+ break;
+ case PointConfiguration:
+ m_activeWidget = new PointConfigurationWidget(m_contentArea);
+ break;
+ case PolarChart:
+ m_activeWidget = new PolarChartWidget(m_contentArea);
+ break;
+ case ScatterInteractions:
+ m_activeWidget = new ScatterInteractionsWidget(m_contentArea);
+ break;
+ case ScatterChart:
+ m_activeWidget = new ScatterWidget(m_contentArea);
+ break;
+ case SelectedBar:
+ m_activeWidget = new SelectedBarWidget(m_contentArea);
+ break;
+ case SplineChart:
+ m_activeWidget = new SplineWidget(m_contentArea);
+ break;
+ case TemperatureRecords:
+ m_activeWidget = new TemperatureRecordsWidget(m_contentArea);
+ break;
+ case StackedDrilldown:
+ m_activeWidget = new StackedDrilldownWidget(m_contentArea);
+ break;
+ }
+
+ m_activeWidget->load();
+ m_activeWidget->resize(m_contentArea->size());
+ m_activeWidget->setVisible(true);
+}
diff --git a/examples/charts/chartsgallery/mainwidget.h b/examples/charts/chartsgallery/mainwidget.h
new file mode 100644
index 00000000..8082812c
--- /dev/null
+++ b/examples/charts/chartsgallery/mainwidget.h
@@ -0,0 +1,75 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MAINWIDGET_H
+#define MAINWIDGET_H
+
+#include <QHash>
+#include <QWidget>
+
+QT_FORWARD_DECLARE_CLASS(QListView)
+QT_FORWARD_DECLARE_CLASS(QStringListModel)
+
+class ContentWidget;
+
+class MainWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit MainWidget(QWidget *parent = nullptr);
+
+protected:
+ void resizeEvent(QResizeEvent *) override;
+
+private:
+ enum Example {
+ AreaChart,
+ BarModelMapper,
+ BarChart,
+ BarChartPercent,
+ BarChartStacked,
+ BarChartHorizontal,
+ BarChartHorizontalPercent,
+ BarChartHorizontalStacked,
+ BoxPlotChart,
+ Callout,
+ CandleStickChart,
+ ChartInteractions,
+ ChartThemes,
+ CustomChart,
+ DateTimeAxis,
+ Donut,
+ DonutBreakdown,
+ DynamicSplineChart,
+ Legend,
+ LegendMarkers,
+ LightMarkersPointSelection,
+ LineAndBarChart,
+ LineChart,
+ LogAxis,
+ ModelData,
+ MultiAxis,
+ NestedDonuts,
+ PieChartCustomization,
+ PieDrilldown,
+ PieChart,
+ PointConfiguration,
+ PolarChart,
+ ScatterChart,
+ ScatterInteractions,
+ SelectedBar,
+ SplineChart,
+ StackedDrilldown,
+ TemperatureRecords
+ };
+
+ void setActiveExample(Example example);
+
+ QListView *m_listView = nullptr;
+ QStringListModel *m_listModel = nullptr;
+ QWidget *m_contentArea = nullptr;
+ ContentWidget *m_activeWidget = nullptr;
+ QHash<QString, Example> m_exampleMap;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/modeldatamodel.cpp b/examples/charts/chartsgallery/modeldatamodel.cpp
new file mode 100644
index 00000000..af5bc9dd
--- /dev/null
+++ b/examples/charts/chartsgallery/modeldatamodel.cpp
@@ -0,0 +1,92 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "modeldatamodel.h"
+
+#include <QColor>
+#include <QList>
+#include <QRandomGenerator>
+#include <QRect>
+
+ModelDataModel::ModelDataModel(QObject *parent) :
+ QAbstractTableModel(parent)
+{
+ m_columnCount = 4;
+ m_rowCount = 15;
+
+ // m_data
+ for (int i = 0; i < m_rowCount; i++) {
+ auto dataList = new QList<qreal>(m_columnCount);
+ for (int k = 0; k < dataList->size(); k++) {
+ if (k % 2 == 0)
+ dataList->replace(k, i * 50 + QRandomGenerator::global()->bounded(20));
+ else
+ dataList->replace(k, QRandomGenerator::global()->bounded(100));
+ }
+ m_data.append(dataList);
+ }
+}
+
+int ModelDataModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return m_data.count();
+}
+
+int ModelDataModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return m_columnCount;
+}
+
+QVariant ModelDataModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ if (orientation == Qt::Horizontal) {
+ if (section % 2 == 0)
+ return "x";
+ else
+ return "y";
+ } else {
+ return QString("%1").arg(section + 1);
+ }
+}
+
+QVariant ModelDataModel::data(const QModelIndex &index, int role) const
+{
+ if (role == Qt::DisplayRole) {
+ return m_data[index.row()]->at(index.column());
+ } else if (role == Qt::EditRole) {
+ return m_data[index.row()]->at(index.column());
+ } else if (role == Qt::BackgroundRole) {
+ for (const QRect &rect : m_mapping) {
+ if (rect.contains(index.column(), index.row()))
+ return QColor(m_mapping.key(rect));
+ }
+ // cell not mapped return white color
+ return QColor(Qt::white);
+ }
+ return QVariant();
+}
+
+bool ModelDataModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (index.isValid() && role == Qt::EditRole) {
+ m_data[index.row()]->replace(index.column(), value.toDouble());
+ emit dataChanged(index, index);
+ return true;
+ }
+ return false;
+}
+
+Qt::ItemFlags ModelDataModel::flags(const QModelIndex &index) const
+{
+ return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
+}
+
+void ModelDataModel::addMapping(const QString &color, const QRect &area)
+{
+ m_mapping.insert(color, area);
+}
diff --git a/examples/charts/chartsgallery/modeldatamodel.h b/examples/charts/chartsgallery/modeldatamodel.h
new file mode 100644
index 00000000..e8b2e1d1
--- /dev/null
+++ b/examples/charts/chartsgallery/modeldatamodel.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MODELDATAMODEL_H
+#define MODELDATAMODEL_H
+
+#include <QAbstractTableModel>
+#include <QMultiHash>
+#include <QRect>
+
+class ModelDataModel : public QAbstractTableModel
+{
+ Q_OBJECT
+public:
+ explicit ModelDataModel(QObject *parent = nullptr);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+
+ void addMapping(const QString &color, const QRect &area);
+ void clearMapping() { m_mapping.clear(); }
+
+private:
+ QList<QList<qreal> *> m_data;
+ QMultiHash<QString, QRect> m_mapping;
+ int m_columnCount;
+ int m_rowCount;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/modeldatawidget.cpp b/examples/charts/chartsgallery/modeldatawidget.cpp
new file mode 100644
index 00000000..20d50aa6
--- /dev/null
+++ b/examples/charts/chartsgallery/modeldatawidget.cpp
@@ -0,0 +1,95 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "modeldatawidget.h"
+#include "modeldatamodel.h"
+
+#include <QChart>
+#include <QChartView>
+#include <QGraphicsLayout>
+#include <QGridLayout>
+#include <QHeaderView>
+#include <QLineSeries>
+#include <QTableView>
+#include <QVXYModelMapper>
+
+QT_USE_NAMESPACE
+
+ModelDataWidget::ModelDataWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ // create simple model for storing user's data
+ //! [1]
+ auto *model = new ModelDataModel;
+ //! [1]
+
+ //! [2]
+ // create table view and add model to it
+ auto tableView = new QTableView;
+ tableView->setModel(model);
+ tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+ tableView->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+ //! [2]
+
+ //! [3]
+ auto chart = new QChart;
+ chart->setAnimationOptions(QChart::AllAnimations);
+ //! [3]
+
+ // series 1
+ //! [4]
+ auto series = new QLineSeries;
+ series->setName("Line 1");
+ auto mapper = new QVXYModelMapper(this);
+ mapper->setXColumn(0);
+ mapper->setYColumn(1);
+ mapper->setSeries(series);
+ mapper->setModel(model);
+ chart->addSeries(series);
+ //! [4]
+
+ //! [5]
+ // for storing color hex from the series
+ QString seriesColorHex = "#000000";
+
+ // get the color of the series and use it for showing the mapped area
+ seriesColorHex = "#" + QString::number(series->pen().color().rgb(), 16).right(6).toUpper();
+ model->addMapping(seriesColorHex, QRect(0, 0, 2, model->rowCount()));
+ //! [5]
+
+ // series 2
+ //! [6]
+ series = new QLineSeries;
+ series->setName("Line 2");
+
+ mapper = new QVXYModelMapper(this);
+ mapper->setXColumn(2);
+ mapper->setYColumn(3);
+ mapper->setSeries(series);
+ mapper->setModel(model);
+ chart->addSeries(series);
+ //! [6]
+
+ //! [7]
+ // get the color of the series and use it for showing the mapped area
+ seriesColorHex = "#" + QString::number(series->pen().color().rgb(), 16).right(6).toUpper();
+ model->addMapping(seriesColorHex, QRect(2, 0, 2, model->rowCount()));
+ //! [7]
+
+ //! [8]
+ chart->createDefaultAxes();
+ chart->layout()->setContentsMargins(0, 0, 0, 0);
+ auto chartView = new QChartView(chart, this);
+ chartView->setRenderHint(QPainter::Antialiasing);
+ //! [8]
+
+ //! [9]
+ // create main layout
+ auto mainLayout = new QGridLayout;
+ mainLayout->addWidget(tableView, 1, 0);
+ mainLayout->addWidget(chartView, 1, 1);
+ mainLayout->setColumnStretch(1, 1);
+ mainLayout->setColumnStretch(0, 0);
+ setLayout(mainLayout);
+ //! [9]
+}
diff --git a/examples/charts/chartsgallery/modeldatawidget.h b/examples/charts/chartsgallery/modeldatawidget.h
new file mode 100644
index 00000000..245e6267
--- /dev/null
+++ b/examples/charts/chartsgallery/modeldatawidget.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MODELDATAWIDGET_H
+#define MODELDATAWIDGET_H
+
+#include "contentwidget.h"
+
+class ModelDataWidget : public ContentWidget
+{
+ Q_OBJECT
+
+public:
+ ModelDataWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/multiaxiswidget.cpp b/examples/charts/chartsgallery/multiaxiswidget.cpp
new file mode 100644
index 00000000..1979a59e
--- /dev/null
+++ b/examples/charts/chartsgallery/multiaxiswidget.cpp
@@ -0,0 +1,61 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "multiaxiswidget.h"
+
+#include <QCategoryAxis>
+#include <QChart>
+#include <QLineSeries>
+#include <QSplineSeries>
+#include <QValueAxis>
+
+MultiAxisWidget::MultiAxisWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto chart = new QChart;
+ chart->legend()->hide();
+ chart->setTitle("Multiple Vertical Axes in Chart");
+ //![1]
+
+ //![2]
+ auto axisX = new QValueAxis;
+ axisX->setTickCount(10);
+ chart->addAxis(axisX, Qt::AlignBottom);
+ //![2]
+
+ //![3]
+ auto series = new QSplineSeries;
+ *series << QPointF(1, 5) << QPointF(3.5, 18) << QPointF(4.8, 7.5) << QPointF(10, 2.5);
+ chart->addSeries(series);
+
+ auto axisY = new QValueAxis;
+ axisY->setLinePenColor(series->pen().color());
+
+ chart->addAxis(axisY, Qt::AlignLeft);
+ series->attachAxis(axisX);
+ series->attachAxis(axisY);
+ //![3]
+
+ //![4]
+ series = new QSplineSeries;
+ *series << QPointF(1, 0.5) << QPointF(1.5, 4.5) << QPointF(2.4, 2.5) << QPointF(4.3, 12.5)
+ << QPointF(5.2, 3.5) << QPointF(7.4, 16.5) << QPointF(8.3, 7.5) << QPointF(10, 17);
+ chart->addSeries(series);
+
+ auto axisY3 = new QCategoryAxis;
+ axisY3->append("Low", 5);
+ axisY3->append("Medium", 12);
+ axisY3->append("High", 17);
+ axisY3->setLinePenColor(series->pen().color());
+ axisY3->setGridLinePen((series->pen()));
+
+ chart->addAxis(axisY3, Qt::AlignRight);
+ series->attachAxis(axisX);
+ series->attachAxis(axisY3);
+ //![4]
+
+ //![5]
+ createDefaultChartView(chart);
+ //![5]
+}
diff --git a/examples/charts/chartsgallery/multiaxiswidget.h b/examples/charts/chartsgallery/multiaxiswidget.h
new file mode 100644
index 00000000..e61cc368
--- /dev/null
+++ b/examples/charts/chartsgallery/multiaxiswidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MULTIAXISWIDGET_H
+#define MULTIAXISWIDGET_H
+
+#include "contentwidget.h"
+
+class MultiAxisWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit MultiAxisWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/nesteddonutswidget.cpp b/examples/charts/chartsgallery/nesteddonutswidget.cpp
new file mode 100644
index 00000000..25c103c9
--- /dev/null
+++ b/examples/charts/chartsgallery/nesteddonutswidget.cpp
@@ -0,0 +1,105 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "nesteddonutswidget.h"
+
+#include <QChart>
+#include <QChartView>
+#include <QGraphicsLayout>
+#include <QGridLayout>
+#include <QLegend>
+#include <QPieSeries>
+#include <QPieSlice>
+#include <QRandomGenerator>
+#include <QTimer>
+
+NestedDonutsWidget::NestedDonutsWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //! [1]
+ auto chartView = new QChartView(this);
+ chartView->setRenderHint(QPainter::Antialiasing);
+ QChart *chart = chartView->chart();
+ chart->legend()->setVisible(false);
+ chart->setTitle("Nested Donuts (Hover over segments to explode them)");
+ chart->setAnimationOptions(QChart::AllAnimations);
+ chart->layout()->setContentsMargins(0, 0, 0, 0);
+ //! [1]
+
+ //! [2]
+ qreal minSize = 0.1;
+ qreal maxSize = 0.9;
+ int donutCount = 5;
+ //! [2]
+
+ //! [3]
+ for (int i = 0; i < donutCount; i++) {
+ auto donut = new QPieSeries;
+ int sliceCount = 3 + QRandomGenerator::global()->bounded(3);
+ for (int j = 0; j < sliceCount; j++) {
+ qreal value = 100 + QRandomGenerator::global()->bounded(100);
+ auto slice = new QPieSlice(QString("%1").arg(value), value);
+ slice->setLabelVisible(true);
+ slice->setLabelColor(Qt::white);
+ slice->setLabelPosition(QPieSlice::LabelInsideTangential);
+ connect(slice, &QPieSlice::hovered, this, &NestedDonutsWidget::explodeSlice);
+ donut->append(slice);
+ donut->setHoleSize(minSize + i * (maxSize - minSize) / donutCount);
+ donut->setPieSize(minSize + (i + 1) * (maxSize - minSize) / donutCount);
+ }
+ m_donuts.append(donut);
+ chartView->chart()->addSeries(donut);
+ }
+ //! [3]
+
+ // create main layout
+ //! [4]
+ auto mainLayout = new QGridLayout;
+ mainLayout->addWidget(chartView, 1, 1);
+ setLayout(mainLayout);
+ //! [4]
+
+ //! [5]
+ m_updateTimer = new QTimer(this);
+ connect(m_updateTimer, &QTimer::timeout, this, &NestedDonutsWidget::updateRotation);
+ m_updateTimer->start(1250);
+ //! [5]
+}
+
+//! [6]
+void NestedDonutsWidget::updateRotation()
+{
+ for (int i = 0; i < m_donuts.count(); i++) {
+ QPieSeries *donut = m_donuts.at(i);
+ qreal phaseShift = -50 + QRandomGenerator::global()->bounded(100);
+ donut->setPieStartAngle(donut->pieStartAngle() + phaseShift);
+ donut->setPieEndAngle(donut->pieEndAngle() + phaseShift);
+ }
+}
+//! [6]
+
+//! [7]
+void NestedDonutsWidget::explodeSlice(bool exploded)
+{
+ auto slice = qobject_cast<QPieSlice *>(sender());
+ if (exploded) {
+ m_updateTimer->stop();
+ qreal sliceStartAngle = slice->startAngle();
+ qreal sliceEndAngle = slice->startAngle() + slice->angleSpan();
+
+ QPieSeries *donut = slice->series();
+ qreal seriesIndex = m_donuts.indexOf(donut);
+ for (int i = seriesIndex + 1; i < m_donuts.count(); i++) {
+ m_donuts.at(i)->setPieStartAngle(sliceEndAngle);
+ m_donuts.at(i)->setPieEndAngle(360 + sliceStartAngle);
+ }
+ } else {
+ for (int i = 0; i < m_donuts.count(); i++) {
+ m_donuts.at(i)->setPieStartAngle(0);
+ m_donuts.at(i)->setPieEndAngle(360);
+ }
+ m_updateTimer->start();
+ }
+ slice->setExploded(exploded);
+}
+//! [7]
diff --git a/examples/charts/chartsgallery/nesteddonutswidget.h b/examples/charts/chartsgallery/nesteddonutswidget.h
new file mode 100644
index 00000000..7dfc95c1
--- /dev/null
+++ b/examples/charts/chartsgallery/nesteddonutswidget.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef NESTEDDONUTSWIDGET_H
+#define NESTEDDONUTSWIDGET_H
+
+#include "contentwidget.h"
+
+QT_FORWARD_DECLARE_CLASS(QTimer)
+QT_FORWARD_DECLARE_CLASS(QPieSeries)
+
+class NestedDonutsWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ NestedDonutsWidget(QWidget *parent = nullptr);
+
+public slots:
+ void updateRotation();
+ void explodeSlice(bool exploded);
+
+private:
+ QList<QPieSeries *> m_donuts;
+ QTimer *m_updateTimer = nullptr;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/pccbrushtool.cpp b/examples/charts/chartsgallery/pccbrushtool.cpp
new file mode 100644
index 00000000..63cdf0c3
--- /dev/null
+++ b/examples/charts/chartsgallery/pccbrushtool.cpp
@@ -0,0 +1,83 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "pccbrushtool.h"
+
+#include <QColorDialog>
+#include <QComboBox>
+#include <QFormLayout>
+#include <QPushButton>
+
+PccBrushTool::PccBrushTool(const QString &title, QWidget *parent)
+ : QWidget(parent)
+{
+ setWindowTitle(title);
+ setWindowFlags(Qt::Tool);
+
+ m_colorButton = new QPushButton();
+ m_styleCombo = new QComboBox();
+ m_styleCombo->addItem("Nobrush", (int) Qt::NoBrush);
+ m_styleCombo->addItem("Solidpattern", (int) Qt::SolidPattern);
+ m_styleCombo->addItem("Dense1pattern", (int) Qt::Dense1Pattern);
+ m_styleCombo->addItem("Dense2attern", (int) Qt::Dense2Pattern);
+ m_styleCombo->addItem("Dense3Pattern", (int) Qt::Dense3Pattern);
+ m_styleCombo->addItem("Dense4Pattern", (int) Qt::Dense4Pattern);
+ m_styleCombo->addItem("Dense5Pattern", (int) Qt::Dense5Pattern);
+ m_styleCombo->addItem("Dense6Pattern", (int) Qt::Dense6Pattern);
+ m_styleCombo->addItem("Dense7Pattern", (int) Qt::Dense7Pattern);
+ m_styleCombo->addItem("HorPattern", (int) Qt::HorPattern);
+ m_styleCombo->addItem("VerPattern", (int) Qt::VerPattern);
+ m_styleCombo->addItem("CrossPattern", (int) Qt::CrossPattern);
+ m_styleCombo->addItem("BDiagPattern", (int) Qt::BDiagPattern);
+ m_styleCombo->addItem("FDiagPattern", (int) Qt::FDiagPattern);
+ m_styleCombo->addItem("DiagCrossPattern", (int) Qt::DiagCrossPattern);
+
+ auto layout = new QFormLayout;
+ layout->addRow("Color", m_colorButton);
+ layout->addRow("Style", m_styleCombo);
+ setLayout(layout);
+
+ connect(m_colorButton, &QPushButton::clicked, this, &PccBrushTool::showColorDialog);
+ connect(m_styleCombo, &QComboBox::currentIndexChanged, this, &PccBrushTool::updateStyle);
+}
+
+void PccBrushTool::setBrush(const QBrush &brush)
+{
+ m_brush = brush;
+ m_colorButton->setText(m_brush.color().name());
+ m_styleCombo->setCurrentIndex(m_brush.style()); // index matches the enum
+}
+
+QBrush PccBrushTool::brush() const
+{
+ return m_brush;
+}
+
+QString PccBrushTool::name() const
+{
+ return name(m_brush);
+}
+
+QString PccBrushTool::name(const QBrush &brush)
+{
+ return brush.color().name();
+}
+
+void PccBrushTool::showColorDialog()
+{
+ QColorDialog dialog(m_brush.color());
+ dialog.show();
+ dialog.exec();
+ m_brush.setColor(dialog.selectedColor());
+ m_colorButton->setText(m_brush.color().name());
+ emit changed();
+}
+
+void PccBrushTool::updateStyle()
+{
+ Qt::BrushStyle style = (Qt::BrushStyle) m_styleCombo->itemData(m_styleCombo->currentIndex()).toInt();
+ if (m_brush.style() != style) {
+ m_brush.setStyle(style);
+ emit changed();
+ }
+}
diff --git a/examples/charts/chartsgallery/pccbrushtool.h b/examples/charts/chartsgallery/pccbrushtool.h
new file mode 100644
index 00000000..2e392b6a
--- /dev/null
+++ b/examples/charts/chartsgallery/pccbrushtool.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef PCCBRUSHTOOL_H
+#define PCCBRUSHTOOL_H
+
+#include <QBrush>
+#include <QWidget>
+
+QT_FORWARD_DECLARE_CLASS(QComboBox)
+QT_FORWARD_DECLARE_CLASS(QPushButton)
+
+class PccBrushTool : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit PccBrushTool(const QString &title, QWidget *parent = nullptr);
+ void setBrush(const QBrush &brush);
+ QBrush brush() const;
+ QString name() const;
+ static QString name(const QBrush &brush);
+
+signals:
+ void changed();
+
+public slots:
+ void showColorDialog();
+ void updateStyle();
+
+private:
+ QBrush m_brush;
+ QPushButton *m_colorButton = nullptr;
+ QComboBox *m_styleCombo = nullptr;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/pcccustomslice.cpp b/examples/charts/chartsgallery/pcccustomslice.cpp
new file mode 100644
index 00000000..6b4857b6
--- /dev/null
+++ b/examples/charts/chartsgallery/pcccustomslice.cpp
@@ -0,0 +1,27 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "pcccustomslice.h"
+
+PccCustomSlice::PccCustomSlice(const QString &label, qreal value)
+ : QPieSlice(label, value)
+{
+ connect(this, &PccCustomSlice::hovered, this, &PccCustomSlice::showHighlight);
+}
+
+QBrush PccCustomSlice::originalBrush()
+{
+ return m_originalBrush;
+}
+
+void PccCustomSlice::showHighlight(bool show)
+{
+ if (show) {
+ QBrush brush = this->brush();
+ m_originalBrush = brush;
+ brush.setColor(brush.color().lighter());
+ setBrush(brush);
+ } else {
+ setBrush(m_originalBrush);
+ }
+}
diff --git a/examples/charts/chartsgallery/pcccustomslice.h b/examples/charts/chartsgallery/pcccustomslice.h
new file mode 100644
index 00000000..b7ab879e
--- /dev/null
+++ b/examples/charts/chartsgallery/pcccustomslice.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef PCCCUSTOMSLICE_H
+#define PCCCUSTOMSLICE_H
+
+#include <QPieSlice>
+
+class PccCustomSlice : public QPieSlice
+{
+ Q_OBJECT
+public:
+ PccCustomSlice(const QString &label, qreal value);
+
+public:
+ QBrush originalBrush();
+
+public slots:
+ void showHighlight(bool show);
+
+private:
+ QBrush m_originalBrush;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/pccpentool.cpp b/examples/charts/chartsgallery/pccpentool.cpp
new file mode 100644
index 00000000..11bb1d76
--- /dev/null
+++ b/examples/charts/chartsgallery/pccpentool.cpp
@@ -0,0 +1,124 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "pccpentool.h"
+
+#include <QColorDialog>
+#include <QComboBox>
+#include <QDoubleSpinBox>
+#include <QFormLayout>
+#include <QPushButton>
+
+PccPenTool::PccPenTool(const QString &title, QWidget *parent)
+ : QWidget(parent)
+{
+ setWindowTitle(title);
+ setWindowFlags(Qt::Tool);
+
+ m_colorButton = new QPushButton(this);
+
+ m_widthSpinBox = new QDoubleSpinBox(this);
+
+ m_styleCombo = new QComboBox(this);
+ m_styleCombo->addItem("NoPen");
+ m_styleCombo->addItem("SolidLine");
+ m_styleCombo->addItem("DashLine");
+ m_styleCombo->addItem("DotLine");
+ m_styleCombo->addItem("DashDotLine");
+ m_styleCombo->addItem("DashDotDotLine");
+
+ m_capStyleCombo = new QComboBox(this);
+ m_capStyleCombo->addItem("FlatCap", Qt::FlatCap);
+ m_capStyleCombo->addItem("SquareCap", Qt::SquareCap);
+ m_capStyleCombo->addItem("RoundCap", Qt::RoundCap);
+
+ m_joinStyleCombo = new QComboBox(this);
+ m_joinStyleCombo->addItem("MiterJoin", Qt::MiterJoin);
+ m_joinStyleCombo->addItem("BevelJoin", Qt::BevelJoin);
+ m_joinStyleCombo->addItem("RoundJoin", Qt::RoundJoin);
+ m_joinStyleCombo->addItem("SvgMiterJoin", Qt::SvgMiterJoin);
+
+ auto layout = new QFormLayout;
+ layout->addRow("Color", m_colorButton);
+ layout->addRow("Width", m_widthSpinBox);
+ layout->addRow("Style", m_styleCombo);
+ layout->addRow("Cap style", m_capStyleCombo);
+ layout->addRow("Join style", m_joinStyleCombo);
+ setLayout(layout);
+
+ // Use old style connect on some signals because the signal is overloaded
+ connect(m_colorButton, &QPushButton::clicked, this, &PccPenTool::showColorDialog);
+ connect(m_widthSpinBox, &QDoubleSpinBox::valueChanged, this, &PccPenTool::updateWidth);
+ connect(m_styleCombo, &QComboBox::currentIndexChanged, this, &PccPenTool::updateStyle);
+ connect(m_capStyleCombo, &QComboBox::currentIndexChanged, this, &PccPenTool::updateCapStyle);
+ connect(m_joinStyleCombo, &QComboBox::currentIndexChanged, this, &PccPenTool::updateJoinStyle);
+}
+
+void PccPenTool::setPen(const QPen &pen)
+{
+ m_pen = pen;
+ m_colorButton->setText(m_pen.color().name());
+ m_widthSpinBox->setValue(m_pen.widthF());
+ m_styleCombo->setCurrentIndex(m_pen.style()); // index matches the enum
+ m_capStyleCombo->setCurrentIndex(m_capStyleCombo->findData(m_pen.capStyle()));
+ m_joinStyleCombo->setCurrentIndex(m_joinStyleCombo->findData(m_pen.joinStyle()));
+}
+
+QPen PccPenTool::pen() const
+{
+ return m_pen;
+}
+
+QString PccPenTool::name() const
+{
+ return name(m_pen);
+}
+
+QString PccPenTool::name(const QPen &pen)
+{
+ return pen.color().name() + ":" + QString::number(pen.widthF());
+}
+
+void PccPenTool::showColorDialog()
+{
+ QColorDialog dialog(m_pen.color());
+ dialog.show();
+ dialog.exec();
+ m_pen.setColor(dialog.selectedColor());
+ m_colorButton->setText(m_pen.color().name());
+ emit changed();
+}
+
+void PccPenTool::updateWidth(double width)
+{
+ if (!qFuzzyCompare((qreal) width, m_pen.widthF())) {
+ m_pen.setWidthF(width);
+ emit changed();
+ }
+}
+
+void PccPenTool::updateStyle(int style)
+{
+ if (m_pen.style() != style) {
+ m_pen.setStyle((Qt::PenStyle) style);
+ emit changed();
+ }
+}
+
+void PccPenTool::updateCapStyle(int index)
+{
+ Qt::PenCapStyle capStyle = (Qt::PenCapStyle) m_capStyleCombo->itemData(index).toInt();
+ if (m_pen.capStyle() != capStyle) {
+ m_pen.setCapStyle(capStyle);
+ emit changed();
+ }
+}
+
+void PccPenTool::updateJoinStyle(int index)
+{
+ Qt::PenJoinStyle joinStyle = (Qt::PenJoinStyle) m_joinStyleCombo->itemData(index).toInt();
+ if (m_pen.joinStyle() != joinStyle) {
+ m_pen.setJoinStyle(joinStyle);
+ emit changed();
+ }
+}
diff --git a/examples/charts/chartsgallery/pccpentool.h b/examples/charts/chartsgallery/pccpentool.h
new file mode 100644
index 00000000..14a48c89
--- /dev/null
+++ b/examples/charts/chartsgallery/pccpentool.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef PCCPENTOOL_H
+#define PCCPENTOOL_H
+
+#include <QPen>
+#include <QWidget>
+
+QT_FORWARD_DECLARE_CLASS(QComboBox);
+QT_FORWARD_DECLARE_CLASS(QDoubleSpinBox);
+QT_FORWARD_DECLARE_CLASS(QPushButton);
+
+class PccPenTool : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit PccPenTool(const QString &title, QWidget *parent = nullptr);
+ void setPen(const QPen &pen);
+ QPen pen() const;
+ QString name() const;
+ static QString name(const QPen &pen);
+
+signals:
+ void changed();
+
+public slots:
+ void showColorDialog();
+ void updateWidth(double width);
+ void updateStyle(int style);
+ void updateCapStyle(int index);
+ void updateJoinStyle(int index);
+
+private:
+ QPen m_pen;
+ QPushButton *m_colorButton;
+ QDoubleSpinBox *m_widthSpinBox;
+ QComboBox *m_styleCombo;
+ QComboBox *m_capStyleCombo;
+ QComboBox *m_joinStyleCombo;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/pccwidget.cpp b/examples/charts/chartsgallery/pccwidget.cpp
new file mode 100644
index 00000000..2f2e0e02
--- /dev/null
+++ b/examples/charts/chartsgallery/pccwidget.cpp
@@ -0,0 +1,398 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "pccbrushtool.h"
+#include "pcccustomslice.h"
+#include "pccwidget.h"
+#include "pccpentool.h"
+
+#include <QChartView>
+#include <QCheckBox>
+#include <QComboBox>
+#include <QDoubleSpinBox>
+#include <QFontDialog>
+#include <QFormLayout>
+#include <QGraphicsLayout>
+#include <QGroupBox>
+#include <QLineEdit>
+#include <QPieSeries>
+#include <QPushButton>
+
+PccWidget::PccWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ // create chart
+ auto chart = new QChart;
+ chart->setTitle("Pie Chart Customization");
+ chart->setAnimationOptions(QChart::AllAnimations);
+ chart->layout()->setContentsMargins(0, 0, 0, 0);
+
+ // create series
+ m_series = new QPieSeries;
+ *m_series << new PccCustomSlice("Slice 1", 10.0);
+ *m_series << new PccCustomSlice("Slice 2", 20.0);
+ *m_series << new PccCustomSlice("Slice 3", 30.0);
+ *m_series << new PccCustomSlice("Slice 4", 40.0);
+ *m_series << new PccCustomSlice("Slice 5", 50.0);
+ m_series->setLabelsVisible();
+ chart->addSeries(m_series);
+
+ connect(m_series, &QPieSeries::clicked, this, &PccWidget::handleSliceClicked);
+
+ // chart settings
+ m_themeComboBox = new QComboBox(this);
+ m_themeComboBox->addItem("Light", QChart::ChartThemeLight);
+ m_themeComboBox->addItem("BlueCerulean", QChart::ChartThemeBlueCerulean);
+ m_themeComboBox->addItem("Dark", QChart::ChartThemeDark);
+ m_themeComboBox->addItem("BrownSand", QChart::ChartThemeBrownSand);
+ m_themeComboBox->addItem("BlueNcs", QChart::ChartThemeBlueNcs);
+ m_themeComboBox->addItem("High Contrast", QChart::ChartThemeHighContrast);
+ m_themeComboBox->addItem("Blue Icy", QChart::ChartThemeBlueIcy);
+ m_themeComboBox->addItem("Qt", QChart::ChartThemeQt);
+
+ m_aaCheckBox = new QCheckBox(this);
+ m_animationsCheckBox = new QCheckBox(this);
+ m_animationsCheckBox->setCheckState(Qt::Checked);
+
+ m_legendCheckBox = new QCheckBox(this);
+
+ m_settingsScrollBar = new QScrollArea(this);
+ auto settingsContentWidget = new QWidget(this);
+
+ auto chartSettingsLayout = new QFormLayout(settingsContentWidget);
+ chartSettingsLayout->addRow("Theme", m_themeComboBox);
+ chartSettingsLayout->addRow("Antialiasing", m_aaCheckBox);
+ chartSettingsLayout->addRow("Animations", m_animationsCheckBox);
+ chartSettingsLayout->addRow("Legend", m_legendCheckBox);
+ auto chartSettings = new QGroupBox("Chart", this);
+ chartSettings->setLayout(chartSettingsLayout);
+
+ connect(m_themeComboBox, &QComboBox::currentIndexChanged, this, &PccWidget::updateChartSettings);
+ connect(m_aaCheckBox, &QCheckBox::toggled, this, &PccWidget::updateChartSettings);
+ connect(m_animationsCheckBox, &QCheckBox::toggled, this, &PccWidget::updateChartSettings);
+ connect(m_legendCheckBox, &QCheckBox::toggled, this, &PccWidget::updateChartSettings);
+
+ // series settings
+ m_hPosition = new QDoubleSpinBox(this);
+ m_hPosition->setMinimum(0.0);
+ m_hPosition->setMaximum(1.0);
+ m_hPosition->setSingleStep(0.1);
+ m_hPosition->setValue(m_series->horizontalPosition());
+
+ m_vPosition = new QDoubleSpinBox(this);
+ m_vPosition->setMinimum(0.0);
+ m_vPosition->setMaximum(1.0);
+ m_vPosition->setSingleStep(0.1);
+ m_vPosition->setValue(m_series->verticalPosition());
+
+ m_sizeFactor = new QDoubleSpinBox(this);
+ m_sizeFactor->setMinimum(0.0);
+ m_sizeFactor->setMaximum(1.0);
+ m_sizeFactor->setSingleStep(0.1);
+ m_sizeFactor->setValue(m_series->pieSize());
+
+ m_startAngle = new QDoubleSpinBox(this);
+ m_startAngle->setMinimum(-720);
+ m_startAngle->setMaximum(720);
+ m_startAngle->setValue(m_series->pieStartAngle());
+ m_startAngle->setSingleStep(1);
+
+ m_endAngle = new QDoubleSpinBox(this);
+ m_endAngle->setMinimum(-720);
+ m_endAngle->setMaximum(720);
+ m_endAngle->setValue(m_series->pieEndAngle());
+ m_endAngle->setSingleStep(1);
+
+ m_holeSize = new QDoubleSpinBox(this);
+ m_holeSize->setMinimum(0.0);
+ m_holeSize->setMaximum(1.0);
+ m_holeSize->setSingleStep(0.1);
+ m_holeSize->setValue(m_series->holeSize());
+
+ auto appendSlice = new QPushButton("Append slice", this);
+ auto insertSlice = new QPushButton("Insert slice", this);
+ auto removeSlice = new QPushButton("Remove selected slice", this);
+
+ auto seriesSettingsLayout = new QFormLayout(settingsContentWidget);
+ seriesSettingsLayout->addRow("Horizontal position", m_hPosition);
+ seriesSettingsLayout->addRow("Vertical position", m_vPosition);
+ seriesSettingsLayout->addRow("Size factor", m_sizeFactor);
+ seriesSettingsLayout->addRow("Start angle", m_startAngle);
+ seriesSettingsLayout->addRow("End angle", m_endAngle);
+ seriesSettingsLayout->addRow("Hole size", m_holeSize);
+ seriesSettingsLayout->addRow(appendSlice);
+ seriesSettingsLayout->addRow(insertSlice);
+ seriesSettingsLayout->addRow(removeSlice);
+ auto seriesSettings = new QGroupBox("Series", this);
+ seriesSettings->setLayout(seriesSettingsLayout);
+
+ connect(m_vPosition,
+ static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
+ this, &PccWidget::updateSerieSettings);
+ connect(m_hPosition,
+ static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
+ this, &PccWidget::updateSerieSettings);
+ connect(m_sizeFactor,
+ static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
+ this, &PccWidget::updateSerieSettings);
+ connect(m_startAngle,
+ static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
+ this, &PccWidget::updateSerieSettings);
+ connect(m_endAngle,
+ static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
+ this, &PccWidget::updateSerieSettings);
+ connect(m_holeSize,
+ static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
+ this, &PccWidget::updateSerieSettings);
+ connect(appendSlice, &QPushButton::clicked, this, &PccWidget::appendSlice);
+ connect(insertSlice, &QPushButton::clicked, this, &PccWidget::insertSlice);
+ connect(removeSlice, &QPushButton::clicked, this, &PccWidget::removeSlice);
+
+ // slice settings
+ m_sliceName = new QLineEdit("<click a slice>", this);
+ m_sliceName->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
+ m_sliceValue = new QDoubleSpinBox(this);
+ m_sliceValue->setMaximum(1000);
+ m_sliceLabelVisible = new QCheckBox(this);
+ m_sliceLabelArmFactor = new QDoubleSpinBox(this);
+ m_sliceLabelArmFactor->setSingleStep(0.01);
+ m_sliceExploded = new QCheckBox(this);
+ m_sliceExplodedFactor = new QDoubleSpinBox(this);
+ m_sliceExplodedFactor->setSingleStep(0.01);
+ m_pen = new QPushButton(this);
+ m_penTool = new PccPenTool("Slice pen", this);
+ m_brush = new QPushButton(this);
+ m_brushTool = new PccBrushTool("Slice brush", this);
+ m_font = new QPushButton(this);
+ m_labelBrush = new QPushButton(this);
+ m_labelBrushTool = new PccBrushTool("Label brush", this);
+ m_labelPosition = new QComboBox(this);
+ m_labelPosition->addItem("Outside", QPieSlice::LabelOutside);
+ m_labelPosition->addItem("Inside horizontal", QPieSlice::LabelInsideHorizontal);
+ m_labelPosition->addItem("Inside tangential", QPieSlice::LabelInsideTangential);
+ m_labelPosition->addItem("Inside normal", QPieSlice::LabelInsideNormal);
+
+ auto sliceSettingsLayout = new QFormLayout(settingsContentWidget);
+ sliceSettingsLayout->addRow("Label", m_sliceName);
+ sliceSettingsLayout->addRow("Value", m_sliceValue);
+ sliceSettingsLayout->addRow("Pen", m_pen);
+ sliceSettingsLayout->addRow("Brush", m_brush);
+ sliceSettingsLayout->addRow("Label visible", m_sliceLabelVisible);
+ sliceSettingsLayout->addRow("Label font", m_font);
+ sliceSettingsLayout->addRow("Label brush", m_labelBrush);
+ sliceSettingsLayout->addRow("Label position", m_labelPosition);
+ sliceSettingsLayout->addRow("Label arm length", m_sliceLabelArmFactor);
+ sliceSettingsLayout->addRow("Exploded", m_sliceExploded);
+ sliceSettingsLayout->addRow("Explode distance", m_sliceExplodedFactor);
+ auto sliceSettings = new QGroupBox("Selected slice", this);
+ sliceSettings->setLayout(sliceSettingsLayout);
+ sliceSettings->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred);
+
+ connect(m_sliceName, &QLineEdit::textChanged, this, &PccWidget::updateSliceSettings);
+ connect(m_sliceValue,
+ static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
+ this, &PccWidget::updateSliceSettings);
+ connect(m_pen, &QPushButton::clicked, m_penTool, &PccPenTool::show);
+ connect(m_penTool, &PccPenTool::changed, this, &PccWidget::updateSliceSettings);
+ connect(m_brush, &QPushButton::clicked, m_brushTool, &PccBrushTool::show);
+ connect(m_brushTool, &PccBrushTool::changed, this, &PccWidget::updateSliceSettings);
+ connect(m_font, &QPushButton::clicked, this, &PccWidget::showFontDialog);
+ connect(m_labelBrush, &QPushButton::clicked, m_labelBrushTool, &PccBrushTool::show);
+ connect(m_labelBrushTool, &PccBrushTool::changed, this, &PccWidget::updateSliceSettings);
+ connect(m_sliceLabelVisible, &QCheckBox::toggled, this, &PccWidget::updateSliceSettings);
+ connect(m_sliceLabelVisible, &QCheckBox::toggled, this, &PccWidget::updateSliceSettings);
+ connect(m_sliceLabelArmFactor, &QDoubleSpinBox::valueChanged,
+ this, &PccWidget::updateSliceSettings);
+ connect(m_sliceExploded, &QCheckBox::toggled, this, &PccWidget::updateSliceSettings);
+ connect(m_sliceExplodedFactor, &QDoubleSpinBox::valueChanged,
+ this, &PccWidget::updateSliceSettings);
+ connect(m_labelPosition, &QComboBox::currentIndexChanged,
+ this, &PccWidget::updateSliceSettings);
+
+ // create chart view
+ m_chartView = new QChartView(chart);
+
+ // create main layout
+ auto settingsLayout = new QVBoxLayout;
+ settingsLayout->addWidget(chartSettings);
+ settingsLayout->addWidget(seriesSettings);
+ settingsLayout->addWidget(sliceSettings);
+
+ settingsContentWidget->setLayout(settingsLayout);
+
+ m_settingsScrollBar->setWidget(settingsContentWidget);
+ m_settingsScrollBar->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ m_settingsScrollBar->setWidgetResizable(true);
+ m_settingsScrollBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
+ m_chartView->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+
+ m_baseLayout = new QGridLayout;
+ m_baseLayout->addWidget(m_settingsScrollBar, 0, 0);
+ m_baseLayout->addWidget(m_chartView, 1, 0);
+ setLayout(m_baseLayout);
+
+ updateSerieSettings();
+ updateChartSettings();
+}
+
+void PccWidget::updateChartSettings()
+{
+ auto theme = static_cast<QChart::ChartTheme>(m_themeComboBox->itemData(
+ m_themeComboBox->currentIndex()).toInt());
+ m_chartView->chart()->setTheme(theme);
+ m_chartView->setRenderHint(QPainter::Antialiasing, m_aaCheckBox->isChecked());
+
+ if (m_animationsCheckBox->checkState() == Qt::Checked)
+ m_chartView->chart()->setAnimationOptions(QChart::AllAnimations);
+ else
+ m_chartView->chart()->setAnimationOptions(QChart::NoAnimation);
+
+ if (m_legendCheckBox->checkState() == Qt::Checked)
+ m_chartView->chart()->legend()->show();
+ else
+ m_chartView->chart()->legend()->hide();
+}
+
+void PccWidget::updateSerieSettings()
+{
+ m_series->setHorizontalPosition(m_hPosition->value());
+ m_series->setVerticalPosition(m_vPosition->value());
+ m_series->setPieSize(m_sizeFactor->value());
+ m_holeSize->setMaximum(m_sizeFactor->value());
+ m_series->setPieStartAngle(m_startAngle->value());
+ m_series->setPieEndAngle(m_endAngle->value());
+ m_series->setHoleSize(m_holeSize->value());
+}
+
+void PccWidget::updateSliceSettings()
+{
+ if (!m_slice)
+ return;
+
+ m_slice->setLabel(m_sliceName->text());
+
+ m_slice->setValue(m_sliceValue->value());
+
+ m_slice->setPen(m_penTool->pen());
+ m_slice->setBrush(m_brushTool->brush());
+
+ m_slice->setLabelBrush(m_labelBrushTool->brush());
+ m_slice->setLabelVisible(m_sliceLabelVisible->isChecked());
+ m_slice->setLabelArmLengthFactor(m_sliceLabelArmFactor->value());
+ // We assume that label position index is in sync with the enum
+ m_slice->setLabelPosition((QPieSlice::LabelPosition)m_labelPosition->currentIndex());
+
+ m_slice->setExploded(m_sliceExploded->isChecked());
+ m_slice->setExplodeDistanceFactor(m_sliceExplodedFactor->value());
+}
+
+void PccWidget::handleSliceClicked(QPieSlice *slice)
+{
+ m_slice = static_cast<PccCustomSlice *>(slice);
+
+ // name
+ m_sliceName->blockSignals(true);
+ m_sliceName->setText(slice->label());
+ m_sliceName->blockSignals(false);
+
+ // value
+ m_sliceValue->blockSignals(true);
+ m_sliceValue->setValue(slice->value());
+ m_sliceValue->blockSignals(false);
+
+ // pen
+ m_pen->setText(PccPenTool::name(m_slice->pen()));
+ m_penTool->setPen(m_slice->pen());
+
+ // brush
+ m_brush->setText(m_slice->originalBrush().color().name());
+ m_brushTool->setBrush(m_slice->originalBrush());
+
+ // label
+ m_labelBrush->setText(PccBrushTool::name(m_slice->labelBrush()));
+ m_labelBrushTool->setBrush(m_slice->labelBrush());
+ m_font->setText(slice->labelFont().toString());
+ m_sliceLabelVisible->blockSignals(true);
+ m_sliceLabelVisible->setChecked(slice->isLabelVisible());
+ m_sliceLabelVisible->blockSignals(false);
+ m_sliceLabelArmFactor->blockSignals(true);
+ m_sliceLabelArmFactor->setValue(slice->labelArmLengthFactor());
+ m_sliceLabelArmFactor->blockSignals(false);
+ m_labelPosition->blockSignals(true);
+ // We assume that label position index is in sync with the enum
+ m_labelPosition->setCurrentIndex(slice->labelPosition());
+ m_labelPosition->blockSignals(false);
+
+ // exploded
+ m_sliceExploded->blockSignals(true);
+ m_sliceExploded->setChecked(slice->isExploded());
+ m_sliceExploded->blockSignals(false);
+ m_sliceExplodedFactor->blockSignals(true);
+ m_sliceExplodedFactor->setValue(slice->explodeDistanceFactor());
+ m_sliceExplodedFactor->blockSignals(false);
+}
+
+void PccWidget::showFontDialog()
+{
+ if (!m_slice)
+ return;
+
+ QFontDialog dialog(m_slice->labelFont());
+ dialog.show();
+ dialog.exec();
+
+ m_slice->setLabelFont(dialog.currentFont());
+ m_font->setText(dialog.currentFont().toString());
+}
+
+void PccWidget::appendSlice()
+{
+ *m_series << new PccCustomSlice("Slice " + QString::number(m_series->count() + 1), 10.0);
+}
+
+void PccWidget::insertSlice()
+{
+ if (!m_slice)
+ return;
+
+ int i = m_series->slices().indexOf(m_slice);
+
+ m_series->insert(i, new PccCustomSlice("Slice " + QString::number(m_series->count() + 1), 10.0));
+}
+
+void PccWidget::removeSlice()
+{
+ if (!m_slice)
+ return;
+
+ m_sliceName->setText("<click a slice>");
+
+ m_series->remove(m_slice);
+ m_slice = 0;
+}
+
+void PccWidget::resizeEvent(QResizeEvent *)
+{
+ if (width() == 0 || height() == 0)
+ return;
+
+ const double aspectRatio = double(width()) / double(height());
+
+ if ((aspectRatio < 1.0) && (m_oldAspectRatio > 1.0)) {
+ m_baseLayout->removeWidget(m_chartView);
+ m_baseLayout->removeWidget(m_settingsScrollBar);
+
+ m_baseLayout->addWidget(m_chartView, 0, 0);
+ m_baseLayout->addWidget(m_settingsScrollBar, 1, 0);
+
+ m_oldAspectRatio = aspectRatio;
+ } else if ((aspectRatio > 1.0) && (m_oldAspectRatio < 1.0)) {
+ m_baseLayout->removeWidget(m_chartView);
+ m_baseLayout->removeWidget(m_settingsScrollBar);
+
+ m_baseLayout->addWidget(m_chartView, 0, 0);
+ m_baseLayout->addWidget(m_settingsScrollBar, 0, 1);
+
+ m_oldAspectRatio = aspectRatio;
+ }
+}
diff --git a/examples/charts/chartsgallery/pccwidget.h b/examples/charts/chartsgallery/pccwidget.h
new file mode 100644
index 00000000..3b0e617c
--- /dev/null
+++ b/examples/charts/chartsgallery/pccwidget.h
@@ -0,0 +1,80 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef PCCWIDGET_H
+#define PCCWIDGET_H
+
+#include "contentwidget.h"
+
+#include <QGridLayout>
+#include <QScrollArea>
+
+QT_FORWARD_DECLARE_CLASS(QChartView);
+QT_FORWARD_DECLARE_CLASS(QCheckBox);
+QT_FORWARD_DECLARE_CLASS(QComboBox);
+QT_FORWARD_DECLARE_CLASS(QDoubleSpinBox);
+QT_FORWARD_DECLARE_CLASS(QLineEdit);
+QT_FORWARD_DECLARE_CLASS(QPushButton);
+QT_FORWARD_DECLARE_CLASS(QPieSeries);
+QT_FORWARD_DECLARE_CLASS(QPieSlice);
+
+class PccPenTool;
+class PccBrushTool;
+class PccCustomSlice;
+
+class PccWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit PccWidget(QWidget *parent = nullptr);
+
+public slots:
+ void updateChartSettings();
+ void updateSerieSettings();
+ void updateSliceSettings();
+ void handleSliceClicked(QPieSlice *slice);
+ void showFontDialog();
+ void appendSlice();
+ void insertSlice();
+ void removeSlice();
+
+private:
+ void resizeEvent(QResizeEvent *e);
+
+ QComboBox *m_themeComboBox = nullptr;
+ QCheckBox *m_aaCheckBox = nullptr;
+ QCheckBox *m_animationsCheckBox = nullptr;
+ QCheckBox *m_legendCheckBox = nullptr;
+
+ QChartView *m_chartView = nullptr;
+ QPieSeries *m_series = nullptr;
+ PccCustomSlice *m_slice = nullptr;
+
+ QDoubleSpinBox *m_hPosition = nullptr;
+ QDoubleSpinBox *m_vPosition = nullptr;
+ QDoubleSpinBox *m_sizeFactor = nullptr;
+ QDoubleSpinBox *m_startAngle = nullptr;
+ QDoubleSpinBox *m_endAngle = nullptr;
+ QDoubleSpinBox *m_holeSize = nullptr;
+
+ QLineEdit *m_sliceName = nullptr;
+ QDoubleSpinBox *m_sliceValue = nullptr;
+ QCheckBox *m_sliceLabelVisible = nullptr;
+ QDoubleSpinBox *m_sliceLabelArmFactor = nullptr;
+ QCheckBox *m_sliceExploded = nullptr;
+ QDoubleSpinBox *m_sliceExplodedFactor = nullptr;
+ QPushButton *m_brush = nullptr;
+ PccBrushTool *m_brushTool = nullptr;
+ QPushButton *m_pen = nullptr;
+ PccPenTool *m_penTool = nullptr;
+ QPushButton *m_font = nullptr;
+ QPushButton *m_labelBrush = nullptr;
+ QComboBox *m_labelPosition = nullptr;
+ PccBrushTool *m_labelBrushTool = nullptr;
+ QGridLayout *m_baseLayout = nullptr;
+ QScrollArea *m_settingsScrollBar = nullptr;
+
+ double m_oldAspectRatio = 0.;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/piedrilldownchart.cpp b/examples/charts/chartsgallery/piedrilldownchart.cpp
new file mode 100644
index 00000000..7d60f727
--- /dev/null
+++ b/examples/charts/chartsgallery/piedrilldownchart.cpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "piedrilldownchart.h"
+#include "piedrilldownslice.h"
+
+PieDrilldownChart::PieDrilldownChart(QGraphicsItem *parent, Qt::WindowFlags wFlags)
+ : QChart(QChart::ChartTypeCartesian, parent, wFlags)
+{
+}
+
+void PieDrilldownChart::changeSeries(QAbstractSeries *series)
+{
+ if (m_currentSeries)
+ removeSeries(m_currentSeries);
+ m_currentSeries = series;
+ addSeries(series);
+ setTitle(series->name());
+}
+
+void PieDrilldownChart::handleSliceClicked(QPieSlice *slice)
+{
+ auto *drilldownSlice = static_cast<PieDrilldownSlice *>(slice);
+ changeSeries(drilldownSlice->drilldownSeries());
+}
diff --git a/examples/charts/chartsgallery/piedrilldownchart.h b/examples/charts/chartsgallery/piedrilldownchart.h
new file mode 100644
index 00000000..66c54f9b
--- /dev/null
+++ b/examples/charts/chartsgallery/piedrilldownchart.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef PIEDRILLDOWNCHART_H
+#define PIEDRILLDOWNCHART_H
+
+#include <QChart>
+
+QT_FORWARD_DECLARE_CLASS(QAbstractSeries);
+QT_FORWARD_DECLARE_CLASS(QPieSlice);
+
+class PieDrilldownChart : public QChart
+{
+ Q_OBJECT
+public:
+ explicit PieDrilldownChart(QGraphicsItem *parent = nullptr, Qt::WindowFlags wFlags = {});
+ void changeSeries(QAbstractSeries *series);
+
+public slots:
+ void handleSliceClicked(QPieSlice *slice);
+
+private:
+ QAbstractSeries *m_currentSeries = nullptr;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/piedrilldownslice.cpp b/examples/charts/chartsgallery/piedrilldownslice.cpp
new file mode 100644
index 00000000..a8612cde
--- /dev/null
+++ b/examples/charts/chartsgallery/piedrilldownslice.cpp
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "piedrilldownslice.h"
+
+PieDrilldownSlice::PieDrilldownSlice(qreal value, const QString &prefix, QAbstractSeries *drilldownSeries)
+ : m_drilldownSeries(drilldownSeries),
+ m_prefix(prefix)
+{
+ setValue(value);
+ updateLabel();
+ setLabelFont(QFont("Arial", 8));
+ connect(this, &PieDrilldownSlice::percentageChanged, this, &PieDrilldownSlice::updateLabel);
+ connect(this, &PieDrilldownSlice::hovered, this, &PieDrilldownSlice::showHighlight);
+}
+
+QAbstractSeries *PieDrilldownSlice::drilldownSeries() const
+{
+ return m_drilldownSeries;
+}
+
+void PieDrilldownSlice::updateLabel()
+{
+ setLabel(QStringLiteral("%1 $%2, %3%").arg(m_prefix,
+ QString::number(value()),
+ QString::number(percentage() * 100, 'f', 1)));
+}
+
+void PieDrilldownSlice::showHighlight(bool show)
+{
+ setLabelVisible(show);
+ setExploded(show);
+}
diff --git a/examples/charts/chartsgallery/piedrilldownslice.h b/examples/charts/chartsgallery/piedrilldownslice.h
new file mode 100644
index 00000000..9579c42e
--- /dev/null
+++ b/examples/charts/chartsgallery/piedrilldownslice.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef PIEDRILLDOWNSLICE_H
+#define PIEDRILLDOWNSLICE_H
+
+#include <QPieSlice>
+
+QT_FORWARD_DECLARE_CLASS(QAbstractSeries);
+
+class PieDrilldownSlice : public QPieSlice
+{
+ Q_OBJECT
+public:
+ PieDrilldownSlice(qreal value, const QString &prefix, QAbstractSeries *drilldownSeries);
+ QAbstractSeries *drilldownSeries() const;
+
+public slots:
+ void updateLabel();
+ void showHighlight(bool show);
+
+private:
+ QAbstractSeries *m_drilldownSeries = nullptr;
+ QString m_prefix;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/piedrilldownwidget.cpp b/examples/charts/chartsgallery/piedrilldownwidget.cpp
new file mode 100644
index 00000000..59555f72
--- /dev/null
+++ b/examples/charts/chartsgallery/piedrilldownwidget.cpp
@@ -0,0 +1,49 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "piedrilldownchart.h"
+#include "piedrilldownslice.h"
+#include "piedrilldownwidget.h"
+
+#include <QChart>
+#include <QLegend>
+#include <QPieSeries>
+#include <QRandomGenerator>
+
+PieDrilldownWidget::PieDrilldownWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ auto *chart = new PieDrilldownChart;
+ chart->setTheme(QChart::ChartThemeLight);
+ chart->setAnimationOptions(QChart::AllAnimations);
+ chart->legend()->setVisible(true);
+ chart->legend()->setAlignment(Qt::AlignRight);
+
+ auto yearSeries = new QPieSeries(this);
+ yearSeries->setName("Sales by year - All (Click on slice to drill down)");
+
+ const QStringList months = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ const QStringList names = {
+ "Jane", "John", "Axel", "Mary", "Susan", "Bob"
+ };
+
+ for (const QString &name : names) {
+ auto series = new QPieSeries(this);
+ series->setName("Sales by month - " + name);
+
+ for (const QString &month : months)
+ *series << new PieDrilldownSlice(QRandomGenerator::global()->bounded(1000), month, yearSeries);
+
+ QObject::connect(series, &QPieSeries::clicked, chart, &PieDrilldownChart::handleSliceClicked);
+
+ *yearSeries << new PieDrilldownSlice(series->sum(), name, series);
+ }
+
+ QObject::connect(yearSeries, &QPieSeries::clicked, chart, &PieDrilldownChart::handleSliceClicked);
+
+ chart->changeSeries(yearSeries);
+
+ createDefaultChartView(chart);
+}
diff --git a/examples/charts/chartsgallery/piedrilldownwidget.h b/examples/charts/chartsgallery/piedrilldownwidget.h
new file mode 100644
index 00000000..cc2b16f1
--- /dev/null
+++ b/examples/charts/chartsgallery/piedrilldownwidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef PIEDRILLDOWNWIDGET_H
+#define PIEDRILLDOWNWIDGET_H
+
+#include "contentwidget.h"
+
+class PieDrilldownWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit PieDrilldownWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/piewidget.cpp b/examples/charts/chartsgallery/piewidget.cpp
new file mode 100644
index 00000000..feb67afe
--- /dev/null
+++ b/examples/charts/chartsgallery/piewidget.cpp
@@ -0,0 +1,40 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "piewidget.h"
+
+#include <QChart>
+#include <QPieSeries>
+#include <QPieSlice>
+
+PieWidget::PieWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto series = new QPieSeries;
+ series->append("Jane", 1);
+ series->append("Joe", 2);
+ series->append("Andy", 3);
+ series->append("Barbara", 4);
+ series->append("Axel", 5);
+ //![1]
+
+ //![2]
+ QPieSlice *slice = series->slices().at(1);
+ slice->setExploded();
+ slice->setLabelVisible();
+ slice->setPen(QPen(Qt::darkGreen, 2));
+ slice->setBrush(Qt::green);
+ //![2]
+
+ //![3]
+ auto chart = new QChart;
+ chart->addSeries(series);
+ chart->setTitle("Simple Pie Chart");
+ chart->legend()->hide();
+ //![3]
+
+ //![4]
+ createDefaultChartView(chart);
+ //![4]
+}
diff --git a/examples/charts/chartsgallery/piewidget.h b/examples/charts/chartsgallery/piewidget.h
new file mode 100644
index 00000000..c57200e9
--- /dev/null
+++ b/examples/charts/chartsgallery/piewidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef PIEWIDGET_H
+#define PIEWIDGET_H
+
+#include "contentwidget.h"
+
+class PieWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit PieWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/pointconfigurationwidget.cpp b/examples/charts/chartsgallery/pointconfigurationwidget.cpp
new file mode 100644
index 00000000..5c2970c3
--- /dev/null
+++ b/examples/charts/chartsgallery/pointconfigurationwidget.cpp
@@ -0,0 +1,160 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "pointconfigurationwidget.h"
+
+#include <QChart>
+#include <QChartView>
+#include <QCheckBox>
+#include <QColor>
+#include <QComboBox>
+#include <QGraphicsLayout>
+#include <QGridLayout>
+#include <QHBoxLayout>
+#include <QIcon>
+#include <QLabel>
+#include <QLineEdit>
+#include <QLineSeries>
+
+//![1]
+PointConfigurationWidget::PointConfigurationWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+//![1]
+ //![2]
+ m_series = new QLineSeries;
+ m_series->setPointsVisible(true);
+ m_series->append({QPointF(0, 7), QPointF(2, 4),
+ QPointF(3, 5), QPointF(7, 4),
+ QPointF(10, 5), QPointF(11, 1),
+ QPointF(13, 3), QPointF(17, 6),
+ QPointF(18, 3), QPointF(20, 2)});
+ //![2]
+
+ //![3]
+ auto selectedPointIndexLabel = new QLabel(tr("Selected Point: "), this);
+ m_selectedPointIndexLineEdit = new QLineEdit(this);
+ m_selectedPointIndexLineEdit->setReadOnly(true);
+
+ auto colorLabel = new QLabel(tr("Color: "), this);
+ m_colorCombobox = new QComboBox(this);
+ QStringList colorStrings = {"red", "orange", "yellow", "green", "blue",
+ "indigo", "violet", "black"};
+ QStringList trColorStrings = {tr("red"), tr("orange"), tr("yellow"),
+ tr("green"), tr("blue"), tr("indigo"),
+ tr("violet"), tr("black")};
+ for (int i = 0; i < colorStrings.size(); i++)
+ m_colorCombobox->addItem(QIcon(), trColorStrings[i], QColor(colorStrings[i]));
+
+ auto sizeLabel = new QLabel(tr("Size: "), this);
+ m_sizeCombobox = new QComboBox(this);
+ for (auto size : { 2, 3, 4, 6, 8, 10, 12, 15 })
+ m_sizeCombobox->addItem(QIcon(), QString::number(size), size);
+
+ auto labelVisibilityLabel = new QLabel(tr("Label Visibility: "), this);
+ m_labelVisibilityCheckbox = new QCheckBox(this);
+
+ auto customLabelLabel = new QLabel(tr("Custom Label: "), this);
+ m_customLabelLineEdit = new QLineEdit(this);
+ //![3]
+
+ //![4]
+ QObject::connect(m_series, &QXYSeries::clicked, m_series, [&](const QPointF &point) {
+ int index = m_series->points().indexOf(point.toPoint());
+ if (index != -1) {
+ m_series->deselectAllPoints();
+ m_series->selectPoint(index);
+ m_selectedPointIndex = index;
+ m_selectedPointConfig = m_series->pointConfiguration(index);
+ const QPointF selectedPoint(m_series->at(index));
+ m_selectedPointIndexLineEdit->setText("(" + QString::number(selectedPoint.x()) + ", " +
+ QString::number(selectedPoint.y()) + ")");
+ PointConfigurations config = m_series->pointConfiguration(index);
+
+ QVariant colorVar = config[QXYSeries::PointConfiguration::Color];
+ QColor color = colorVar.isValid() ? colorVar.value<QColor>() : m_series->color();
+ if (m_colorCombobox->findData(color) < 0)
+ m_colorCombobox->addItem(color.name(), color);
+ m_colorCombobox->setCurrentIndex(m_colorCombobox->findData(color));
+
+ QVariant sizeVar = config[QXYSeries::PointConfiguration::Size];
+ qreal size = sizeVar.isValid() ? sizeVar.toReal() : m_series->markerSize();
+ if (m_sizeCombobox->findData(size) < 0)
+ m_sizeCombobox->addItem(QString::number(size), size);
+ m_sizeCombobox->setCurrentIndex(m_sizeCombobox->findData(size));
+
+ QVariant labelVisibilityVar = config[QXYSeries::PointConfiguration::LabelVisibility];
+ bool labelVisibility = labelVisibilityVar.isValid() ? labelVisibilityVar.toBool() :
+ m_series->pointLabelsVisible();
+ m_labelVisibilityCheckbox->setChecked(labelVisibility);
+
+ QVariant customLabelVar = config[QXYSeries::PointConfiguration::LabelFormat];
+ QString customLabel = customLabelVar.isValid() ? customLabelVar.toString() : "";
+ m_customLabelLineEdit->setText(customLabel);
+ }
+ });
+ //![4]
+
+ //![5]
+ QObject::connect(m_colorCombobox, &QComboBox::activated, m_series, [&](const int) {
+ m_selectedPointConfig[QXYSeries::PointConfiguration::Color] = m_colorCombobox->currentData();
+ m_series->setPointConfiguration(m_selectedPointIndex, m_selectedPointConfig);
+ });
+ QObject::connect(m_sizeCombobox, &QComboBox::activated, m_series, [&](const int) {
+ m_selectedPointConfig[QXYSeries::PointConfiguration::Size] = m_sizeCombobox->currentData();
+ m_series->setPointConfiguration(m_selectedPointIndex, m_selectedPointConfig);
+ });
+ QObject::connect(m_labelVisibilityCheckbox, &QAbstractButton::clicked, m_series, [&](const bool checked) {
+ m_selectedPointConfig[QXYSeries::PointConfiguration::LabelVisibility] = checked;
+ m_series->setPointConfiguration(m_selectedPointIndex, m_selectedPointConfig);
+ });
+ QObject::connect(m_customLabelLineEdit, &QLineEdit::editingFinished, m_series, [&]() {
+ m_selectedPointConfig[QXYSeries::PointConfiguration::LabelFormat] = m_customLabelLineEdit->text();
+ m_series->setPointConfiguration(m_selectedPointIndex, m_selectedPointConfig);
+ });
+ //![5]
+
+ //![6]
+ auto chart = new QChart;
+ chart->addSeries(m_series);
+ chart->createDefaultAxes();
+ chart->setTitle("Select points with mouse click");
+ chart->layout()->setContentsMargins(0, 0, 0, 0);
+ chart->legend()->setVisible(false);
+
+ m_selectInitialPointConnection = QObject::connect(chart, &QChart::geometryChanged, chart, [&]() {
+ m_series->selectPoint(4);
+ m_series->clicked(m_series->at(m_series->selectedPoints()[0]));
+ disconnect(m_selectInitialPointConnection);
+ });
+
+ auto chartView = new QChartView(chart, this);
+ chartView->setRenderHint(QPainter::Antialiasing);
+
+ auto controlWidget = new QWidget(this);
+ auto controlLayout = new QGridLayout(controlWidget);
+ controlLayout->setColumnStretch(1, 1);
+
+ controlLayout->addWidget(selectedPointIndexLabel, 0, 0);
+ controlLayout->addWidget(m_selectedPointIndexLineEdit, 0, 1);
+
+ controlLayout->addWidget(colorLabel, 1, 0);
+ controlLayout->addWidget(m_colorCombobox, 1, 1);
+
+ controlLayout->addWidget(sizeLabel, 2, 0);
+ controlLayout->addWidget(m_sizeCombobox, 2, 1);
+
+ controlLayout->addWidget(labelVisibilityLabel, 3, 0);
+ controlLayout->addWidget(m_labelVisibilityCheckbox, 3, 1, 1, 2);
+
+ controlLayout->addWidget(customLabelLabel, 4, 0);
+ controlLayout->addWidget(m_customLabelLineEdit, 4, 1);
+
+ auto mainLayout = new QHBoxLayout(this);
+ mainLayout->addWidget(chartView);
+ mainLayout->setStretch(0, 1);
+ mainLayout->addWidget(controlWidget);
+ //![6]
+//![7]
+}
+//![7]
diff --git a/examples/charts/chartsgallery/pointconfigurationwidget.h b/examples/charts/chartsgallery/pointconfigurationwidget.h
new file mode 100644
index 00000000..92aba69d
--- /dev/null
+++ b/examples/charts/chartsgallery/pointconfigurationwidget.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef POINTCONFIGURATIONWIDGET_H
+#define POINTCONFIGURATIONWIDGET_H
+
+#include "contentwidget.h"
+
+#include <QXYSeries>
+
+QT_FORWARD_DECLARE_CLASS(QLineEdit)
+QT_FORWARD_DECLARE_CLASS(QComboBox)
+QT_FORWARD_DECLARE_CLASS(QCheckBox)
+
+typedef QHash<QXYSeries::PointConfiguration, QVariant> PointConfigurations;
+
+class PointConfigurationWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit PointConfigurationWidget(QWidget *parent = nullptr);
+
+private:
+ QXYSeries *m_series = nullptr;
+
+ QMetaObject::Connection m_selectInitialPointConnection;
+ int m_selectedPointIndex = -1;
+ PointConfigurations m_selectedPointConfig;
+
+ QLineEdit *m_selectedPointIndexLineEdit = nullptr;
+ QComboBox *m_colorCombobox = nullptr;
+ QComboBox *m_sizeCombobox = nullptr;
+ QCheckBox *m_labelVisibilityCheckbox = nullptr;
+ QLineEdit *m_customLabelLineEdit = nullptr;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/polarchartview.cpp b/examples/charts/chartsgallery/polarchartview.cpp
new file mode 100644
index 00000000..751ae45f
--- /dev/null
+++ b/examples/charts/chartsgallery/polarchartview.cpp
@@ -0,0 +1,93 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "polarchartview.h"
+
+#include <QAbstractAxis>
+#include <QMouseEvent>
+#include <QPolarChart>
+#include <QValueAxis>
+
+PolarChartView::PolarChartView(QWidget *parent)
+ : QChartView(parent)
+{
+}
+
+//![1]
+void PolarChartView::keyPressEvent(QKeyEvent *event)
+{
+ switch (event->key()) {
+ case Qt::Key_Plus:
+ chart()->zoomIn();
+ break;
+ case Qt::Key_Minus:
+ chart()->zoomOut();
+ break;
+ case Qt::Key_Left:
+ chart()->scroll(-1.0, 0);
+ break;
+ case Qt::Key_Right:
+ chart()->scroll(1.0, 0);
+ break;
+ case Qt::Key_Up:
+ chart()->scroll(0, 1.0);
+ break;
+ case Qt::Key_Down:
+ chart()->scroll(0, -1.0);
+ break;
+ case Qt::Key_Space:
+ switchChartType();
+ break;
+ default:
+ QGraphicsView::keyPressEvent(event);
+ break;
+ }
+}
+//![1]
+
+//![2]
+void PolarChartView::switchChartType()
+{
+ QChart *newChart;
+ QChart *oldChart = chart();
+
+ if (oldChart->chartType() == QChart::ChartTypeCartesian)
+ newChart = new QPolarChart;
+ else
+ newChart = new QChart;
+
+ // Move series and axes from old chart to new one
+ const QList<QAbstractSeries *> seriesList = oldChart->series();
+ const QList<QAbstractAxis *> axisList = oldChart->axes();
+ QList<QPair<qreal, qreal> > axisRanges;
+
+ for (QAbstractAxis *axis : axisList) {
+ auto valueAxis = static_cast<QValueAxis *>(axis);
+ axisRanges.append(QPair<qreal, qreal>(valueAxis->min(), valueAxis->max()));
+ }
+
+ for (QAbstractSeries *series : seriesList)
+ oldChart->removeSeries(series);
+
+ for (QAbstractAxis *axis : axisList) {
+ oldChart->removeAxis(axis);
+ newChart->addAxis(axis, axis->alignment());
+ }
+
+ for (QAbstractSeries *series : seriesList) {
+ newChart->addSeries(series);
+ for (QAbstractAxis *axis : axisList)
+ series->attachAxis(axis);
+ }
+
+ int count = 0;
+ for (QAbstractAxis *axis : axisList) {
+ axis->setRange(axisRanges[count].first, axisRanges[count].second);
+ count++;
+ }
+
+ newChart->setTitle(oldChart->title());
+ setChart(newChart);
+ delete oldChart;
+}
+//![2]
diff --git a/examples/charts/chartsgallery/polarchartview.h b/examples/charts/chartsgallery/polarchartview.h
new file mode 100644
index 00000000..ee4e8fb9
--- /dev/null
+++ b/examples/charts/chartsgallery/polarchartview.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef POLARCHARTVIEW_H
+#define POLARCHARTVIEW_H
+
+#include <QChartView>
+
+class PolarChartView : public QChartView
+{
+public:
+ PolarChartView(QWidget *parent = nullptr);
+
+protected:
+ void keyPressEvent(QKeyEvent *event);
+
+private:
+ void switchChartType();
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/polarchartwidget.cpp b/examples/charts/chartsgallery/polarchartwidget.cpp
new file mode 100644
index 00000000..d0550c7c
--- /dev/null
+++ b/examples/charts/chartsgallery/polarchartwidget.cpp
@@ -0,0 +1,110 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "polarchartview.h"
+#include "polarchartwidget.h"
+
+#include <QAreaSeries>
+#include <QChart>
+#include <QLineSeries>
+#include <QPolarChart>
+#include <QScatterSeries>
+#include <QSplineSeries>
+#include <QValueAxis>
+
+PolarChartWidget::PolarChartWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ const qreal angularMin = -100;
+ const qreal angularMax = 100;
+
+ const qreal radialMin = -100;
+ const qreal radialMax = 100;
+
+ auto series1 = new QScatterSeries;
+ series1->setName("scatter");
+ for (int i = angularMin; i <= angularMax; i += 10)
+ series1->append(i, (i / radialMax) * radialMax + 8.0);
+
+ auto series2 = new QSplineSeries;
+ series2->setName("spline");
+ for (int i = angularMin; i <= angularMax; i += 10)
+ series2->append(i, (i / radialMax) * radialMax);
+
+ auto series3 = new QLineSeries;
+ series3->setName("star outer");
+ qreal ad = (angularMax - angularMin) / 8;
+ qreal rd = (radialMax - radialMin) / 3 * 1.3;
+ series3->append(angularMin, radialMax);
+ series3->append(angularMin + ad * 1, radialMin + rd);
+ series3->append(angularMin + ad * 2, radialMax);
+ series3->append(angularMin + ad * 3, radialMin + rd);
+ series3->append(angularMin + ad * 4, radialMax);
+ series3->append(angularMin + ad * 5, radialMin + rd);
+ series3->append(angularMin + ad * 6, radialMax);
+ series3->append(angularMin + ad * 7, radialMin + rd);
+ series3->append(angularMin + ad * 8, radialMax);
+
+ auto series4 = new QLineSeries;
+ series4->setName("star inner");
+ ad = (angularMax - angularMin) / 8;
+ rd = (radialMax - radialMin) / 3;
+ series4->append(angularMin, radialMax);
+ series4->append(angularMin + ad * 1, radialMin + rd);
+ series4->append(angularMin + ad * 2, radialMax);
+ series4->append(angularMin + ad * 3, radialMin + rd);
+ series4->append(angularMin + ad * 4, radialMax);
+ series4->append(angularMin + ad * 5, radialMin + rd);
+ series4->append(angularMin + ad * 6, radialMax);
+ series4->append(angularMin + ad * 7, radialMin + rd);
+ series4->append(angularMin + ad * 8, radialMax);
+
+ auto series5 = new QAreaSeries;
+ series5->setName("star area");
+ series5->setUpperSeries(series3);
+ series5->setLowerSeries(series4);
+ series5->setOpacity(0.5);
+
+ //![1]
+ auto chart = new QPolarChart;
+ //![1]
+ chart->addSeries(series1);
+ chart->addSeries(series2);
+ chart->addSeries(series3);
+ chart->addSeries(series4);
+ chart->addSeries(series5);
+
+ chart->setTitle("Use arrow keys to scroll, +/- to zoom, and space to switch chart type.");
+
+ //![2]
+ auto angularAxis = new QValueAxis;
+ angularAxis->setTickCount(9); // First and last ticks are co-located on 0/360 angle.
+ angularAxis->setLabelFormat("%.1f");
+ angularAxis->setShadesVisible(true);
+ angularAxis->setShadesBrush(QBrush(QColor(249, 249, 255)));
+ chart->addAxis(angularAxis, QPolarChart::PolarOrientationAngular);
+
+ auto radialAxis = new QValueAxis;
+ radialAxis->setTickCount(9);
+ radialAxis->setLabelFormat("%d");
+ chart->addAxis(radialAxis, QPolarChart::PolarOrientationRadial);
+ //![2]
+
+ series1->attachAxis(radialAxis);
+ series1->attachAxis(angularAxis);
+ series2->attachAxis(radialAxis);
+ series2->attachAxis(angularAxis);
+ series3->attachAxis(radialAxis);
+ series3->attachAxis(angularAxis);
+ series4->attachAxis(radialAxis);
+ series4->attachAxis(angularAxis);
+ series5->attachAxis(radialAxis);
+ series5->attachAxis(angularAxis);
+
+ radialAxis->setRange(radialMin, radialMax);
+ angularAxis->setRange(angularMin, angularMax);
+
+ auto chartView = new PolarChartView(this);
+ chartView->setChart(chart);
+ setDefaultChartView(chartView);
+}
diff --git a/examples/charts/chartsgallery/polarchartwidget.h b/examples/charts/chartsgallery/polarchartwidget.h
new file mode 100644
index 00000000..8d151059
--- /dev/null
+++ b/examples/charts/chartsgallery/polarchartwidget.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef POLARCHARTWIDGET_H
+#define POLARCHARTWIDGET_H
+
+#include "contentwidget.h"
+
+class PolarChartView;
+
+class PolarChartWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit PolarChartWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/scatterinteractionswidget.cpp b/examples/charts/chartsgallery/scatterinteractionswidget.cpp
new file mode 100644
index 00000000..b518c6da
--- /dev/null
+++ b/examples/charts/chartsgallery/scatterinteractionswidget.cpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "scatterinteractionswidget.h"
+
+#include <QChart>
+#include <QtMath>
+#include <QScatterSeries>
+
+ScatterInteractionsWidget::ScatterInteractionsWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ m_scatter = new QScatterSeries;
+ m_scatter->setName("scatter1");
+ for (qreal x(0.5); x <= 4.0; x += 0.5) {
+ for (qreal y(0.5); y <= 4.0; y += 0.5)
+ *m_scatter << QPointF(x, y);
+ }
+ m_scatter2 = new QScatterSeries;
+ m_scatter2->setName("scatter2");
+
+ auto *chart = new QChart;
+ chart->setTitle("Click to interact with scatter points");
+ chart->addSeries(m_scatter2);
+ chart->addSeries(m_scatter);
+ chart->createDefaultAxes();
+ chart->axes(Qt::Horizontal).first()->setRange(0, 4.5);
+ chart->axes(Qt::Vertical).first()->setRange(0, 4.5);
+
+ connect(m_scatter, &QScatterSeries::clicked,
+ this, &ScatterInteractionsWidget::handleClickedPoint);
+
+ createDefaultChartView(chart);
+}
+
+void ScatterInteractionsWidget::handleClickedPoint(const QPointF &point)
+{
+ QPointF clickedPoint = point;
+
+ // Find the closest point from series 1
+ QPointF closest(INT_MAX, INT_MAX);
+ qreal distance(INT_MAX);
+ const auto points = m_scatter->points();
+ for (const QPointF &currentPoint : points) {
+ qreal currentDistance = qSqrt((currentPoint.x() - clickedPoint.x())
+ * (currentPoint.x() - clickedPoint.x())
+ + (currentPoint.y() - clickedPoint.y())
+ * (currentPoint.y() - clickedPoint.y()));
+ if (currentDistance < distance) {
+ distance = currentDistance;
+ closest = currentPoint;
+ }
+ }
+
+ // Remove the closest point from series 1 and append it to series 2
+ m_scatter->remove(closest);
+ m_scatter2->append(closest);
+}
diff --git a/examples/charts/chartsgallery/scatterinteractionswidget.h b/examples/charts/chartsgallery/scatterinteractionswidget.h
new file mode 100644
index 00000000..ba757c53
--- /dev/null
+++ b/examples/charts/chartsgallery/scatterinteractionswidget.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef SCATTERINTERACTIONSWIDGET_H
+#define SCATTERINTERACTIONSWIDGET_H
+
+#include "contentwidget.h"
+
+QT_FORWARD_DECLARE_CLASS(QScatterSeries)
+
+class ScatterInteractionsWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit ScatterInteractionsWidget(QWidget *parent = nullptr);
+
+private slots:
+ void handleClickedPoint(const QPointF &point);
+
+private:
+ QScatterSeries *m_scatter = nullptr;
+ QScatterSeries *m_scatter2 = nullptr;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/scatterwidget.cpp b/examples/charts/chartsgallery/scatterwidget.cpp
new file mode 100644
index 00000000..413a090b
--- /dev/null
+++ b/examples/charts/chartsgallery/scatterwidget.cpp
@@ -0,0 +1,84 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "scatterwidget.h"
+
+#include <QChart>
+#include <QLegendMarker>
+#include <QImage>
+#include <QPainter>
+#include <QScatterSeries>
+#include <QtMath>
+
+ScatterWidget::ScatterWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto series0 = new QScatterSeries;
+ series0->setName("scatter1");
+ series0->setMarkerShape(QScatterSeries::MarkerShapeCircle);
+ series0->setMarkerSize(15.0);
+
+ auto series1 = new QScatterSeries;
+ series1->setName("scatter2");
+ series1->setMarkerShape(QScatterSeries::MarkerShapeRectangle);
+ series1->setMarkerSize(20.0);
+
+ auto series2 = new QScatterSeries;
+ series2->setName("scatter3");
+ series2->setMarkerShape(QScatterSeries::MarkerShapeRectangle);
+ series2->setMarkerSize(30.0);
+ //![1]
+
+ //![2]
+ series0->append(0, 6);
+ series0->append(2, 4);
+ series0->append(3, 8);
+ series0->append(7, 4);
+ series0->append(10, 5);
+
+ *series1 << QPointF(1, 1) << QPointF(3, 3) << QPointF(7, 6) << QPointF(8, 3) << QPointF(10, 2);
+ *series2 << QPointF(1, 5) << QPointF(4, 6) << QPointF(6, 3) << QPointF(9, 5);
+ //![2]
+
+ //![3]
+ QPainterPath starPath;
+ starPath.moveTo(28, 15);
+ for (int i = 1; i < 5; ++i) {
+ starPath.lineTo(14 + 14 * qCos(0.8 * i * M_PI),
+ 15 + 14 * qSin(0.8 * i * M_PI));
+ }
+ starPath.closeSubpath();
+
+ QImage star(30, 30, QImage::Format_ARGB32);
+ star.fill(Qt::transparent);
+
+ QPainter painter(&star);
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.setPen(QRgb(0xf6a625));
+ painter.setBrush(painter.pen().color());
+ painter.drawPath(starPath);
+
+ series2->setBrush(star);
+ series2->setPen(QColor(Qt::transparent));
+ //![3]
+
+ //![4]
+ auto chart = new QChart;
+ chart->addSeries(series0);
+ chart->addSeries(series1);
+ chart->addSeries(series2);
+
+ chart->setTitle("Simple Scatter Chart");
+ chart->createDefaultAxes();
+ chart->setDropShadowEnabled(false);
+ //![4]
+
+ //![5]
+ chart->legend()->setMarkerShape(QLegend::MarkerShapeFromSeries);
+ //![5]
+
+ //![6]
+ createDefaultChartView(chart);
+ //![6]
+}
diff --git a/examples/charts/chartsgallery/scatterwidget.h b/examples/charts/chartsgallery/scatterwidget.h
new file mode 100644
index 00000000..6b836718
--- /dev/null
+++ b/examples/charts/chartsgallery/scatterwidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef SCATTERWIDGET_H
+#define SCATTERWIDGET_H
+
+#include "contentwidget.h"
+
+class ScatterWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit ScatterWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/selectedbarwidget.cpp b/examples/charts/chartsgallery/selectedbarwidget.cpp
new file mode 100644
index 00000000..d54d2201
--- /dev/null
+++ b/examples/charts/chartsgallery/selectedbarwidget.cpp
@@ -0,0 +1,147 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "selectedbarwidget.h"
+
+#include <QBarCategoryAxis>
+#include <QBarSeries>
+#include <QBarSet>
+#include <QChart>
+#include <QChartView>
+#include <QGraphicsLayout>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QValueAxis>
+
+SelectedBarWidget::SelectedBarWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ QBarSet *setChicken = createChickenSet();
+ QBarSet *setPork = createPorkSet();
+ QBarSet *setTurkey = createTurkeySet();
+ QBarSet *setHam = createHamSet();
+ qreal totalSum = setChicken->sum() + setPork->sum() + setTurkey->sum() + setHam->sum();
+ QList<QBarSet *> setList = QList<QBarSet *>{setChicken, setPork, setTurkey, setHam};
+
+ auto series = new QBarSeries;
+ series->append(setList);
+ //![1]
+
+ //![2]
+ auto chart = new QChart;
+ chart->addSeries(series);
+ chart->setTitle(tr("Meat Consumption (Click on bars to select them)"));
+ chart->setAnimationOptions(QChart::SeriesAnimations);
+ chart->legend()->setVisible(true);
+ chart->legend()->setAlignment(Qt::AlignBottom);
+ chart->layout()->setContentsMargins(0, 0, 0, 0);
+ //![2]
+
+ //![3]
+ const auto barSets = series->barSets();
+ for (QBarSet *barSet : barSets)
+ barSet->setSelectedColor(barSet->brush().color().darker());
+ //![3]
+
+ //![4]
+ QStringList categories = createYearCategories();
+ auto axisX = new QBarCategoryAxis;
+ axisX->setCategories(categories);
+ chart->addAxis(axisX, Qt::AlignBottom);
+ series->attachAxis(axisX);
+
+ auto axisY = new QValueAxis;
+ axisY->setRange(0, 20);
+ axisY->setTitleText(tr("Tons"));
+ axisY->setLabelsAngle(-90);
+ axisY->setTitleVisible(true);
+ chart->addAxis(axisY, Qt::AlignLeft);
+ series->attachAxis(axisY);
+ //![4]
+
+ //![5]
+ auto chartView = new QChartView(chart, this);
+ chartView->setRenderHint(QPainter::Antialiasing);
+ //![5]
+
+ //![6]
+ auto labelWidget = new QWidget(this);
+ auto labelLayout = new QHBoxLayout(labelWidget);
+ labelLayout->setAlignment(Qt::AlignCenter);
+
+ auto totalSumLabel = new QLabel(tr("Total sum: %1 T").arg(totalSum), this);
+ labelLayout->addWidget(totalSumLabel);
+ totalSumLabel->setContentsMargins(0, 0, 54, 0);
+
+ auto selectedSumLabel = new QLabel(tr("Selected sum: 0 T"), this);
+ labelLayout->addWidget(selectedSumLabel);
+
+ auto unselectedSumLabel = new QLabel(tr("Unselected sum: %1 T").arg(totalSum), this);
+ labelLayout->addWidget(unselectedSumLabel);
+ unselectedSumLabel->setContentsMargins(54, 0, 0, 0);
+ //![6]
+
+ //![7]
+ QObject::connect(series, &QAbstractBarSeries::clicked, series, [=](int index, QBarSet *set) {
+ set->toggleSelection({index});
+ qreal selectedSum = 0.;
+ for (int i = 0; i < setList.size(); ++i) {
+ auto selectedIndices = setList.at(i)->selectedBars();
+ for (int k = 0; k < selectedIndices.size(); ++k)
+ selectedSum += setList.at(i)->at(selectedIndices.at(k));
+ }
+ selectedSumLabel->setText(tr("Selected sum: %1 T").arg(selectedSum));
+ // Because of rounding errors, selectedSum can result in being bigger than total sum
+ qreal unselectedSum = totalSum - selectedSum < 0 ? 0. : totalSum - selectedSum;
+ unselectedSumLabel->setText(
+ tr("Unselected sum: %1 T")
+ .arg(unselectedSum)
+ );
+ });
+ //![7]
+
+ //![8]
+ auto mainLayout = new QVBoxLayout(this);
+
+ mainLayout->addWidget(chartView);
+ mainLayout->addWidget(labelWidget);
+ //![8]
+}
+
+QBarSet *SelectedBarWidget::createChickenSet()
+{
+ auto set = new QBarSet(tr("Chicken"));
+ set->append({15.0, 12.0, 8.0, 11.5, 13.7});
+ return set;
+}
+
+QBarSet *SelectedBarWidget::createPorkSet()
+{
+ auto set = new QBarSet(tr("Pork"));
+ set->append({9.0, 11.0, 9.0, 7, 12.2});
+ return set;
+}
+
+QBarSet *SelectedBarWidget::createTurkeySet()
+{
+ auto set = new QBarSet(tr("Turkey"));
+ set->append({5.0, 7.6, 9.3, 8, 8.1});
+ return set;
+}
+
+QBarSet *SelectedBarWidget::createHamSet()
+{
+ auto set = new QBarSet(tr("Ham"));
+ set->append({5.4, 7.1, 9.3, 12.3, 11.3});
+ return set;
+}
+
+QStringList SelectedBarWidget::createYearCategories()
+{
+ return QStringList{tr("2017"),
+ tr("2018"),
+ tr("2019"),
+ tr("2020"),
+ tr("2021")};
+}
diff --git a/examples/charts/chartsgallery/selectedbarwidget.h b/examples/charts/chartsgallery/selectedbarwidget.h
new file mode 100644
index 00000000..2e401dcd
--- /dev/null
+++ b/examples/charts/chartsgallery/selectedbarwidget.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef SELECTEDBARWIDGET_H
+#define SELECTEDBARWIDGET_H
+
+#include "contentwidget.h"
+
+#include <QStringList>
+
+QT_FORWARD_DECLARE_CLASS(QBarSet)
+
+class SelectedBarWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit SelectedBarWidget(QWidget *parent = nullptr);
+
+private:
+ QBarSet *createChickenSet();
+ QBarSet *createPorkSet();
+ QBarSet *createTurkeySet();
+ QBarSet *createHamSet();
+ QStringList createYearCategories();
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/splinewidget.cpp b/examples/charts/chartsgallery/splinewidget.cpp
new file mode 100644
index 00000000..1bda42f7
--- /dev/null
+++ b/examples/charts/chartsgallery/splinewidget.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "splinewidget.h"
+
+#include <QChart>
+#include <QSplineSeries>
+
+SplineWidget::SplineWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto series = new QSplineSeries;
+ series->setName("Spline");
+ //![1]
+
+ //![2]
+ series->append(0, 6);
+ series->append(2, 4);
+ series->append(3, 8);
+ series->append(7, 4);
+ series->append(10, 5);
+ *series << QPointF(11, 1) << QPointF(13, 3) << QPointF(17, 6) << QPointF(18, 3) << QPointF(20, 2);
+ //![2]
+
+ //![3]
+ auto chart = new QChart;
+ chart->legend()->hide();
+ chart->addSeries(series);
+ chart->setTitle("Simple Spline Chart");
+ chart->createDefaultAxes();
+ chart->axes(Qt::Vertical).first()->setRange(0, 10);
+ //![3]
+
+ //![4]
+ createDefaultChartView(chart);
+ //![4]
+}
diff --git a/examples/charts/chartsgallery/splinewidget.h b/examples/charts/chartsgallery/splinewidget.h
new file mode 100644
index 00000000..5d9d20cc
--- /dev/null
+++ b/examples/charts/chartsgallery/splinewidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef SPLINEWIDGET_H
+#define SPLINEWIDGET_H
+
+#include "contentwidget.h"
+
+class SplineWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit SplineWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/stackeddrilldownchart.cpp b/examples/charts/chartsgallery/stackeddrilldownchart.cpp
new file mode 100644
index 00000000..89df4ec0
--- /dev/null
+++ b/examples/charts/chartsgallery/stackeddrilldownchart.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "stackeddrilldownchart.h"
+
+#include <QBarCategoryAxis>
+#include <QValueAxis>
+
+StackedDrilldownChart::StackedDrilldownChart(QGraphicsItem *parent, Qt::WindowFlags wFlags)
+ : QChart(QChart::ChartTypeCartesian, parent, wFlags),
+ m_axisX(new QBarCategoryAxis),
+ m_axisY(new QValueAxis)
+{
+ addAxis(m_axisY, Qt::AlignLeft);
+ addAxis(m_axisX, Qt::AlignBottom);
+}
+
+void StackedDrilldownChart::changeSeries(StackedDrilldownSeries *series)
+{
+ if (m_currentSeries)
+ removeSeries(m_currentSeries);
+
+ m_currentSeries = series;
+
+ // Reset axis
+ m_axisX->setCategories(m_currentSeries->categories());
+ addSeries(series);
+ series->attachAxis(m_axisX);
+ series->attachAxis(m_axisY);
+ m_axisY->setRange(0,m_currentSeries->maxValue());
+ setTitle(series->name());
+}
+
+void StackedDrilldownChart::handleClicked(int index, QBarSet *)
+{
+ auto series = static_cast<StackedDrilldownSeries *>(sender());
+ changeSeries(series->drilldownSeries(index));
+}
diff --git a/examples/charts/chartsgallery/stackeddrilldownchart.h b/examples/charts/chartsgallery/stackeddrilldownchart.h
new file mode 100644
index 00000000..85f3a1a0
--- /dev/null
+++ b/examples/charts/chartsgallery/stackeddrilldownchart.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef STACKEDDRILLDOWNCHART_H
+#define STACKEDDRILLDOWNCHART_H
+
+#include "stackeddrilldownseries.h"
+
+#include <QChart>
+
+QT_FORWARD_DECLARE_CLASS(QBarCategoryAxis)
+QT_FORWARD_DECLARE_CLASS(QValueAxis)
+
+//! [1]
+class StackedDrilldownChart : public QChart
+{
+ Q_OBJECT
+public:
+ explicit StackedDrilldownChart(QGraphicsItem *parent = nullptr, Qt::WindowFlags wFlags = {});
+
+ void changeSeries(StackedDrilldownSeries *series);
+
+public slots:
+ void handleClicked(int index, QBarSet *);
+
+private:
+ StackedDrilldownSeries *m_currentSeries = nullptr;
+ QBarCategoryAxis *m_axisX = nullptr;
+ QValueAxis *m_axisY = nullptr;
+};
+//! [1]
+
+#endif
diff --git a/examples/charts/chartsgallery/stackeddrilldownseries.cpp b/examples/charts/chartsgallery/stackeddrilldownseries.cpp
new file mode 100644
index 00000000..39b8ca4d
--- /dev/null
+++ b/examples/charts/chartsgallery/stackeddrilldownseries.cpp
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "stackeddrilldownseries.h"
+
+StackedDrilldownSeries::StackedDrilldownSeries(const QStringList &categories,
+ int maxValue,
+ QObject *parent)
+ : QStackedBarSeries(parent)
+ , m_maxValue(maxValue)
+{
+ m_categories = categories;
+}
+
+void StackedDrilldownSeries::mapDrilldownSeries(int index, StackedDrilldownSeries *drilldownSeries)
+{
+ m_drilldownSeries[index] = drilldownSeries;
+}
+
+StackedDrilldownSeries *StackedDrilldownSeries::drilldownSeries(int index) const
+{
+ return m_drilldownSeries[index];
+}
+
+QStringList StackedDrilldownSeries::categories() const
+{
+ return m_categories;
+}
+
+int StackedDrilldownSeries::maxValue() const
+{
+ return m_maxValue;
+}
diff --git a/examples/charts/chartsgallery/stackeddrilldownseries.h b/examples/charts/chartsgallery/stackeddrilldownseries.h
new file mode 100644
index 00000000..3161811e
--- /dev/null
+++ b/examples/charts/chartsgallery/stackeddrilldownseries.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef STACKEDDRILLDOWNSERIES_H
+#define STACKEDDRILLDOWNSERIES_H
+
+#include <QMap>
+#include <QStackedBarSeries>
+
+//! [1]
+class StackedDrilldownSeries : public QStackedBarSeries
+{
+ Q_OBJECT
+public:
+ StackedDrilldownSeries(const QStringList &categories, int maxValue, QObject *parent = nullptr);
+
+ void mapDrilldownSeries(int index, StackedDrilldownSeries *drilldownSeries);
+ StackedDrilldownSeries *drilldownSeries(int index) const;
+ QStringList categories() const;
+ int maxValue() const;
+
+private:
+ QMap<int, StackedDrilldownSeries *> m_drilldownSeries;
+ QStringList m_categories;
+ int m_maxValue = 0;
+};
+//! [1]
+
+#endif
diff --git a/examples/charts/chartsgallery/stackeddrilldownwidget.cpp b/examples/charts/chartsgallery/stackeddrilldownwidget.cpp
new file mode 100644
index 00000000..5882c0c7
--- /dev/null
+++ b/examples/charts/chartsgallery/stackeddrilldownwidget.cpp
@@ -0,0 +1,91 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "stackeddrilldownchart.h"
+#include "stackeddrilldownseries.h"
+#include "stackeddrilldownwidget.h"
+
+#include <QBarSet>
+#include <QChart>
+#include <QRandomGenerator>
+
+StackedDrilldownWidget::StackedDrilldownWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //! [1]
+ auto drilldownChart = new StackedDrilldownChart;
+ drilldownChart->setAnimationOptions(QChart::SeriesAnimations);
+ //! [1]
+
+ //! [2]
+ // Define categories
+ const QStringList months = {
+ "May", "Jun", "Jul", "Aug", "Sep"
+ };
+ const QStringList weeks = {
+ "week 1", "week 2", "week 3", "week 4"
+ };
+ const QStringList plants = {
+ "Habanero", "Lemon Drop", "Starfish", "Aji Amarillo"
+ };
+ //! [2]
+
+ //! [3]
+ // Create drilldown structure
+ auto seasonSeries = new StackedDrilldownSeries(months, 320, drilldownChart);
+ seasonSeries->setName("Crop by month - Season (Click on bar to drill down)");
+
+ // Each month in season series has drilldown series for weekly data
+ for (int month = 0; month < months.count(); month++) {
+ // Create drilldown series for every week
+ auto weeklySeries = new StackedDrilldownSeries(weeks, 80, drilldownChart);
+ seasonSeries->mapDrilldownSeries(month, weeklySeries);
+
+ // Drilling down from weekly data brings us back to season data.
+ for (int week = 0; week < weeks.count(); week++) {
+ weeklySeries->mapDrilldownSeries(week, seasonSeries);
+ weeklySeries->setName(QString("Crop by week - " + months.at(month)));
+ }
+
+ // Use clicked signal to implement drilldown
+ QObject::connect(weeklySeries, &StackedDrilldownSeries::clicked,
+ drilldownChart, &StackedDrilldownChart::handleClicked);
+ }
+
+ // Enable drilldown from season series using clicked signal
+ QObject::connect(seasonSeries, &StackedDrilldownSeries::clicked,
+ drilldownChart, &StackedDrilldownChart::handleClicked);
+ //! [3]
+
+ //! [4]
+ // Fill monthly and weekly series with data
+ for (const QString &plant : plants) {
+ auto monthlyCrop = new QBarSet(plant);
+ for (int month = 0; month < months.count(); month++) {
+ auto weeklyCrop = new QBarSet(plant);
+ for (int week = 0; week < weeks.count(); week++)
+ *weeklyCrop << QRandomGenerator::global()->bounded(20);
+ // Get the drilldown series from season series and add crop to it.
+ seasonSeries->drilldownSeries(month)->append(weeklyCrop);
+ *monthlyCrop << weeklyCrop->sum();
+ }
+ seasonSeries->append(monthlyCrop);
+ }
+ //! [4]
+
+ //! [5]
+ // Show season series in initial view
+ drilldownChart->changeSeries(seasonSeries);
+ drilldownChart->setTitle(seasonSeries->name());
+ //! [5]
+
+ //! [6]
+ drilldownChart->axes(Qt::Horizontal).first()->setGridLineVisible(false);
+ drilldownChart->legend()->setVisible(true);
+ drilldownChart->legend()->setAlignment(Qt::AlignBottom);
+ //! [6]
+
+ //! [7]
+ createDefaultChartView(drilldownChart);
+ //! [7]
+}
diff --git a/examples/charts/chartsgallery/stackeddrilldownwidget.h b/examples/charts/chartsgallery/stackeddrilldownwidget.h
new file mode 100644
index 00000000..a8c8acff
--- /dev/null
+++ b/examples/charts/chartsgallery/stackeddrilldownwidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef STACKEDDRILLDOWNWIDGET_H
+#define STACKEDDRILLDOWNWIDGET_H
+
+#include "contentwidget.h"
+
+class StackedDrilldownWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit StackedDrilldownWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/temperaturerecordswidget.cpp b/examples/charts/chartsgallery/temperaturerecordswidget.cpp
new file mode 100644
index 00000000..36b748be
--- /dev/null
+++ b/examples/charts/chartsgallery/temperaturerecordswidget.cpp
@@ -0,0 +1,65 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "temperaturerecordswidget.h"
+
+#include <QBarCategoryAxis>
+#include <QBarSeries>
+#include <QBarSet>
+#include <QChart>
+#include <QLegend>
+#include <QStackedBarSeries>
+#include <QValueAxis>
+
+TemperatureRecordsWidget::TemperatureRecordsWidget(QWidget *parent)
+ : ContentWidget(parent)
+{
+ //![1]
+ auto low = new QBarSet("Min");
+ auto high = new QBarSet("Max");
+
+ *low << -52 << -50 << -45.3 << -37.0 << -25.6 << -8.0
+ << -6.0 << -11.8 << -19.7 << -32.8 << -43.0 << -48.0;
+ *high << 11.9 << 12.8 << 18.5 << 26.5 << 32.0 << 34.8
+ << 38.2 << 34.8 << 29.8 << 20.4 << 15.1 << 11.8;
+ //![1]
+
+ //![2]
+ auto series = new QStackedBarSeries;
+ series->append(low);
+ series->append(high);
+ //![2]
+
+ //![3]
+ auto chart = new QChart;
+ chart->addSeries(series);
+ chart->setTitle("Temperature records in Celcius");
+ chart->setAnimationOptions(QChart::SeriesAnimations);
+ //![3]
+
+ //![4]
+ QStringList categories = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+
+ auto axisX = new QBarCategoryAxis;
+ axisX->append(categories);
+ axisX->setTitleText("Month");
+ chart->addAxis(axisX, Qt::AlignBottom);
+ auto axisY = new QValueAxis;
+ axisY->setRange(-52, 52);
+ axisY->setTitleText("Temperature [&deg;C]");
+ chart->addAxis(axisY, Qt::AlignLeft);
+ series->attachAxis(axisX);
+ series->attachAxis(axisY);
+ //![4]
+
+ //![5]
+ chart->legend()->setVisible(true);
+ chart->legend()->setAlignment(Qt::AlignBottom);
+ //![5]
+
+ //![6]
+ createDefaultChartView(chart);
+ //![6]
+}
diff --git a/examples/charts/chartsgallery/temperaturerecordswidget.h b/examples/charts/chartsgallery/temperaturerecordswidget.h
new file mode 100644
index 00000000..eb43717c
--- /dev/null
+++ b/examples/charts/chartsgallery/temperaturerecordswidget.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef TEMPERATURERECORDSWIDGET_H
+#define TEMPERATURERECORDSWIDGET_H
+
+#include "contentwidget.h"
+
+class TemperatureRecordsWidget : public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit TemperatureRecordsWidget(QWidget *parent = nullptr);
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/themewidget.cpp b/examples/charts/chartsgallery/themewidget.cpp
new file mode 100644
index 00000000..31afc403
--- /dev/null
+++ b/examples/charts/chartsgallery/themewidget.cpp
@@ -0,0 +1,353 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "themewidget.h"
+#include "ui_themewidget.h"
+
+#include <QAbstractBarSeries>
+#include <QAreaSeries>
+#include <QBarSet>
+#include <QChartView>
+#include <QCheckBox>
+#include <QComboBox>
+#include <QGridLayout>
+#include <QLegend>
+#include <QLineSeries>
+#include <QPercentBarSeries>
+#include <QPieSeries>
+#include <QPieSlice>
+#include <QRandomGenerator>
+#include <QScatterSeries>
+#include <QSplineSeries>
+#include <QStackedBarSeries>
+#include <QValueAxis>
+
+ThemeWidget::ThemeWidget(QWidget *parent) :
+ ContentWidget(parent),
+ m_listCount(3),
+ m_valueMax(10),
+ m_valueCount(7),
+ m_dataTable(generateRandomData(m_listCount, m_valueMax, m_valueCount)),
+ m_ui(new Ui_ThemeWidgetForm)
+{
+ m_ui->setupUi(this);
+ populateThemeBox();
+ populateAnimationBox();
+ populateLegendBox();
+
+ //create charts
+
+ QChartView *chartView;
+
+ chartView = new QChartView(createAreaChart(), this);
+ m_ui->gridLayout->addWidget(chartView, 1, 0);
+ m_charts << chartView;
+
+ chartView = new QChartView(createPieChart(), this);
+ // Funny things happen if the pie slice labels do not fit the screen, so we ignore size policy
+ chartView->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
+ m_ui->gridLayout->addWidget(chartView, 1, 1);
+ m_charts << chartView;
+
+ //![5]
+ chartView = new QChartView(createLineChart(), this);
+ m_ui->gridLayout->addWidget(chartView, 1, 2);
+ //![5]
+ m_charts << chartView;
+
+ chartView = new QChartView(createBarChart(m_valueCount), this);
+ m_ui->gridLayout->addWidget(chartView, 2, 0);
+ m_charts << chartView;
+
+ chartView = new QChartView(createSplineChart(), this);
+ m_ui->gridLayout->addWidget(chartView, 2, 1);
+ m_charts << chartView;
+
+ chartView = new QChartView(createScatterChart(), this);
+ m_ui->gridLayout->addWidget(chartView, 2, 2);
+ m_charts << chartView;
+
+ // Set defaults
+ m_ui->antialiasCheckBox->setChecked(true);
+
+ updateUI();
+}
+
+ThemeWidget::~ThemeWidget()
+{
+ delete m_ui;
+}
+
+DataTable ThemeWidget::generateRandomData(int listCount, int valueMax, int valueCount) const
+{
+ DataTable dataTable;
+
+ // generate random data
+ for (int i(0); i < listCount; i++) {
+ DataList dataList;
+ qreal yValue(0);
+ for (int j(0); j < valueCount; j++) {
+ yValue = yValue + QRandomGenerator::global()->bounded(valueMax / (qreal) valueCount);
+ QPointF value((j + QRandomGenerator::global()->generateDouble()) * ((qreal) m_valueMax / (qreal) valueCount),
+ yValue);
+ QString label = "Slice " + QString::number(i) + ":" + QString::number(j);
+ dataList << Data(value, label);
+ }
+ dataTable << dataList;
+ }
+
+ return dataTable;
+}
+
+void ThemeWidget::populateThemeBox()
+{
+ // add items to theme combobox
+ m_ui->themeComboBox->addItem("Light", QChart::ChartThemeLight);
+ m_ui->themeComboBox->addItem("Blue Cerulean", QChart::ChartThemeBlueCerulean);
+ m_ui->themeComboBox->addItem("Dark", QChart::ChartThemeDark);
+ m_ui->themeComboBox->addItem("Brown Sand", QChart::ChartThemeBrownSand);
+ m_ui->themeComboBox->addItem("Blue NCS", QChart::ChartThemeBlueNcs);
+ m_ui->themeComboBox->addItem("High Contrast", QChart::ChartThemeHighContrast);
+ m_ui->themeComboBox->addItem("Blue Icy", QChart::ChartThemeBlueIcy);
+ m_ui->themeComboBox->addItem("Qt", QChart::ChartThemeQt);
+}
+
+void ThemeWidget::populateAnimationBox()
+{
+ // add items to animation combobox
+ m_ui->animatedComboBox->addItem("No Animations", QChart::NoAnimation);
+ m_ui->animatedComboBox->addItem("GridAxis Animations", QChart::GridAxisAnimations);
+ m_ui->animatedComboBox->addItem("Series Animations", QChart::SeriesAnimations);
+ m_ui->animatedComboBox->addItem("All Animations", QChart::AllAnimations);
+}
+
+void ThemeWidget::populateLegendBox()
+{
+ // add items to legend combobox
+ m_ui->legendComboBox->addItem("No Legend ", 0);
+ m_ui->legendComboBox->addItem("Legend Top", Qt::AlignTop);
+ m_ui->legendComboBox->addItem("Legend Bottom", Qt::AlignBottom);
+ m_ui->legendComboBox->addItem("Legend Left", Qt::AlignLeft);
+ m_ui->legendComboBox->addItem("Legend Right", Qt::AlignRight);
+}
+
+QChart *ThemeWidget::createAreaChart() const
+{
+ auto chart = new QChart;
+ chart->setTitle("Area Chart");
+
+ // The lower series initialized to zero values
+ QLineSeries *lowerSeries = nullptr;
+ QString name("Series ");
+ int nameIndex = 0;
+ for (int i(0); i < m_dataTable.count(); i++) {
+ auto upperSeries = new QLineSeries(chart);
+ for (int j(0); j < m_dataTable[i].count(); j++) {
+ Data data = m_dataTable[i].at(j);
+ if (lowerSeries) {
+ const auto &points = lowerSeries->points();
+ upperSeries->append(QPointF(j, points[i].y() + data.first.y()));
+ } else {
+ upperSeries->append(QPointF(j, data.first.y()));
+ }
+ }
+ auto area = new QAreaSeries(upperSeries, lowerSeries);
+ area->setName(name + QString::number(nameIndex));
+ nameIndex++;
+ chart->addSeries(area);
+ lowerSeries = upperSeries;
+ }
+
+ chart->createDefaultAxes();
+ chart->axes(Qt::Horizontal).first()->setRange(0, m_valueCount - 1);
+ chart->axes(Qt::Vertical).first()->setRange(0, m_valueMax);
+ // Add space to label to add space between labels and axis
+ auto axisY = qobject_cast<QValueAxis *>(chart->axes(Qt::Vertical).first());
+ Q_ASSERT(axisY);
+ axisY->setLabelFormat("%.1f ");
+
+ return chart;
+}
+
+QChart *ThemeWidget::createBarChart(int valueCount) const
+{
+ Q_UNUSED(valueCount);
+ auto chart = new QChart;
+ chart->setTitle("Bar Chart");
+
+ auto series = new QStackedBarSeries(chart);
+ for (int i(0); i < m_dataTable.count(); i++) {
+ auto set = new QBarSet("Bar set " + QString::number(i));
+ for (const Data &data : m_dataTable[i])
+ *set << data.first.y();
+ series->append(set);
+ }
+ chart->addSeries(series);
+
+ chart->createDefaultAxes();
+ chart->axes(Qt::Vertical).first()->setRange(0, m_valueMax * 2);
+ // Add space to label to add space between labels and axis
+ auto axisY = qobject_cast<QValueAxis *>(chart->axes(Qt::Vertical).first());
+ Q_ASSERT(axisY);
+ axisY->setLabelFormat("%.1f ");
+
+ return chart;
+}
+
+QChart *ThemeWidget::createLineChart() const
+{
+ //![1]
+ auto chart = new QChart;
+ chart->setTitle("Line Chart");
+ //![1]
+
+ //![2]
+ QString name("Series ");
+ int nameIndex = 0;
+ for (const DataList &list : m_dataTable) {
+ auto series = new QLineSeries(chart);
+ for (const Data &data : list)
+ series->append(data.first);
+ series->setName(name + QString::number(nameIndex));
+ nameIndex++;
+ chart->addSeries(series);
+ }
+ //![2]
+
+ //![3]
+ chart->createDefaultAxes();
+ chart->axes(Qt::Horizontal).first()->setRange(0, m_valueMax);
+ chart->axes(Qt::Vertical).first()->setRange(0, m_valueCount);
+ //![3]
+ //![4]
+ // Add space to label to add space between labels and axis
+ auto axisY = qobject_cast<QValueAxis *>(chart->axes(Qt::Vertical).first());
+ Q_ASSERT(axisY);
+ axisY->setLabelFormat("%.1f ");
+ //![4]
+
+ return chart;
+}
+
+QChart *ThemeWidget::createPieChart() const
+{
+ auto chart = new QChart;
+ chart->setTitle("Pie Chart");
+
+ auto series = new QPieSeries(chart);
+ for (const Data &data : m_dataTable[0]) {
+ QPieSlice *slice = series->append(data.second, data.first.y());
+ if (data == m_dataTable[0].first()) {
+ // Show the first slice exploded with label
+ slice->setLabelVisible();
+ slice->setExploded();
+ slice->setExplodeDistanceFactor(0.5);
+ }
+ }
+ series->setPieSize(0.4);
+ chart->addSeries(series);
+
+ return chart;
+}
+
+QChart *ThemeWidget::createSplineChart() const
+{
+ auto chart = new QChart;
+ chart->setTitle("Spline Chart");
+ QString name("Series ");
+ int nameIndex = 0;
+ for (const DataList &list : m_dataTable) {
+ auto series = new QSplineSeries(chart);
+ for (const Data &data : list)
+ series->append(data.first);
+ series->setName(name + QString::number(nameIndex));
+ nameIndex++;
+ chart->addSeries(series);
+ }
+
+ chart->createDefaultAxes();
+ chart->axes(Qt::Horizontal).first()->setRange(0, m_valueMax);
+ chart->axes(Qt::Vertical).first()->setRange(0, m_valueCount);
+
+ // Add space to label to add space between labels and axis
+ auto axisY = qobject_cast<QValueAxis *>(chart->axes(Qt::Vertical).first());
+ Q_ASSERT(axisY);
+ axisY->setLabelFormat("%.1f ");
+ return chart;
+}
+
+QChart *ThemeWidget::createScatterChart() const
+{
+ // scatter chart
+ auto chart = new QChart;
+ chart->setTitle("Scatter Chart");
+ QString name("Series ");
+ int nameIndex = 0;
+ for (const DataList &list : m_dataTable) {
+ auto series = new QScatterSeries(chart);
+ for (const Data &data : list)
+ series->append(data.first);
+ series->setName(name + QString::number(nameIndex));
+ nameIndex++;
+ chart->addSeries(series);
+ }
+
+ chart->createDefaultAxes();
+ chart->axes(Qt::Horizontal).first()->setRange(0, m_valueMax);
+ chart->axes(Qt::Vertical).first()->setRange(0, m_valueCount);
+ // Add space to label to add space between labels and axis
+ auto axisY = qobject_cast<QValueAxis *>(chart->axes(Qt::Vertical).first());
+ Q_ASSERT(axisY);
+ axisY->setLabelFormat("%.1f ");
+ return chart;
+}
+
+void ThemeWidget::updateUI()
+{
+ //![6]
+ auto theme = static_cast<QChart::ChartTheme>(
+ m_ui->themeComboBox->itemData(m_ui->themeComboBox->currentIndex()).toInt());
+ //![6]
+ const auto charts = m_charts;
+ if (!m_charts.isEmpty() && m_charts.at(0)->chart()->theme() != theme) {
+ for (QChartView *chartView : charts) {
+ //![7]
+ chartView->chart()->setTheme(theme);
+ //![7]
+ }
+ }
+
+ // Update antialiasing
+ //![11]
+ bool checked = m_ui->antialiasCheckBox->isChecked();
+ for (QChartView *chart : charts)
+ chart->setRenderHint(QPainter::Antialiasing, checked);
+ //![11]
+
+ // Update animation options
+ //![9]
+ QChart::AnimationOptions options(
+ m_ui->animatedComboBox->itemData(m_ui->animatedComboBox->currentIndex()).toInt());
+ if (!m_charts.isEmpty() && m_charts.at(0)->chart()->animationOptions() != options) {
+ for (QChartView *chartView : charts)
+ chartView->chart()->setAnimationOptions(options);
+ }
+ //![9]
+
+ // Update legend alignment
+ //![10]
+ Qt::Alignment alignment(
+ m_ui->legendComboBox->itemData(m_ui->legendComboBox->currentIndex()).toInt());
+
+ if (!alignment) {
+ for (QChartView *chartView : charts)
+ chartView->chart()->legend()->hide();
+ } else {
+ for (QChartView *chartView : charts) {
+ chartView->chart()->legend()->setAlignment(alignment);
+ chartView->chart()->legend()->show();
+ }
+ }
+ //![10]
+}
+
diff --git a/examples/charts/chartsgallery/themewidget.h b/examples/charts/chartsgallery/themewidget.h
new file mode 100644
index 00000000..e630040c
--- /dev/null
+++ b/examples/charts/chartsgallery/themewidget.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef THEMEWIDGET_H
+#define THEMEWIDGET_H
+
+#include "contentwidget.h"
+
+QT_FORWARD_DECLARE_CLASS(QChart)
+QT_FORWARD_DECLARE_CLASS(QChartView)
+QT_FORWARD_DECLARE_CLASS(Ui_ThemeWidgetForm);
+
+typedef QPair<QPointF, QString> Data;
+typedef QList<Data> DataList;
+typedef QList<DataList> DataTable;
+
+class ThemeWidget: public ContentWidget
+{
+ Q_OBJECT
+public:
+ explicit ThemeWidget(QWidget *parent = nullptr);
+ ~ThemeWidget();
+
+private slots:
+ void updateUI();
+
+private:
+ DataTable generateRandomData(int listCount, int valueMax, int valueCount) const;
+ void populateThemeBox();
+ void populateAnimationBox();
+ void populateLegendBox();
+ void connectSignals();
+ QChart *createAreaChart() const;
+ QChart *createBarChart(int valueCount) const;
+ QChart *createPieChart() const;
+ QChart *createLineChart() const;
+ QChart *createSplineChart() const;
+ QChart *createScatterChart() const;
+
+private:
+ int m_listCount;
+ int m_valueMax;
+ int m_valueCount;
+ QList<QChartView *> m_charts;
+ DataTable m_dataTable;
+
+ Ui_ThemeWidgetForm *m_ui;
+};
+
+#endif
diff --git a/examples/charts/chartsgallery/themewidget.ui b/examples/charts/chartsgallery/themewidget.ui
new file mode 100644
index 00000000..9ea2bb7c
--- /dev/null
+++ b/examples/charts/chartsgallery/themewidget.ui
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ThemeWidgetForm</class>
+ <widget class="QWidget" name="ThemeWidgetForm">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>900</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0" colspan="3">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="themeLabel">
+ <property name="text">
+ <string>Theme:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="themeComboBox"/>
+ </item>
+ <item>
+ <widget class="QLabel" name="animatedLabel">
+ <property name="text">
+ <string>Animation:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="animatedComboBox"/>
+ </item>
+ <item>
+ <widget class="QLabel" name="legendLabel">
+ <property name="text">
+ <string>Legend:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="legendComboBox"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="antialiasCheckBox">
+ <property name="text">
+ <string>Anti-aliasing</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>themeComboBox</sender>
+ <signal>currentIndexChanged(int)</signal>
+ <receiver>ThemeWidgetForm</receiver>
+ <slot>updateUI()</slot>
+ </connection>
+ <connection>
+ <sender>antialiasCheckBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>ThemeWidgetForm</receiver>
+ <slot>updateUI()</slot>
+ </connection>
+ <connection>
+ <sender>legendComboBox</sender>
+ <signal>currentIndexChanged(int)</signal>
+ <receiver>ThemeWidgetForm</receiver>
+ <slot>updateUI()</slot>
+ </connection>
+ <connection>
+ <sender>animatedComboBox</sender>
+ <signal>currentIndexChanged(int)</signal>
+ <receiver>ThemeWidgetForm</receiver>
+ <slot>updateUI()</slot>
+ </connection>
+ </connections>
+ <slots>
+ <slot>updateUI()</slot>
+ </slots>
+</ui>