1 | // Copyright (C) 2023 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include <QtGraphsWidgets/q3dbarswidgetitem.h> |
5 | #include <private/q3dbarswidgetitem_p.h> |
6 | #include <private/qquickgraphsbars_p.h> |
7 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | /*! |
11 | * \class Q3DBarsWidgetItem |
12 | * \inmodule QtGraphsWidgets |
13 | * \ingroup graphs_3D_widgets |
14 | * \brief The Q3DBarsWidgetItem class provides methods for rendering 3D bar graphs. |
15 | * |
16 | * This class enables developers to render 3D bar graphs and view them by |
17 | * freely rotating the scene. Rotation is achieved by holding down the right |
18 | * mouse button and moving the mouse, while zooming is accomplished using |
19 | * the mouse wheel. If enabled, selection is performed with the left mouse |
20 | * button. The scene can be reset to the default camera view by clicking the |
21 | * mouse wheel. On touch devices, rotation is achieved by tap-and-move, |
22 | * selection by tap-and-hold, and zooming by pinch. |
23 | * |
24 | * If no axes are set explicitly for Q3DBarsWidgetItem, temporary default axes without |
25 | * labels are created. These default axes can be modified via axis accessors, |
26 | * but as soon as any axis is set explicitly for the orientation, the default |
27 | * axis for that orientation is destroyed. |
28 | * |
29 | * Q3DBarsWidgetItem supports more than one visible series at the same time. All series |
30 | * don't need to have the same number of rows and columns. Row and column |
31 | * labels are taken from the first added series unless explicitly defined |
32 | * for row and column axes. |
33 | * |
34 | * Q3DBarsWidgetItem has transparency support. This feature allows you to adjust the |
35 | * opacity of the bars, making them partially see-through, fully transparent, |
36 | * or opaque. |
37 | * |
38 | * \section1 How to construct a minimal Q3DBarsWidgetItem graph |
39 | * |
40 | * First, construct an instance of Q3DBarsWidgetItem: |
41 | * |
42 | * \snippet doc_src_q3dbars_construction.cpp 4 |
43 | * |
44 | * After constructing Q3DBarsWidgetItem, you can set the data window by changing the range |
45 | * on the row and column axes. It is not mandatory, as the data window will default |
46 | * to showing all of the data in the series. If the amount of data is large, it |
47 | * is usually preferable to show just a portion of it. For example, let's set |
48 | * the data window to display the first five rows and columns: |
49 | * |
50 | * \snippet doc_src_q3dbars_construction.cpp 0 |
51 | * |
52 | * Now, Q3DBarsWidgetItem is ready to receive data to be rendered. Create a series with one |
53 | * row of 5 values: |
54 | * |
55 | * \snippet doc_src_q3dbars_construction.cpp 1 |
56 | * |
57 | * \note We set the data window to 5 x 5, but we are adding only one row of |
58 | * data. This is okay; the rest of the rows will just be blank. |
59 | * |
60 | * Finally you will need to set it visible: |
61 | * |
62 | * \snippet doc_src_q3dbars_construction.cpp 2 |
63 | * |
64 | * The complete code needed to create and display this graph is: |
65 | * |
66 | * \snippet doc_src_q3dbars_construction.cpp 3 |
67 | * |
68 | * And this is what those few lines of code produce: |
69 | * |
70 | * \image q3dbars-minimal.png |
71 | * |
72 | * The scene can be rotated, zoomed into, and a bar can be selected to view its |
73 | * value, but no other interactions are included in this minimal code example. |
74 | * You can learn more by familiarizing yourself with the examples provided, like |
75 | * the \l{Simple Bar Graph}. |
76 | * |
77 | * \sa Q3DScatterWidgetItem, Q3DSurfaceWidgetItem, {Qt Graphs C++ Classes for 3D} |
78 | */ |
79 | |
80 | /*! |
81 | * Constructs a new 3D bar graph with the optional \a parent. |
82 | */ |
83 | Q3DBarsWidgetItem::Q3DBarsWidgetItem(QObject *parent) |
84 | : Q3DGraphsWidgetItem(*(new Q3DBarsWidgetItemPrivate()), parent, QStringLiteral("Bars3D" )) |
85 | {} |
86 | |
87 | /*! |
88 | * Destroys the 3D bar graph. |
89 | */ |
90 | Q3DBarsWidgetItem::~Q3DBarsWidgetItem() {} |
91 | |
92 | /*! |
93 | * \property Q3DBarsWidgetItem::primarySeries |
94 | * |
95 | * \brief The primary series of the graph. |
96 | * |
97 | * Sets \a series as the primary series of the graph. The primary series |
98 | * determines the row and column axis labels when the labels are not explicitly |
99 | * set to the axes. |
100 | * |
101 | * If the specified series is not yet added to the graph, setting it as the |
102 | * primary series will also implicitly add it to the graph. |
103 | * |
104 | * If the primary series itself is removed from the graph, this property |
105 | * resets to default. |
106 | * |
107 | * If \a series is null, this property resets to default. |
108 | * Defaults to the first added series or zero if no series are added to the |
109 | * graph. |
110 | */ |
111 | void Q3DBarsWidgetItem::setPrimarySeries(QBar3DSeries *series) |
112 | { |
113 | graphBars()->setPrimarySeries(series); |
114 | emit primarySeriesChanged(series); |
115 | } |
116 | |
117 | QBar3DSeries *Q3DBarsWidgetItem::primarySeries() const |
118 | { |
119 | return graphBars()->primarySeries(); |
120 | } |
121 | |
122 | /*! |
123 | * Adds the \a series to the graph. A graph can contain multiple series, but |
124 | * only one set of axes, so the rows and columns of all series must match for |
125 | * the visualized data to be meaningful. If the graph has multiple visible |
126 | * series, only the primary series will generate the row or column labels on the |
127 | * axes in cases where the labels are not explicitly set for the axes. If the |
128 | * newly added series has specified a selected bar, it will be highlighted and |
129 | * any existing selection will be cleared. Only one added series can have an |
130 | * active selection. |
131 | * |
132 | * \sa seriesList(), primarySeries, Q3DGraphsWidgetItem::hasSeries() |
133 | */ |
134 | void Q3DBarsWidgetItem::addSeries(QBar3DSeries *series) |
135 | { |
136 | graphBars()->addSeries(series); |
137 | } |
138 | |
139 | /*! |
140 | * Removes the \a series from the graph. |
141 | * |
142 | * \sa Q3DGraphsWidgetItem::hasSeries() |
143 | */ |
144 | void Q3DBarsWidgetItem::removeSeries(QBar3DSeries *series) |
145 | { |
146 | graphBars()->removeSeries(series); |
147 | } |
148 | |
149 | /*! |
150 | * Inserts the \a series into the position \a index in the series list. |
151 | * If the \a series has already been added to the list, it is moved to the |
152 | * new \a index. |
153 | * \note When moving a series to a new \a index that is after its old index, |
154 | * the new position in the list is calculated as if the series was still in its |
155 | * old index, so the final index is actually the \a index decremented by one. |
156 | * |
157 | * \sa addSeries(), seriesList(), Q3DGraphsWidgetItem::hasSeries() |
158 | */ |
159 | void Q3DBarsWidgetItem::insertSeries(int index, QBar3DSeries *series) |
160 | { |
161 | graphBars()->insertSeries(index, series); |
162 | } |
163 | |
164 | /*! |
165 | * Returns the list of series added to this graph. |
166 | * |
167 | * \sa Q3DGraphsWidgetItem::hasSeries() |
168 | */ |
169 | QList<QBar3DSeries *> Q3DBarsWidgetItem::seriesList() const |
170 | { |
171 | QList<QBar3DSeries *> barSeriesList; |
172 | for (QAbstract3DSeries *abstractSeries : graphBars()->m_seriesList) { |
173 | QBar3DSeries *barSeries = qobject_cast<QBar3DSeries *>(object: abstractSeries); |
174 | if (barSeries) |
175 | barSeriesList.append(t: barSeries); |
176 | } |
177 | |
178 | return barSeriesList; |
179 | } |
180 | |
181 | /*! |
182 | * \property Q3DBarsWidgetItem::multiSeriesUniform |
183 | * |
184 | * \brief Whether bars are to be scaled with proportions set to a single series |
185 | * bar even if there are multiple series displayed. |
186 | * |
187 | * If set to \c {true}, \l{barSpacing}{bar spacing} will be correctly applied |
188 | * only to the X-axis. Preset to \c false by default. |
189 | */ |
190 | void Q3DBarsWidgetItem::setMultiSeriesUniform(bool uniform) |
191 | { |
192 | graphBars()->setMultiSeriesUniform(uniform); |
193 | emit multiSeriesUniformChanged(uniform); |
194 | } |
195 | |
196 | bool Q3DBarsWidgetItem::isMultiSeriesUniform() const |
197 | { |
198 | return graphBars()->isMultiSeriesUniform(); |
199 | } |
200 | |
201 | /*! |
202 | * \property Q3DBarsWidgetItem::barThickness |
203 | * |
204 | * \brief The bar thickness ratio between the X and Z dimensions. |
205 | * |
206 | * The value \c 1.0 means that the bars are as wide as they are deep, whereas |
207 | *\c 0.5 makes them twice as deep as they are wide. Preset to \c 1.0 by default. |
208 | */ |
209 | void Q3DBarsWidgetItem::setBarThickness(float thicknessRatio) |
210 | { |
211 | graphBars()->setBarThickness(thicknessRatio); |
212 | emit barThicknessChanged(thicknessRatio); |
213 | } |
214 | |
215 | float Q3DBarsWidgetItem::barThickness() const |
216 | { |
217 | return graphBars()->barThickness(); |
218 | } |
219 | |
220 | /*! |
221 | * \property Q3DBarsWidgetItem::barSpacing |
222 | * |
223 | * \brief Bar spacing in the X and Z dimensions. |
224 | * |
225 | * Preset to \c {(1.0, 1.0)} by default. Spacing is affected by the |
226 | * barSpacingRelative property. |
227 | * |
228 | * \sa barSpacingRelative, multiSeriesUniform, barSeriesMargin |
229 | */ |
230 | void Q3DBarsWidgetItem::setBarSpacing(QSizeF spacing) |
231 | { |
232 | graphBars()->setBarSpacing(spacing); |
233 | emit barSpacingChanged(spacing); |
234 | } |
235 | |
236 | QSizeF Q3DBarsWidgetItem::barSpacing() const |
237 | { |
238 | return graphBars()->barSpacing(); |
239 | } |
240 | |
241 | /*! |
242 | * \property Q3DBarsWidgetItem::barSpacingRelative |
243 | * |
244 | * \brief Whether spacing is absolute or relative to bar thickness. |
245 | * |
246 | * If it is \c true, the value of \c 0.0 means that the bars are placed |
247 | * side-to-side, \c 1.0 means that a space as wide as the thickness of one bar |
248 | * is left between the bars, and so on. Preset to \c true. |
249 | */ |
250 | void Q3DBarsWidgetItem::setBarSpacingRelative(bool relative) |
251 | { |
252 | graphBars()->setBarSpacingRelative(relative); |
253 | emit barSpacingRelativeChanged(relative); |
254 | } |
255 | |
256 | bool Q3DBarsWidgetItem::isBarSpacingRelative() const |
257 | { |
258 | return graphBars()->isBarSpacingRelative(); |
259 | } |
260 | |
261 | /*! |
262 | * \property Q3DBarsWidgetItem::barSeriesMargin |
263 | * |
264 | * \brief Margin between series columns in X and Z dimensions. |
265 | * Sensible values are on the range [0,1). |
266 | * |
267 | * Preset to \c {(0.0, 0.0)} by default. This property enables |
268 | * showing bars from different series side by side, but with space between |
269 | * columns. |
270 | * |
271 | * \sa barSpacing |
272 | */ |
273 | void Q3DBarsWidgetItem::setBarSeriesMargin(QSizeF margin) |
274 | { |
275 | graphBars()->setBarSeriesMargin(margin); |
276 | emit barSeriesMarginChanged(margin); |
277 | } |
278 | |
279 | QSizeF Q3DBarsWidgetItem::barSeriesMargin() const |
280 | { |
281 | return graphBars()->barSeriesMargin(); |
282 | } |
283 | |
284 | /*! |
285 | * \property Q3DBarsWidgetItem::rowAxis |
286 | * |
287 | * \brief The axis attached to the active row. |
288 | * |
289 | * Sets the axis of the active row to \a axis. Implicitly calls addAxis() to |
290 | * transfer the ownership of the axis to this graph. |
291 | * |
292 | * If \a axis is null, a temporary default axis with no labels is created. |
293 | * This temporary axis is destroyed if another axis is set explicitly to the |
294 | * same orientation. |
295 | * |
296 | * \sa addAxis(), releaseAxis() |
297 | */ |
298 | void Q3DBarsWidgetItem::setRowAxis(QCategory3DAxis *axis) |
299 | { |
300 | graphBars()->setRowAxis(axis); |
301 | emit rowAxisChanged(axis: rowAxis()); |
302 | } |
303 | |
304 | QCategory3DAxis *Q3DBarsWidgetItem::rowAxis() const |
305 | { |
306 | return graphBars()->rowAxis(); |
307 | } |
308 | |
309 | /*! |
310 | * \property Q3DBarsWidgetItem::columnAxis |
311 | * |
312 | * \brief The axis attached to the active column. |
313 | * |
314 | * Sets the axis of the active column to \a axis. Implicitly calls addAxis() to |
315 | * transfer the ownership of the axis to this graph. |
316 | * |
317 | * If \a axis is null, a temporary default axis with no labels is created. |
318 | * This temporary axis is destroyed if another axis is set explicitly to the |
319 | * same orientation. |
320 | * |
321 | * \sa addAxis(), releaseAxis() |
322 | */ |
323 | void Q3DBarsWidgetItem::setColumnAxis(QCategory3DAxis *axis) |
324 | { |
325 | graphBars()->setColumnAxis(axis); |
326 | emit columnAxisChanged(axis: columnAxis()); |
327 | } |
328 | |
329 | QCategory3DAxis *Q3DBarsWidgetItem::columnAxis() const |
330 | { |
331 | return graphBars()->columnAxis(); |
332 | } |
333 | |
334 | /*! |
335 | * \property Q3DBarsWidgetItem::valueAxis |
336 | * |
337 | * Sets the active value axis (the Y-axis) to \a axis. Implicitly calls |
338 | * addAxis() to transfer the ownership of \a axis to this graph. |
339 | * |
340 | * If \a axis is null, a temporary default axis with no labels and |
341 | * an automatically adjusting range is created. |
342 | * This temporary axis is destroyed if another axis is set explicitly to the |
343 | * same orientation. |
344 | * |
345 | * \sa addAxis(), releaseAxis() |
346 | */ |
347 | void Q3DBarsWidgetItem::setValueAxis(QValue3DAxis *axis) |
348 | { |
349 | graphBars()->setValueAxis(axis); |
350 | emit valueAxisChanged(axis: valueAxis()); |
351 | } |
352 | |
353 | QValue3DAxis *Q3DBarsWidgetItem::valueAxis() const |
354 | { |
355 | return graphBars()->valueAxis(); |
356 | } |
357 | |
358 | /*! |
359 | * \property Q3DBarsWidgetItem::selectedSeries |
360 | * \readonly |
361 | * |
362 | * \brief The selected series or a null value. |
363 | * |
364 | * If selectionMode has the \c SelectionMultiSeries flag set, this |
365 | * property holds the series that owns the selected bar. |
366 | */ |
367 | QBar3DSeries *Q3DBarsWidgetItem::selectedSeries() const |
368 | { |
369 | return graphBars()->selectedSeries(); |
370 | } |
371 | |
372 | /*! |
373 | * \property Q3DBarsWidgetItem::floorLevel |
374 | * |
375 | * \brief The floor level for the bar graph in Y-axis data coordinates. |
376 | * |
377 | * The actual floor level will be restricted by the Y-axis minimum and maximum |
378 | * values. |
379 | * Defaults to zero. |
380 | */ |
381 | void Q3DBarsWidgetItem::setFloorLevel(float level) |
382 | { |
383 | graphBars()->setFloorLevel(level); |
384 | emit floorLevelChanged(level); |
385 | } |
386 | |
387 | float Q3DBarsWidgetItem::floorLevel() const |
388 | { |
389 | return graphBars()->floorLevel(); |
390 | } |
391 | |
392 | bool Q3DBarsWidgetItem::event(QEvent *event) |
393 | { |
394 | return Q3DGraphsWidgetItem::event(event); |
395 | } |
396 | |
397 | /*! |
398 | * Adds \a axis to the graph. The axes added via addAxis are not yet taken to |
399 | * use, addAxis is simply used to give the ownership of the \a axis to the |
400 | * graph. The \a axis must not be null or added to another graph. |
401 | * |
402 | * \sa releaseAxis(), setValueAxis(), setRowAxis(), setColumnAxis() |
403 | */ |
404 | void Q3DBarsWidgetItem::addAxis(QAbstract3DAxis *axis) |
405 | { |
406 | graphBars()->addAxis(axis); |
407 | } |
408 | |
409 | /*! |
410 | * Releases the ownership of the \a axis back to the caller, if it is added to |
411 | * this graph. If the released \a axis is in use, a new default axis will be |
412 | * created and set active. |
413 | * |
414 | * If the default axis is released and added back later, it behaves as any other |
415 | * axis would. |
416 | * |
417 | * \sa addAxis(), setValueAxis(), setRowAxis(), setColumnAxis() |
418 | */ |
419 | void Q3DBarsWidgetItem::releaseAxis(QAbstract3DAxis *axis) |
420 | { |
421 | graphBars()->releaseAxis(axis); |
422 | } |
423 | |
424 | /*! |
425 | * Returns the list of all added axes. |
426 | * |
427 | * \sa addAxis() |
428 | */ |
429 | QList<QAbstract3DAxis *> Q3DBarsWidgetItem::axes() const |
430 | { |
431 | return graphBars()->axes(); |
432 | } |
433 | |
434 | /*! |
435 | * \internal |
436 | */ |
437 | QQuickGraphsBars *Q3DBarsWidgetItem::graphBars() |
438 | { |
439 | Q_D(Q3DBarsWidgetItem); |
440 | return static_cast<QQuickGraphsBars *>(d->m_graphsItem.get()); |
441 | } |
442 | |
443 | /*! |
444 | * \internal |
445 | */ |
446 | const QQuickGraphsBars *Q3DBarsWidgetItem::graphBars() const |
447 | { |
448 | Q_D(const Q3DBarsWidgetItem); |
449 | return static_cast<const QQuickGraphsBars *>(d->m_graphsItem.get()); |
450 | } |
451 | |
452 | QT_END_NAMESPACE |
453 | |