1 | // Copyright (C) 2023 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include <QtGraphs/qbarset.h> |
5 | #include <private/qbarset_p.h> |
6 | #include <private/charthelpers_p.h> |
7 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | /*! |
11 | \class QBarSet |
12 | \inmodule QtGraphs |
13 | \ingroup graphs_2D |
14 | \brief The QBarSet class represents one set of bars in a bar graph. |
15 | |
16 | A bar set contains one data value for each category. The first value of a set is assumed to |
17 | belong to the first category, the second one to the second category, and so on. If the set has |
18 | fewer values than there are categories, the missing values are assumed to be located at the end |
19 | of the set. For missing values in the middle of a set, the numerical value of zero is used. |
20 | Labels for zero value sets are not shown. |
21 | |
22 | \sa QBarSeries |
23 | */ |
24 | /*! |
25 | \qmltype BarSet |
26 | \nativetype QBarSet |
27 | \inqmlmodule QtGraphs |
28 | \ingroup graphs_qml_2D |
29 | \brief Represents one set of bars in a bar graph. |
30 | |
31 | A bar set contains one data value for each category. The first value of a set is assumed to |
32 | belong to the first category, the second one to the second category, and so on. If the set has |
33 | fewer values than there are categories, the missing values are assumed to be located at the end |
34 | of the set. For missing values in the middle of a set, the numerical value of zero is used. |
35 | Labels for zero value sets are not shown. |
36 | |
37 | \sa BarSeries |
38 | */ |
39 | |
40 | /*! |
41 | \property QBarSet::label |
42 | \brief The label of the bar set. |
43 | */ |
44 | /*! |
45 | \qmlproperty string BarSet::label |
46 | The label of the bar set. |
47 | */ |
48 | |
49 | /*! |
50 | \property QBarSet::color |
51 | \brief The fill color of the bar set. |
52 | */ |
53 | /*! |
54 | \qmlproperty color BarSet::color |
55 | The fill color of the bar set. |
56 | */ |
57 | |
58 | /*! |
59 | \property QBarSet::selectedColor |
60 | \brief The fill color of the selected set. |
61 | */ |
62 | /*! |
63 | \qmlproperty color BarSet::selectedColor |
64 | The fill color of the selected set. |
65 | */ |
66 | |
67 | /*! |
68 | \property QBarSet::borderColor |
69 | \brief The border color of the bar set. |
70 | */ |
71 | /*! |
72 | \qmlproperty color BarSet::borderColor |
73 | The border color of the bar set. |
74 | */ |
75 | |
76 | /*! |
77 | \property QBarSet::borderWidth |
78 | \brief The width of the border line. |
79 | By default, the width is -1, meaning the border width is defined by the theme. |
80 | */ |
81 | /*! |
82 | \qmlproperty real BarSet::borderWidth |
83 | By default, the width is -1, meaning the border width is defined by the theme. |
84 | */ |
85 | |
86 | /*! |
87 | \property QBarSet::count |
88 | \brief The number of values in the bar set. |
89 | */ |
90 | /*! |
91 | \qmlproperty int BarSet::count |
92 | The number of values in the bar set. |
93 | */ |
94 | |
95 | /*! |
96 | \property QBarSet::labelColor |
97 | \brief The text (label) color of the bar set. |
98 | */ |
99 | /*! |
100 | \qmlproperty color BarSet::labelColor |
101 | The text (label) color of the bar set. |
102 | */ |
103 | |
104 | /*! |
105 | \property QBarSet::selectedBars |
106 | \brief The indexes of the bars which are currently selected. |
107 | */ |
108 | /*! |
109 | \qmlproperty list BarSet::selectedBars |
110 | The indexes of the bars which are currently selected. |
111 | */ |
112 | |
113 | /*! |
114 | \property QBarSet::values |
115 | \brief The values of the bar set. |
116 | |
117 | You can set a list of either \l [QML]{real} or \l [QML]{point} |
118 | types as values. |
119 | |
120 | If you set a list of real types as values, they directly define the bar set values. |
121 | |
122 | If you set a list of point types as values, the x-coordinate of the point specifies its |
123 | zero-based index in the bar set. The size of the bar set is the highest x-coordinate value + 1. |
124 | If a point is missing for any x-coordinate between zero and the highest value, |
125 | it gets the value zero. |
126 | */ |
127 | /*! |
128 | \qmlproperty list<variant> BarSet::values |
129 | The values of the bar set. You can set a list of either \l [QML]{real} or \l [QML]{point} |
130 | types as values. |
131 | |
132 | If you set a list of real types as values, they directly define the bar set values. |
133 | |
134 | If you set a list of point types as values, the x-coordinate of the point specifies its |
135 | zero-based index in the bar set. The size of the bar set is the highest x-coordinate value + 1. |
136 | If a point is missing for any x-coordinate between zero and the highest value, |
137 | it gets the value zero. |
138 | |
139 | For example, the following bar sets have equal values: |
140 | \code |
141 | myBarSet1.values = [5, 0, 1, 5]; |
142 | myBarSet2.values = [Qt.point(0, 5), Qt.point(2, 1), Qt.point(3, 5)]; |
143 | \endcode |
144 | */ |
145 | |
146 | /*! |
147 | \fn void QBarSet::update() |
148 | This signal is emitted when the barset is updated. |
149 | */ |
150 | /*! |
151 | \qmlsignal BarSet::update() |
152 | This signal is emitted when the barset is updated. |
153 | */ |
154 | |
155 | /*! |
156 | \qmlsignal BarSet::labelChanged() |
157 | This signal is emitted when the label of the bar set changes. |
158 | \sa label |
159 | */ |
160 | |
161 | /*! |
162 | \qmlsignal BarSet::colorChanged(color) |
163 | This signal is emitted when the fill color of the bar set changes to \a color. |
164 | */ |
165 | |
166 | /*! |
167 | \qmlsignal BarSet::borderColorChanged(color) |
168 | This signal is emitted when the border color of the bar set changes to \a color. |
169 | */ |
170 | |
171 | /*! |
172 | \qmlsignal BarSet::labelColorChanged(color) |
173 | This signal is emitted when the text (label) color of the bar set changes to \a color. |
174 | */ |
175 | |
176 | /*! |
177 | \qmlsignal BarSet::valuesChanged() |
178 | This signal is emitted when the values of the bar set change. |
179 | */ |
180 | |
181 | /*! |
182 | \qmlsignal BarSet::selectedColorChanged(color color) |
183 | This signal is emitted when the selected bar color changes. The new color is |
184 | \a color. |
185 | */ |
186 | |
187 | /*! |
188 | \qmlsignal BarSet::countChanged() |
189 | This signal is emitted when the barset's value count changes. |
190 | */ |
191 | |
192 | /*! |
193 | \qmlsignal BarSet::borderWidthChanged(real width) |
194 | This signal is emitted when the barset's border width changes. |
195 | The new width is \a width. |
196 | */ |
197 | |
198 | /*! |
199 | \fn void QBarSet::valuesAdded(qsizetype index, qsizetype count) |
200 | This signal is emitted when new values are added to the bar set. |
201 | \a index indicates the position of the first inserted value, and \a count is the number |
202 | of inserted values. |
203 | \sa append(), insert() |
204 | */ |
205 | /*! |
206 | \qmlsignal BarSet::valuesAdded(int index, int count) |
207 | This signal is emitted when new values are added to the bar set. |
208 | \a index indicates the position of the first inserted value, and \a count is the number |
209 | of inserted values. |
210 | */ |
211 | |
212 | /*! |
213 | \fn void QBarSet::valuesRemoved(qsizetype index, qsizetype count) |
214 | This signal is emitted when values are removed from the bar set. |
215 | \a index indicates the position of the first removed value, and \a count is the number |
216 | of removed values. |
217 | \sa remove() |
218 | */ |
219 | /*! |
220 | \qmlsignal BarSet::valuesRemoved(int index, int count) |
221 | This signal is emitted when values are removed from the bar set. |
222 | \a index indicates the position of the first removed value, and \a count is the number |
223 | of removed values. |
224 | */ |
225 | |
226 | /*! |
227 | \fn void QBarSet::valueChanged(qsizetype index) |
228 | This signal is emitted when the value at the position specified by \a index is modified. |
229 | \sa at() |
230 | */ |
231 | /*! |
232 | \qmlsignal BarSet::valueChanged(int index) |
233 | This signal is emitted when the value at the position specified by \a index is modified. |
234 | */ |
235 | |
236 | /*! |
237 | \fn void QBarSet::updatedBars() |
238 | This signal is emitted when the bars in this set are updated. |
239 | */ |
240 | /*! |
241 | \qmlsignal BarSet::updatedBars() |
242 | This signal is emitted when the bars in this set are updated. |
243 | */ |
244 | |
245 | /*! |
246 | \fn void QBarSet::valueAdded(qsizetype index, qsizetype count) |
247 | This signal is emitted when new values are added to the bar set. |
248 | \a index indicates the position of the first inserted value, and \a count |
249 | is the number of inserted values. |
250 | */ |
251 | /*! |
252 | \qmlsignal BarSet::valueAdded(int index, int count) |
253 | This signal is emitted when new values are added to the bar set. |
254 | \a index indicates the position of the first inserted value, and \a count |
255 | is the number of inserted values. |
256 | */ |
257 | |
258 | /*! |
259 | \fn void QBarSet::valueRemoved(qsizetype index, qsizetype count) |
260 | This signal is emitted when values are removed from the bar set. |
261 | \a index indicates the position of the first removed value, and \a count |
262 | is the number of removed values. |
263 | */ |
264 | /*! |
265 | \qmlsignal BarSet::valueRemoved(int index, int count) |
266 | This signal is emitted when values are removed from the bar set. |
267 | \a index indicates the position of the first removed value, and \a count |
268 | is the number of removed values. |
269 | */ |
270 | |
271 | /*! |
272 | \fn void QBarSet::selectedBarsChanged(const QList<qsizetype> &indexes) |
273 | This signal is emitted when the selected bar changes. \a indexes is |
274 | a list selected bar indexes. |
275 | */ |
276 | /*! |
277 | \qmlsignal BarSet::selectedBarsChanged(list<int> indexes) |
278 | This signal is emitted when the selected bar changes. \a indexes is |
279 | a list selected bar indexes. |
280 | */ |
281 | |
282 | QBarSet::QBarSet(QObject *parent) |
283 | : QBarSet(QString(), parent) |
284 | {} |
285 | |
286 | /*! |
287 | Constructs a bar set with the label \a label and the parent \a parent. |
288 | */ |
289 | QBarSet::QBarSet(const QString &label, QObject *parent) |
290 | : QObject(*(new QBarSetPrivate(label)), parent) |
291 | {} |
292 | |
293 | /*! |
294 | Removes the bar set. |
295 | */ |
296 | QBarSet::~QBarSet() |
297 | { |
298 | // NOTE: d_ptr destroyed by QObject |
299 | } |
300 | |
301 | /*! |
302 | Sets \a label as the new label for the bar set. |
303 | */ |
304 | void QBarSet::setLabel(const QString &label) |
305 | { |
306 | Q_D(QBarSet); |
307 | if (d->m_label != label) { |
308 | d->m_label = label; |
309 | d->setLabelsDirty(true); |
310 | emit update(); |
311 | emit labelChanged(); |
312 | } |
313 | } |
314 | |
315 | /*! |
316 | Returns the label of the bar set. |
317 | */ |
318 | QString QBarSet::label() const |
319 | { |
320 | Q_D(const QBarSet); |
321 | return d->m_label; |
322 | } |
323 | |
324 | /*! |
325 | \qmlmethod BarSet::append(real value) |
326 | Appends the new value specified by \a value to the end of the bar set. |
327 | */ |
328 | /*! |
329 | Appends the new value specified by \a value to the end of the bar set. |
330 | */ |
331 | void QBarSet::append(qreal value) |
332 | { |
333 | Q_D(QBarSet); |
334 | // Convert to QPointF |
335 | qsizetype index = d->m_values.size(); |
336 | d->append(value: QPointF(d->m_values.size(), value)); |
337 | emit valuesAdded(index, count: 1); |
338 | emit countChanged(); |
339 | emit update(); |
340 | } |
341 | |
342 | /*! |
343 | \qmlmethod BarSet::append(list<real> values) |
344 | Appends the list of real values specified by \a values to the end of the bar set. |
345 | |
346 | \sa append() |
347 | */ |
348 | /*! |
349 | Appends the list of real values specified by \a values to the end of the bar set. |
350 | |
351 | \sa append() |
352 | */ |
353 | void QBarSet::append(const QList<qreal> &values) |
354 | { |
355 | Q_D(QBarSet); |
356 | qsizetype index = d->m_values.size(); |
357 | d->append(values); |
358 | emit valuesAdded(index, count: values.size()); |
359 | emit countChanged(); |
360 | emit update(); |
361 | } |
362 | |
363 | /*! |
364 | \qmlmethod BarSet::insert(int index, real value) |
365 | Inserts \a value in the position specified by \a index. |
366 | The values following the inserted value are moved up one position. |
367 | |
368 | \sa remove() |
369 | */ |
370 | /*! |
371 | Inserts \a value in the position specified by \a index. |
372 | The values following the inserted value are moved up one position. |
373 | |
374 | \sa remove() |
375 | */ |
376 | void QBarSet::insert(qsizetype index, qreal value) |
377 | { |
378 | Q_D(QBarSet); |
379 | d->insert(index, value); |
380 | |
381 | bool callSignal = false; |
382 | if (!d->m_selectedBars.isEmpty()) { |
383 | // if value was inserted we need to move already selected bars by 1 |
384 | QSet<qsizetype> selectedAfterInsert; |
385 | for (const auto &value : std::as_const(t&: d->m_selectedBars)) { |
386 | if (value >= index) { |
387 | selectedAfterInsert << value + 1; |
388 | callSignal = true; |
389 | } else { |
390 | selectedAfterInsert << value; |
391 | } |
392 | } |
393 | d->m_selectedBars = selectedAfterInsert; |
394 | emit update(); |
395 | } |
396 | |
397 | emit valuesAdded(index, count: 1); |
398 | emit countChanged(); |
399 | if (callSignal) |
400 | emit selectedBarsChanged(indexes: selectedBars()); |
401 | } |
402 | |
403 | /*! |
404 | \qmlmethod BarSet::remove(int index, int count) |
405 | Removes the number of values specified by \a count from the bar set starting |
406 | with the value specified by \a index. |
407 | |
408 | If you leave out \a count, only the value specified by \a index is removed. |
409 | */ |
410 | /*! |
411 | Removes the number of values specified by \a count from the bar set starting with |
412 | the value specified by \a index. |
413 | \sa insert() |
414 | */ |
415 | void QBarSet::remove(qsizetype index, qsizetype count) |
416 | { |
417 | Q_D(QBarSet); |
418 | qsizetype removedCount = d->remove(index, count); |
419 | if (removedCount > 0) { |
420 | emit valuesRemoved(index, count: removedCount); |
421 | emit countChanged(); |
422 | emit update(); |
423 | } |
424 | } |
425 | |
426 | /*! |
427 | \qmlmethod BarSet::replace(int index, real value) |
428 | Adds the value specified by \a value to the bar set at the position |
429 | specified by \a index. |
430 | */ |
431 | /*! |
432 | Adds the value specified by \a value to the bar set at the position specified by \a index. |
433 | */ |
434 | void QBarSet::replace(qsizetype index, qreal value) |
435 | { |
436 | Q_D(QBarSet); |
437 | if (index >= 0 && index < d->m_values.size()) { |
438 | d->replace(index, value); |
439 | emit valueChanged(index); |
440 | emit update(); |
441 | } |
442 | } |
443 | |
444 | /*! |
445 | \qmlmethod real BarSet::at(int index) |
446 | Returns the value specified by \a index from the bar set. |
447 | If the index is out of bounds, 0.0 is returned. |
448 | */ |
449 | /*! |
450 | Returns the value specified by \a index from the bar set. |
451 | If the index is out of bounds, 0.0 is returned. |
452 | */ |
453 | qreal QBarSet::at(qsizetype index) const |
454 | { |
455 | Q_D(const QBarSet); |
456 | if (index < 0 || index >= d->m_values.size()) |
457 | return 0; |
458 | return d->m_values.at(i: index).y(); |
459 | } |
460 | |
461 | /*! |
462 | \qmlmethod int BarSet::count() |
463 | Returns the number of values in a bar set. |
464 | */ |
465 | /*! |
466 | Returns the number of values in a bar set. |
467 | */ |
468 | qsizetype QBarSet::count() const |
469 | { |
470 | Q_D(const QBarSet); |
471 | return d->m_values.size(); |
472 | } |
473 | |
474 | /*! |
475 | \qmlmethod real BarSet::sum() |
476 | Returns the sum of all values in the bar set. |
477 | */ |
478 | /*! |
479 | Returns the sum of all values in the bar set. |
480 | */ |
481 | qreal QBarSet::sum() const |
482 | { |
483 | Q_D(const QBarSet); |
484 | qreal total(0); |
485 | for (int i = 0; i < d->m_values.size(); i++) |
486 | total += d->m_values.at(i).y(); |
487 | return total; |
488 | } |
489 | |
490 | /*! |
491 | \qmlmethod BarSet::clear() |
492 | Removes all values from the set. |
493 | */ |
494 | /*! |
495 | Removes all values from the set. |
496 | */ |
497 | void QBarSet::clear() |
498 | { |
499 | Q_D(QBarSet); |
500 | remove(index: 0, count: d->m_values.size()); |
501 | } |
502 | |
503 | /*! |
504 | A convenience operator for appending the real value specified by \a value to the end of the |
505 | bar set. |
506 | |
507 | \sa append() |
508 | */ |
509 | QBarSet &QBarSet::operator << (qreal value) |
510 | { |
511 | append(value); |
512 | return *this; |
513 | } |
514 | |
515 | /*! |
516 | Returns the value of the bar set specified by \a index. |
517 | If the index is out of bounds, 0.0 is returned. |
518 | */ |
519 | qreal QBarSet::operator [](qsizetype index) const |
520 | { |
521 | return at(index); |
522 | } |
523 | |
524 | /*! |
525 | Returns the fill color for the bar set. |
526 | */ |
527 | QColor QBarSet::color() const |
528 | { |
529 | Q_D(const QBarSet); |
530 | return d->m_color; |
531 | } |
532 | |
533 | /*! |
534 | Sets the fill color for the bar set to \a color. |
535 | */ |
536 | void QBarSet::setColor(QColor color) |
537 | { |
538 | Q_D(QBarSet); |
539 | if (d->m_color != color) { |
540 | d->m_color = color; |
541 | emit update(); |
542 | emit colorChanged(color); |
543 | } |
544 | } |
545 | |
546 | /*! |
547 | Returns the line color for the bar set. |
548 | */ |
549 | QColor QBarSet::borderColor() const |
550 | { |
551 | Q_D(const QBarSet); |
552 | return d->m_borderColor; |
553 | } |
554 | |
555 | /*! |
556 | Sets the line color for the bar set to \a color. |
557 | */ |
558 | void QBarSet::setBorderColor(QColor color) |
559 | { |
560 | Q_D(QBarSet); |
561 | if (d->m_borderColor != color) { |
562 | d->m_borderColor = color; |
563 | emit update(); |
564 | emit borderColorChanged(color); |
565 | } |
566 | } |
567 | |
568 | /*! |
569 | Returns the text color for the bar set. |
570 | */ |
571 | QColor QBarSet::labelColor() const |
572 | { |
573 | Q_D(const QBarSet); |
574 | return d->m_labelColor; |
575 | } |
576 | |
577 | /*! |
578 | Sets the text color for the bar set to \a color. |
579 | */ |
580 | void QBarSet::setLabelColor(QColor color) |
581 | { |
582 | Q_D(QBarSet); |
583 | if (d->m_labelColor != color) { |
584 | d->m_labelColor = color; |
585 | emit update(); |
586 | emit labelColorChanged(color); |
587 | } |
588 | } |
589 | |
590 | /*! |
591 | Returns the color of the selected bars. |
592 | |
593 | This is the fill (brush) color of bars marked as selected. If not specified, |
594 | value of QBarSet::color is used as default. |
595 | \sa color |
596 | */ |
597 | QColor QBarSet::selectedColor() const |
598 | { |
599 | Q_D(const QBarSet); |
600 | return d->m_selectedColor; |
601 | } |
602 | |
603 | /*! |
604 | Sets the \a color of the selected bars. |
605 | \sa selectedColor |
606 | */ |
607 | void QBarSet::setSelectedColor(QColor color) |
608 | { |
609 | Q_D(QBarSet); |
610 | if (d->m_selectedColor != color) { |
611 | d->m_selectedColor = color; |
612 | d->setLabelsDirty(true); |
613 | emit update(); |
614 | emit updatedBars(); |
615 | emit selectedColorChanged(color); |
616 | } |
617 | } |
618 | |
619 | |
620 | qreal QBarSet::borderWidth() const |
621 | { |
622 | Q_D(const QBarSet); |
623 | return d->m_borderWidth; |
624 | } |
625 | |
626 | void QBarSet::setBorderWidth(qreal width) |
627 | { |
628 | Q_D(QBarSet); |
629 | width = qMax(a: 0.0, b: width); |
630 | if (!qFuzzyCompare(p1: d->m_borderWidth, p2: width)) { |
631 | d->m_borderWidth = width; |
632 | emit update(); |
633 | emit borderWidthChanged(width); |
634 | } |
635 | } |
636 | |
637 | QVariantList QBarSet::values() const |
638 | { |
639 | QVariantList values; |
640 | for (qsizetype i(0); i < count(); i++) |
641 | values.append(t: QVariant(QBarSet::at(index: i))); |
642 | return values; |
643 | } |
644 | |
645 | void QBarSet::setValues(const QVariantList &values) |
646 | { |
647 | bool valuesUpdated = false; |
648 | // See if we can replace values instead of remove & add all. |
649 | // This way e.g. selections remain. |
650 | const bool doReplace = count() == values.size(); |
651 | |
652 | if (!doReplace) { |
653 | while (count()) |
654 | remove(index: count() - 1); |
655 | valuesUpdated = true; |
656 | } |
657 | |
658 | if (values.size() > 0 && values.at(i: 0).canConvert<QPoint>()) { |
659 | // Create list of values for appending if the first item is Qt.point |
660 | int maxValue = 0; |
661 | for (int i = 0; i < values.size(); i++) { |
662 | if (values.at(i).canConvert<QPoint>() && |
663 | values.at(i).toPoint().x() > maxValue) { |
664 | maxValue = values.at(i).toPoint().x(); |
665 | } |
666 | } |
667 | |
668 | QList<qreal> indexValueList; |
669 | indexValueList.resize(size: maxValue + 1); |
670 | |
671 | for (int i = 0; i < values.size(); i++) { |
672 | if (values.at(i).canConvert<QPoint>()) |
673 | indexValueList.replace(i: values.at(i).toPoint().x(), t: values.at(i).toPointF().y()); |
674 | } |
675 | |
676 | for (int i = 0; i < indexValueList.size(); i++) { |
677 | if (doReplace) |
678 | QBarSet::replace(index: i, value: indexValueList.at(i)); |
679 | else |
680 | QBarSet::append(value: indexValueList.at(i)); |
681 | valuesUpdated = true; |
682 | } |
683 | |
684 | } else { |
685 | for (int i(0); i < values.size(); i++) { |
686 | if (values.at(i).canConvert<double>()) { |
687 | if (doReplace) |
688 | QBarSet::replace(index: i, value: values[i].toDouble()); |
689 | else |
690 | QBarSet::append(value: values[i].toDouble()); |
691 | valuesUpdated = true; |
692 | } |
693 | } |
694 | } |
695 | emit update(); |
696 | if (valuesUpdated) |
697 | emit valuesChanged(); |
698 | } |
699 | |
700 | |
701 | /*! |
702 | \qmlmethod bool BarSet::isBarSelected(int index) |
703 | Returns \c true if the bar at the given \a index is among selected bars and \c false otherwise. |
704 | \note Selected bars are drawn using the selected color if it was specified using BarSet::setSelectedColor. |
705 | \sa selectedBars, setBarSelected(), selectedColor |
706 | */ |
707 | /*! |
708 | Returns \c true if the bar at the given \a index is among selected bars and \c false otherwise. |
709 | \note Selected bars are drawn using the selected color if it was specified using QBarSet::setSelectedColor. |
710 | \sa selectedBars(), setBarSelected(), setSelectedColor() |
711 | */ |
712 | bool QBarSet::isBarSelected(qsizetype index) const |
713 | { |
714 | Q_D(const QBarSet); |
715 | return d->isBarSelected(index); |
716 | } |
717 | |
718 | /*! |
719 | \qmlmethod BarSet::selectBar(int index) |
720 | Marks the bar at \a index as selected. |
721 | \note Emits BarSet::selectedBarsChanged. |
722 | \sa setBarSelected() |
723 | */ |
724 | /*! |
725 | Marks the bar at \a index as selected. |
726 | \note Emits QBarSet::selectedBarsChanged. |
727 | \sa setBarSelected() |
728 | */ |
729 | void QBarSet::selectBar(qsizetype index) |
730 | { |
731 | setBarSelected(index, selected: true); |
732 | } |
733 | |
734 | /*! |
735 | \qmlmethod BarSet::deselectBar(int index) |
736 | Deselects the bar at \a index. |
737 | \note Emits BarSet::selectedBarsChanged. |
738 | \sa setBarSelected() |
739 | */ |
740 | /*! |
741 | Deselects the bar at \a index. |
742 | \note Emits QBarSet::selectedBarsChanged. |
743 | \sa setBarSelected() |
744 | */ |
745 | void QBarSet::deselectBar(qsizetype index) |
746 | { |
747 | setBarSelected(index, selected: false); |
748 | } |
749 | |
750 | /*! |
751 | \qmlmethod BarSet::setBarSelected(int index, bool selected) |
752 | Marks the bar at \a index as either selected or deselected as specified by \a selected. |
753 | \note Selected bars are drawn using the selected color if it was specified. Emits BarSet::selectedBarsChanged. |
754 | \sa selectedColor |
755 | */ |
756 | /*! |
757 | Marks the bar at \a index as either selected or deselected as specified by \a selected. |
758 | \note Selected bars are drawn using the selected color if it was specified. Emits QBarSet::selectedBarsChanged. |
759 | \sa setSelectedColor() |
760 | */ |
761 | void QBarSet::setBarSelected(qsizetype index, bool selected) |
762 | { |
763 | Q_D(QBarSet); |
764 | bool callSignal = false; |
765 | d->setBarSelected(index, selected, callSignal); |
766 | |
767 | if (callSignal) |
768 | emit selectedBarsChanged(indexes: selectedBars()); |
769 | emit update(); |
770 | } |
771 | |
772 | /*! |
773 | \qmlmethod BarSet::selectAllBars() |
774 | Marks all bars in the set as selected. |
775 | \note Emits BarSet::selectedBarsChanged. |
776 | \sa setBarSelected() |
777 | */ |
778 | /*! |
779 | Marks all bars in the set as selected. |
780 | \note Emits QBarSet::selectedBarsChanged. |
781 | \sa setBarSelected() |
782 | */ |
783 | void QBarSet::selectAllBars() |
784 | { |
785 | Q_D(QBarSet); |
786 | bool callSignal = false; |
787 | for (int i = 0; i < d->m_values.size(); ++i) |
788 | d->setBarSelected(index: i, selected: true, callSignal); |
789 | |
790 | if (callSignal) |
791 | emit selectedBarsChanged(indexes: selectedBars()); |
792 | emit update(); |
793 | } |
794 | |
795 | /*! |
796 | \qmlmethod BarSet::deselectAllBars() |
797 | Deselects all bars in the set. |
798 | \note Emits BarSet::selectedBarsChanged. |
799 | \sa setBarSelected() |
800 | */ |
801 | /*! |
802 | Deselects all bars in the set. |
803 | \note Emits QBarSet::selectedBarsChanged. |
804 | \sa setBarSelected() |
805 | */ |
806 | void QBarSet::deselectAllBars() |
807 | { |
808 | Q_D(QBarSet); |
809 | bool callSignal = false; |
810 | for (int i = 0; i < d->m_values.size(); ++i) |
811 | d->setBarSelected(index: i, selected: false, callSignal); |
812 | |
813 | if (callSignal) |
814 | emit selectedBarsChanged(indexes: selectedBars()); |
815 | emit update(); |
816 | } |
817 | |
818 | /*! |
819 | \qmlmethod BarSet::selectBars(list<int> indexes) |
820 | Marks multiple bars passed in an \a indexes list as selected. |
821 | \note Emits BarSet::selectedBarsChanged. |
822 | \sa setBarSelected() |
823 | */ |
824 | /*! |
825 | Marks multiple bars passed in an \a indexes list as selected. |
826 | \note Emits QBarSet::selectedBarsChanged. |
827 | \sa setBarSelected() |
828 | */ |
829 | void QBarSet::selectBars(const QList<qsizetype> &indexes) |
830 | { |
831 | Q_D(QBarSet); |
832 | bool callSignal = false; |
833 | for (const qsizetype &index : indexes) |
834 | d->setBarSelected(index, selected: true, callSignal); |
835 | |
836 | if (callSignal) |
837 | emit selectedBarsChanged(indexes: selectedBars()); |
838 | emit update(); |
839 | } |
840 | |
841 | /*! |
842 | \qmlmethod BarSet::deselectBars(list<int> indexes) |
843 | Marks multiple bars passed in an \a indexes list as deselected. |
844 | \note Emits BarSet::selectedBarsChanged. |
845 | \sa setBarSelected() |
846 | */ |
847 | /*! |
848 | Marks multiple bars passed in an \a indexes list as deselected. |
849 | \note Emits QBarSet::selectedBarsChanged. |
850 | \sa setBarSelected() |
851 | */ |
852 | void QBarSet::deselectBars(const QList<qsizetype> &indexes) |
853 | { |
854 | Q_D(QBarSet); |
855 | bool callSignal = false; |
856 | for (const qsizetype &index : indexes) |
857 | d->setBarSelected(index, selected: false, callSignal); |
858 | |
859 | if (callSignal) |
860 | emit selectedBarsChanged(indexes: selectedBars()); |
861 | emit update(); |
862 | } |
863 | |
864 | /*! |
865 | \qmlmethod BarSet::toggleSelection(list<int> indexes) |
866 | Changes the selection state of bars at the given \a indexes to the opposite one. |
867 | \note Emits BarSet::selectedBarsChanged. |
868 | \sa setBarSelected() |
869 | */ |
870 | /*! |
871 | Changes the selection state of bars at the given \a indexes to the opposite one. |
872 | \note Emits QBarSet::selectedBarsChanged. |
873 | \sa setBarSelected() |
874 | */ |
875 | void QBarSet::toggleSelection(const QList<qsizetype> &indexes) |
876 | { |
877 | Q_D(QBarSet); |
878 | bool callSignal = false; |
879 | for (const qsizetype &index : indexes) |
880 | d->setBarSelected(index, selected: !isBarSelected(index), callSignal); |
881 | |
882 | if (callSignal) |
883 | emit selectedBarsChanged(indexes: selectedBars()); |
884 | emit update(); |
885 | } |
886 | |
887 | /*! |
888 | Returns a list of bars marked as selected. |
889 | \sa setBarSelected() |
890 | */ |
891 | QList<qsizetype> QBarSet::selectedBars() const |
892 | { |
893 | Q_D(const QBarSet); |
894 | return QList<qsizetype>(d->m_selectedBars.begin(), d->m_selectedBars.end()); |
895 | } |
896 | |
897 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
898 | |
899 | QBarSetPrivate::QBarSetPrivate(const QString &label) |
900 | : m_label(label) |
901 | , m_visualsDirty(true) |
902 | {} |
903 | |
904 | QBarSetPrivate::~QBarSetPrivate() {} |
905 | |
906 | void QBarSetPrivate::append(QPointF value) |
907 | { |
908 | if (isValidValue(point: value)) { |
909 | Q_Q(QBarSet); |
910 | m_values.append(t: value); |
911 | emit q->valueAdded(index: m_values.size() - 1, count: 1); |
912 | } |
913 | } |
914 | |
915 | void QBarSetPrivate::append(const QList<QPointF> &values) |
916 | { |
917 | qsizetype originalIndex = m_values.size(); |
918 | for (const auto &value : values) { |
919 | if (isValidValue(point: value)) |
920 | m_values.append(t: value); |
921 | } |
922 | Q_Q(QBarSet); |
923 | emit q->valueAdded(index: originalIndex, count: values.size()); |
924 | } |
925 | |
926 | void QBarSetPrivate::append(const QList<qreal> &values) |
927 | { |
928 | qsizetype originalIndex = m_values.size(); |
929 | qsizetype index = originalIndex; |
930 | for (const auto value : values) { |
931 | if (isValidValue(value)) { |
932 | m_values.append(t: QPointF(index, value)); |
933 | index++; |
934 | } |
935 | } |
936 | Q_Q(QBarSet); |
937 | emit q->valueAdded(index: originalIndex, count: values.size()); |
938 | } |
939 | |
940 | void QBarSetPrivate::insert(qsizetype index, qreal value) |
941 | { |
942 | m_values.insert(i: index, t: QPointF(index, value)); |
943 | Q_Q(QBarSet); |
944 | emit q->valueAdded(index, count: 1); |
945 | } |
946 | |
947 | void QBarSetPrivate::insert(qsizetype index, QPointF value) |
948 | { |
949 | m_values.insert(i: index, t: value); |
950 | Q_Q(QBarSet); |
951 | emit q->valueAdded(index, count: 1); |
952 | } |
953 | |
954 | qsizetype QBarSetPrivate::remove(qsizetype index, qsizetype count) |
955 | { |
956 | qsizetype removeCount = count; |
957 | |
958 | if ((index < 0) || (m_values.size() == 0)) |
959 | return 0; // Invalid index or not values in list, remove nothing. |
960 | else if ((index + count) > m_values.size()) |
961 | removeCount = m_values.size() - index; // Trying to remove more items than list has. Limit amount to be removed. |
962 | |
963 | int c = 0; |
964 | while (c < removeCount) { |
965 | m_values.removeAt(i: index); |
966 | c++; |
967 | } |
968 | |
969 | bool callSignal = false; |
970 | if (!m_selectedBars.empty()) { |
971 | QSet<qsizetype> selectedAfterRemoving; |
972 | |
973 | for (const qsizetype &selectedBarIndex : std::as_const(t&: m_selectedBars)) { |
974 | if (selectedBarIndex < index) { |
975 | selectedAfterRemoving << selectedBarIndex; |
976 | } else if (selectedBarIndex >= index + removeCount) { |
977 | selectedAfterRemoving << selectedBarIndex - removeCount; |
978 | callSignal = true; |
979 | } else { |
980 | callSignal = true; |
981 | } |
982 | } |
983 | |
984 | m_selectedBars = selectedAfterRemoving; |
985 | } |
986 | Q_Q(QBarSet); |
987 | emit q->valueRemoved(index, count: removeCount); |
988 | if (callSignal) |
989 | emit q->selectedBarsChanged(indexes: q->selectedBars()); |
990 | |
991 | return removeCount; |
992 | } |
993 | |
994 | void QBarSetPrivate::replace(qsizetype index, qreal value) |
995 | { |
996 | if (index < 0 || index >= m_values.size()) |
997 | return; |
998 | |
999 | m_values.replace(i: index, t: QPointF(index, value)); |
1000 | } |
1001 | |
1002 | qreal QBarSetPrivate::pos(qsizetype index) const |
1003 | { |
1004 | if (index < 0 || index >= m_values.size()) |
1005 | return 0; |
1006 | return m_values.at(i: index).x(); |
1007 | } |
1008 | |
1009 | qreal QBarSetPrivate::value(qsizetype index) const |
1010 | { |
1011 | if (index < 0 || index >= m_values.size()) |
1012 | return 0; |
1013 | return m_values.at(i: index).y(); |
1014 | } |
1015 | |
1016 | void QBarSetPrivate::setBarSelected(qsizetype index, bool selected, bool &callSignal) |
1017 | { |
1018 | if (index < 0 || index > m_values.size() - 1) |
1019 | return; |
1020 | |
1021 | if (selected) { |
1022 | if (!isBarSelected(index)) { |
1023 | m_selectedBars << index; |
1024 | callSignal = true; |
1025 | } |
1026 | } else { |
1027 | if (isBarSelected(index)) { |
1028 | m_selectedBars.remove(value: index); |
1029 | callSignal = true; |
1030 | } |
1031 | } |
1032 | |
1033 | if (callSignal) |
1034 | setVisualsDirty(true); |
1035 | } |
1036 | |
1037 | bool QBarSetPrivate::isBarSelected(qsizetype index) const |
1038 | { |
1039 | return m_selectedBars.contains(value: index); |
1040 | } |
1041 | |
1042 | QT_END_NAMESPACE |
1043 | |
1044 | #include "moc_qbarset.cpp" |
1045 | |