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
8QT_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 */
83Q3DBarsWidgetItem::Q3DBarsWidgetItem(QObject *parent)
84 : Q3DGraphsWidgetItem(*(new Q3DBarsWidgetItemPrivate()), parent, QStringLiteral("Bars3D"))
85{}
86
87/*!
88 * Destroys the 3D bar graph.
89 */
90Q3DBarsWidgetItem::~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 */
111void Q3DBarsWidgetItem::setPrimarySeries(QBar3DSeries *series)
112{
113 graphBars()->setPrimarySeries(series);
114 emit primarySeriesChanged(series);
115}
116
117QBar3DSeries *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 */
134void 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 */
144void 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 */
159void 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 */
169QList<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 */
190void Q3DBarsWidgetItem::setMultiSeriesUniform(bool uniform)
191{
192 graphBars()->setMultiSeriesUniform(uniform);
193 emit multiSeriesUniformChanged(uniform);
194}
195
196bool 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 */
209void Q3DBarsWidgetItem::setBarThickness(float thicknessRatio)
210{
211 graphBars()->setBarThickness(thicknessRatio);
212 emit barThicknessChanged(thicknessRatio);
213}
214
215float 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 */
230void Q3DBarsWidgetItem::setBarSpacing(QSizeF spacing)
231{
232 graphBars()->setBarSpacing(spacing);
233 emit barSpacingChanged(spacing);
234}
235
236QSizeF 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 */
250void Q3DBarsWidgetItem::setBarSpacingRelative(bool relative)
251{
252 graphBars()->setBarSpacingRelative(relative);
253 emit barSpacingRelativeChanged(relative);
254}
255
256bool 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 */
273void Q3DBarsWidgetItem::setBarSeriesMargin(QSizeF margin)
274{
275 graphBars()->setBarSeriesMargin(margin);
276 emit barSeriesMarginChanged(margin);
277}
278
279QSizeF 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 */
298void Q3DBarsWidgetItem::setRowAxis(QCategory3DAxis *axis)
299{
300 graphBars()->setRowAxis(axis);
301 emit rowAxisChanged(axis: rowAxis());
302}
303
304QCategory3DAxis *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 */
323void Q3DBarsWidgetItem::setColumnAxis(QCategory3DAxis *axis)
324{
325 graphBars()->setColumnAxis(axis);
326 emit columnAxisChanged(axis: columnAxis());
327}
328
329QCategory3DAxis *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 */
347void Q3DBarsWidgetItem::setValueAxis(QValue3DAxis *axis)
348{
349 graphBars()->setValueAxis(axis);
350 emit valueAxisChanged(axis: valueAxis());
351}
352
353QValue3DAxis *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 */
367QBar3DSeries *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 */
381void Q3DBarsWidgetItem::setFloorLevel(float level)
382{
383 graphBars()->setFloorLevel(level);
384 emit floorLevelChanged(level);
385}
386
387float Q3DBarsWidgetItem::floorLevel() const
388{
389 return graphBars()->floorLevel();
390}
391
392bool 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 */
404void 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 */
419void 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 */
429QList<QAbstract3DAxis *> Q3DBarsWidgetItem::axes() const
430{
431 return graphBars()->axes();
432}
433
434/*!
435 * \internal
436 */
437QQuickGraphsBars *Q3DBarsWidgetItem::graphBars()
438{
439 Q_D(Q3DBarsWidgetItem);
440 return static_cast<QQuickGraphsBars *>(d->m_graphsItem.get());
441}
442
443/*!
444 * \internal
445 */
446const QQuickGraphsBars *Q3DBarsWidgetItem::graphBars() const
447{
448 Q_D(const Q3DBarsWidgetItem);
449 return static_cast<const QQuickGraphsBars *>(d->m_graphsItem.get());
450}
451
452QT_END_NAMESPACE
453

source code of qtgraphs/src/graphs3d/widget/q3dbarswidgetitem.cpp