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 | |
16 | QT_BEGIN_NAMESPACE |
17 | |
18 | ChartThemeManager::ChartThemeManager(QChart* chart) : |
19 | m_chart(chart) |
20 | { |
21 | } |
22 | |
23 | |
24 | void 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 |
69 | void 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 |
85 | void 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 | |
93 | int 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 | |
107 | int 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 | |
118 | void 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 | |
125 | void ChartThemeManager::handleSeriesRemoved(QAbstractSeries *series) |
126 | { |
127 | m_seriesMap.remove(key: series); |
128 | } |
129 | |
130 | void ChartThemeManager::handleAxisAdded(QAbstractAxis *axis) |
131 | { |
132 | m_axisList.append(t: axis); |
133 | axis->d_ptr->initializeTheme(theme: m_theme.data(),forced: false); |
134 | } |
135 | |
136 | void ChartThemeManager::handleAxisRemoved(QAbstractAxis *axis) |
137 | { |
138 | m_axisList.removeAll(t: axis); |
139 | } |
140 | |
141 | void 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 | } |
147 | QList<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 | |
173 | QColor 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 | |
184 | QColor 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 | |
224 | QT_END_NAMESPACE |
225 | |
226 | #include "moc_chartthememanager_p.cpp" |
227 | |