1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3#include <private/qabstractseries_p.h>
4#include <private/qabstractaxis_p.h>
5//themes
6#include <private/chartthemesystem_p.h>
7#include <private/chartthemelight_p.h>
8#include <private/chartthemebluecerulean_p.h>
9#include <private/chartthemedark_p.h>
10#include <private/chartthemebrownsand_p.h>
11#include <private/chartthemebluencs_p.h>
12#include <private/chartthemehighcontrast_p.h>
13#include <private/chartthemeblueicy_p.h>
14#include <private/chartthemeqt_p.h>
15
16QT_BEGIN_NAMESPACE
17
18ChartThemeManager::ChartThemeManager(QChart* chart) :
19 m_chart(chart)
20{
21}
22
23
24void ChartThemeManager::setTheme(QChart::ChartTheme theme)
25{
26 if (m_theme.isNull() || theme != m_theme->id()) {
27 switch (theme) {
28 case QChart::ChartThemeLight:
29 m_theme.reset(other: new ChartThemeLight());
30 break;
31 case QChart::ChartThemeBlueCerulean:
32 m_theme.reset(other: new ChartThemeBlueCerulean());
33 break;
34 case QChart::ChartThemeDark:
35 m_theme.reset(other: new ChartThemeDark());
36 break;
37 case QChart::ChartThemeBrownSand:
38 m_theme.reset(other: new ChartThemeBrownSand());
39 break;
40 case QChart::ChartThemeBlueNcs:
41 m_theme.reset(other: new ChartThemeBlueNcs());
42 break;
43 case QChart::ChartThemeHighContrast:
44 m_theme.reset(other: new ChartThemeHighContrast());
45 break;
46 case QChart::ChartThemeBlueIcy:
47 m_theme.reset(other: new ChartThemeBlueIcy());
48 break;
49 case QChart::ChartThemeQt:
50 m_theme.reset(other: new ChartThemeQt());
51 break;
52 default:
53 m_theme.reset(other: new ChartThemeSystem());
54 break;
55 }
56
57 if (!m_theme.isNull()) {
58 decorateChart(chart: m_chart,theme: m_theme.data());
59 decorateLegend(legend: m_chart->legend(),theme: m_theme.data());
60 foreach (QAbstractAxis* axis, m_axisList)
61 axis->d_ptr->initializeTheme(theme: m_theme.data(), forced: true);
62 foreach (QAbstractSeries* series, m_seriesMap.keys())
63 series->d_ptr->initializeTheme(index: m_seriesMap[series], theme: m_theme.data(), forced: true);
64 }
65 }
66}
67
68// decorateChart is only called when theme is forcibly initialized
69void ChartThemeManager::decorateChart(QChart *chart, ChartTheme *theme) const
70{
71 chart->setBackgroundBrush(theme->chartBackgroundGradient());
72
73 QPen pen(Qt::transparent);
74 QBrush brush;
75 chart->setPlotAreaBackgroundBrush(brush);
76 chart->setPlotAreaBackgroundPen(pen);
77 chart->setPlotAreaBackgroundVisible(false);
78
79 chart->setTitleFont(theme->masterFont());
80 chart->setTitleBrush(theme->labelBrush());
81 chart->setDropShadowEnabled(theme->isBackgroundDropShadowEnabled());
82}
83
84// decorateLegend is only called when theme is forcibly initialized
85void ChartThemeManager::decorateLegend(QLegend *legend, ChartTheme *theme) const
86{
87 legend->setPen(theme->axisLinePen());
88 legend->setBrush(theme->chartBackgroundGradient());
89 legend->setFont(theme->labelFont());
90 legend->setLabelBrush(theme->labelBrush());
91}
92
93int ChartThemeManager::createIndexKey(const QList<int> &keys) const
94{
95 auto keysCopy = keys;
96 std::sort(first: keysCopy.begin(), last: keysCopy.end());
97
98 int i = 0;
99 for (const auto key : keysCopy) {
100 if (i != key)
101 break;
102 ++i;
103 }
104 return i;
105}
106
107int ChartThemeManager::seriesCount(QAbstractSeries::SeriesType type) const
108{
109 int count = 0;
110 QList<QAbstractSeries *> series = m_seriesMap.keys();
111 foreach(QAbstractSeries *s, series) {
112 if (s->type() == type)
113 count++;
114 }
115 return count;
116}
117
118void ChartThemeManager::handleSeriesAdded(QAbstractSeries *series)
119{
120 int key = createIndexKey(keys: m_seriesMap.values());
121 m_seriesMap.insert(key: series,value: key);
122 series->d_ptr->initializeTheme(index: key,theme: m_theme.data(),forced: false);
123}
124
125void ChartThemeManager::handleSeriesRemoved(QAbstractSeries *series)
126{
127 m_seriesMap.remove(key: series);
128}
129
130void ChartThemeManager::handleAxisAdded(QAbstractAxis *axis)
131{
132 m_axisList.append(t: axis);
133 axis->d_ptr->initializeTheme(theme: m_theme.data(),forced: false);
134}
135
136void ChartThemeManager::handleAxisRemoved(QAbstractAxis *axis)
137{
138 m_axisList.removeAll(t: axis);
139}
140
141void ChartThemeManager::updateSeries(QAbstractSeries *series)
142{
143 if(m_seriesMap.contains(key: series)){
144 series->d_ptr->initializeTheme(index: m_seriesMap[series],theme: m_theme.data(),forced: false);
145 }
146}
147QList<QGradient> ChartThemeManager::generateSeriesGradients(const QList<QColor>& colors)
148{
149 QList<QGradient> result;
150 // Generate gradients in HSV color space
151 foreach (const QColor &color, colors) {
152 QLinearGradient g;
153 qreal h = color.hsvHueF();
154 qreal s = color.hsvSaturationF();
155
156 QColor start = color;
157 start.setHsvF(h, s: 0.0, v: 1.0);
158 g.setColorAt(pos: 0.0, color: start);
159
160 g.setColorAt(pos: 0.5, color);
161
162 QColor end = color;
163 end.setHsvF(h, s, v: 0.25);
164 g.setColorAt(pos: 1.0, color: end);
165
166 result << g;
167 }
168
169 return result;
170}
171
172
173QColor ChartThemeManager::colorAt(const QColor &start, const QColor &end, qreal pos)
174{
175 Q_ASSERT(pos >= 0.0 && pos <= 1.0);
176 qreal r = start.redF() + ((end.redF() - start.redF()) * pos);
177 qreal g = start.greenF() + ((end.greenF() - start.greenF()) * pos);
178 qreal b = start.blueF() + ((end.blueF() - start.blueF()) * pos);
179 QColor c;
180 c.setRgbF(r, g, b);
181 return c;
182}
183
184QColor ChartThemeManager::colorAt(const QGradient &gradient, qreal pos)
185{
186 Q_ASSERT(pos >= 0 && pos <= 1.0);
187
188 QGradientStops stops = gradient.stops();
189 int count = stops.size();
190
191 // find previous stop relative to position
192 QGradientStop prev = stops.first();
193 for (int i = 0; i < count; i++) {
194 QGradientStop stop = stops.at(i);
195 if (pos > stop.first)
196 prev = stop;
197
198 // given position is actually a stop position?
199 if (pos == stop.first) {
200 //qDebug() << "stop color" << pos;
201 return stop.second;
202 }
203 }
204
205 // find next stop relative to position
206 QGradientStop next = stops.last();
207 for (int i = count - 1; i >= 0; i--) {
208 QGradientStop stop = stops.at(i);
209 if (pos < stop.first)
210 next = stop;
211 }
212
213 //qDebug() << "prev" << prev.first << "pos" << pos << "next" << next.first;
214
215 qreal range = next.first - prev.first;
216 qreal posDelta = pos - prev.first;
217 qreal relativePos = posDelta / range;
218
219 //qDebug() << "range" << range << "posDelta" << posDelta << "relativePos" << relativePos;
220
221 return colorAt(start: prev.second, end: next.second, pos: relativePos);
222}
223
224QT_END_NAMESPACE
225
226#include "moc_chartthememanager_p.cpp"
227

source code of qtcharts/src/charts/chartthememanager.cpp