1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Data Visualization module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 or (at your option) any later version |
20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by |
21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
22 | ** included in the packaging of this file. Please review the following |
23 | ** information to ensure the GNU General Public License requirements will |
24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
25 | ** |
26 | ** $QT_END_LICENSE$ |
27 | ** |
28 | ****************************************************************************/ |
29 | |
30 | #include "axisrendercache_p.h" |
31 | |
32 | #include <QtGui/QFontMetrics> |
33 | |
34 | QT_BEGIN_NAMESPACE_DATAVISUALIZATION |
35 | |
36 | AxisRenderCache::AxisRenderCache() |
37 | : m_type(QAbstract3DAxis::AxisTypeNone), |
38 | m_min(0.0f), |
39 | m_max(10.0f), |
40 | m_segmentCount(5), |
41 | m_subSegmentCount(1), |
42 | m_reversed(false), |
43 | m_font(QFont(QStringLiteral("Arial" ))), |
44 | m_formatter(0), |
45 | m_ctrlFormatter(0), |
46 | m_drawer(0), |
47 | m_positionsDirty(true), |
48 | m_translate(0.0f), |
49 | m_scale(1.0f), |
50 | m_labelAutoRotation(0.0f), |
51 | m_titleVisible(false), |
52 | m_titleFixed(false) |
53 | { |
54 | } |
55 | |
56 | AxisRenderCache::~AxisRenderCache() |
57 | { |
58 | foreach (LabelItem *label, m_labelItems) |
59 | delete label; |
60 | m_titleItem.clear(); |
61 | |
62 | delete m_formatter; |
63 | } |
64 | |
65 | void AxisRenderCache::setDrawer(Drawer *drawer) |
66 | { |
67 | m_drawer = drawer; |
68 | m_font = m_drawer->font(); |
69 | if (m_drawer) |
70 | updateTextures(); |
71 | } |
72 | |
73 | void AxisRenderCache::setType(QAbstract3DAxis::AxisType type) |
74 | { |
75 | m_type = type; |
76 | |
77 | // If type is set, it means completely new axis instance, so clear all old data |
78 | m_labels.clear(); |
79 | m_title.clear(); |
80 | m_min = 0.0f; |
81 | m_max = 10.0f; |
82 | m_segmentCount = 5; |
83 | m_subSegmentCount = 1; |
84 | m_labelFormat.clear(); |
85 | |
86 | m_titleItem.clear(); |
87 | foreach (LabelItem *label, m_labelItems) |
88 | delete label; |
89 | m_labelItems.clear(); |
90 | } |
91 | |
92 | void AxisRenderCache::setTitle(const QString &title) |
93 | { |
94 | if (m_title != title) { |
95 | m_title = title; |
96 | // Generate axis label texture |
97 | if (m_drawer) |
98 | m_drawer->generateLabelItem(item&: m_titleItem, text: title); |
99 | } |
100 | } |
101 | |
102 | void AxisRenderCache::setLabels(const QStringList &labels) |
103 | { |
104 | if (m_labels != labels) { |
105 | int newSize(labels.size()); |
106 | int oldSize(m_labels.size()); |
107 | |
108 | for (int i = newSize; i < oldSize; i++) |
109 | delete m_labelItems.takeLast(); |
110 | |
111 | m_labelItems.reserve(alloc: newSize); |
112 | |
113 | int widest = maxLabelWidth(labels); |
114 | |
115 | for (int i = 0; i < newSize; i++) { |
116 | if (i >= oldSize) |
117 | m_labelItems.append(t: new LabelItem); |
118 | if (m_drawer) { |
119 | if (labels.at(i).isEmpty()) { |
120 | m_labelItems[i]->clear(); |
121 | } else if (i >= oldSize || labels.at(i) != m_labels.at(i) |
122 | || m_labelItems[i]->size().width() != widest) { |
123 | m_drawer->generateLabelItem(item&: *m_labelItems[i], text: labels.at(i), widestLabel: widest); |
124 | } |
125 | } |
126 | } |
127 | m_labels = labels; |
128 | } |
129 | } |
130 | |
131 | void AxisRenderCache::updateAllPositions() |
132 | { |
133 | // As long as grid and subgrid lines are drawn identically, we can further optimize |
134 | // by caching all grid and subgrid positions into a single vector. |
135 | // If subgrid lines are ever themed separately, this array will probably become obsolete. |
136 | if (m_formatter) { |
137 | int gridCount = m_formatter->gridPositions().size(); |
138 | int subGridCount = m_formatter->subGridPositions().size(); |
139 | int labelCount = m_formatter->labelPositions().size(); |
140 | int fullSize = gridCount + subGridCount; |
141 | |
142 | m_adjustedGridLinePositions.resize(asize: fullSize); |
143 | m_adjustedLabelPositions.resize(asize: labelCount); |
144 | int index = 0; |
145 | int grid = 0; |
146 | int label = 0; |
147 | float position = 0.0f; |
148 | for (; label < labelCount; label++) { |
149 | position = m_formatter->labelPositions().at(i: label); |
150 | if (m_reversed) |
151 | position = 1.0f - position; |
152 | m_adjustedLabelPositions[label] = position * m_scale + m_translate; |
153 | } |
154 | for (; grid < gridCount; grid++) { |
155 | position = m_formatter->gridPositions().at(i: grid); |
156 | if (m_reversed) |
157 | position = 1.0f - position; |
158 | m_adjustedGridLinePositions[index++] = position * m_scale + m_translate; |
159 | } |
160 | for (int subGrid = 0; subGrid < subGridCount; subGrid++) { |
161 | position = m_formatter->subGridPositions().at(i: subGrid); |
162 | if (m_reversed) |
163 | position = 1.0f - position; |
164 | m_adjustedGridLinePositions[index++] = position * m_scale + m_translate; |
165 | } |
166 | |
167 | m_positionsDirty = false; |
168 | } |
169 | } |
170 | |
171 | void AxisRenderCache::updateTextures() |
172 | { |
173 | m_font = m_drawer->font(); |
174 | |
175 | if (m_title.isEmpty()) |
176 | m_titleItem.clear(); |
177 | else |
178 | m_drawer->generateLabelItem(item&: m_titleItem, text: m_title); |
179 | |
180 | int widest = maxLabelWidth(labels: m_labels); |
181 | |
182 | for (int i = 0; i < m_labels.size(); i++) { |
183 | if (m_labels.at(i).isEmpty()) |
184 | m_labelItems[i]->clear(); |
185 | else |
186 | m_drawer->generateLabelItem(item&: *m_labelItems[i], text: m_labels.at(i), widestLabel: widest); |
187 | } |
188 | } |
189 | |
190 | void AxisRenderCache::clearLabels() |
191 | { |
192 | m_titleItem.clear(); |
193 | for (int i = 0; i < m_labels.size(); i++) |
194 | m_labelItems[i]->clear(); |
195 | } |
196 | |
197 | int AxisRenderCache::maxLabelWidth(const QStringList &labels) const |
198 | { |
199 | int labelWidth = 0; |
200 | QFont labelFont = m_font; |
201 | labelFont.setPointSize(textureFontSize); |
202 | QFontMetrics labelFM(labelFont); |
203 | for (int i = 0; i < labels.size(); i++) { |
204 | int newWidth = labelFM.horizontalAdvance(labels.at(i)); |
205 | if (labelWidth < newWidth) |
206 | labelWidth = newWidth; |
207 | } |
208 | return labelWidth; |
209 | } |
210 | |
211 | QT_END_NAMESPACE_DATAVISUALIZATION |
212 | |