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