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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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