summaryrefslogtreecommitdiffstats
path: root/src/charts/legend/qlegend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/charts/legend/qlegend.cpp')
-rw-r--r--src/charts/legend/qlegend.cpp632
1 files changed, 632 insertions, 0 deletions
diff --git a/src/charts/legend/qlegend.cpp b/src/charts/legend/qlegend.cpp
new file mode 100644
index 00000000..ead1fac8
--- /dev/null
+++ b/src/charts/legend/qlegend.cpp
@@ -0,0 +1,632 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2014 Digia Plc
+ ** All rights reserved.
+ ** For any questions to Digia, please use contact form at http://qt.digia.com
+ **
+ ** This file is part of the Qt Enterprise Charts Add-on.
+ **
+ ** $QT_BEGIN_LICENSE$
+ ** Licensees holding valid Qt Enterprise licenses may use this file in
+ ** accordance with the Qt Enterprise License Agreement provided with the
+ ** Software or, alternatively, in accordance with the terms contained in
+ ** a written agreement between you and Digia.
+ **
+ ** If you have questions regarding the use of this file, please use
+ ** contact form at http://qt.digia.com
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+#include "qlegend.h"
+#include "qlegend_p.h"
+#include "qabstractseries.h"
+#include "qabstractseries_p.h"
+#include "qchart_p.h"
+#include "legendlayout_p.h"
+#include "chartpresenter_p.h"
+#include "abstractchartlayout_p.h"
+#include "qlegendmarker.h"
+#include "qlegendmarker_p.h"
+#include "legendmarkeritem_p.h"
+#include "chartdataset_p.h"
+#include <QPainter>
+#include <QPen>
+#include <QGraphicsItemGroup>
+
+QT_CHARTS_BEGIN_NAMESPACE
+
+/*!
+ \class QLegend
+ \inmodule Qt Charts
+ \brief Legend object.
+ \mainclass
+
+ QLegend is a graphical object for displaying the legend of the chart. Legend state is updated by QChart, when
+ series have been changed. By default, legend is drawn by QChart, but user can set a new parent to legend and
+ handle the drawing manually.
+ User isn't supposed to create or delete legend objects, but can reference it via QChart class.
+
+ \image examples_percentbarchart_legend.png
+
+ \sa QChart
+*/
+/*!
+ \qmltype Legend
+ \instantiates QLegend
+ \inqmlmodule QtCharts
+
+ \brief Legend is part of Qt Chart QML API.
+
+ Legend is a graphical object, whics displays legend of the chart. Legend state is updated by
+ ChartView, when series have been changed. Legend is used via ChartView class. For example:
+ \code
+ ChartView {
+ legend.visible: true
+ legend.alignment: Qt.AlignBottom
+ // Add a few series...
+ }
+ \endcode
+
+ \image examples_percentbarchart_legend.png
+
+ Please note that there is no QML API available for modifying legend markers, unlike in the Qt
+ API of Charts. The use case of modifying markers can be implemented for example by creating your
+ own custom legend. For an example on how to do this,
+ see \l {qmlcustomlegend}{Qml Custom Example} application.
+*/
+
+/*!
+ \property QLegend::alignment
+ \brief The alignment of the legend.
+
+ Legend paints on the defined position in the chart. The following alignments are supported:
+ Qt::AlignTop, Qt::AlignBottom, Qt::AlignLeft, Qt::AlignRight. If you set more than one flag the result is undefined.
+*/
+/*!
+ \qmlproperty Qt.Alignment Legend::alignment
+ \brief The alignment of the legend.
+
+ Legend paints on the defined position in the chart. The following alignments are supported:
+ Qt.AlignTop, Qt.AlignBottom, Qt.AlignLeft, Qt.AlignRight. If you set more than one flag the result is undefined.
+*/
+
+/*!
+ \property QLegend::backgroundVisible
+ Whether the legend background is visible or not.
+*/
+/*!
+ \qmlproperty bool Legend::backgroundVisible
+ Whether the legend background is visible or not.
+*/
+
+/*!
+ \property QLegend::color
+ The color of the legend, i.e. the background (brush) color. Note that if you change the color
+ of the legend, the style of the legend brush is set to Qt::SolidPattern.
+*/
+/*!
+ \qmlproperty color Legend::color
+ The color of the legend, i.e. the background (brush) color.
+*/
+
+/*!
+ \property QLegend::borderColor
+ The border color of the legend, i.e. the line color.
+*/
+/*!
+ \qmlproperty color Legend::borderColor
+ The border color of the legend, i.e. the line color.
+*/
+
+/*!
+ \property QLegend::font
+ The font of markers used by legend.
+*/
+/*!
+ \qmlproperty Font Legend::font
+ The font of markers used by legend.
+*/
+
+/*!
+ \property QLegend::labelColor
+ The color of brush used to draw labels.
+*/
+/*!
+ \qmlproperty color Legend::labelColor
+ The color of brush used to draw labels.
+*/
+
+/*!
+ \property QLegend::reverseMarkers
+ Whether reverse order is used for the markers in legend or not. False by default.
+*/
+/*!
+ \qmlproperty bool Legend::reverseMarkers
+ Whether reverse order is used for the markers in legend or not. False by default.
+*/
+
+/*!
+ \fn void QLegend::backgroundVisibleChanged(bool)
+ The visibility of the legend background changed to \a visible.
+*/
+
+/*!
+ \fn void QLegend::colorChanged(QColor)
+ The color of the legend background changed to \a color.
+*/
+
+/*!
+ \fn void QLegend::borderColorChanged(QColor)
+ The border color of the legend background changed to \a color.
+*/
+
+/*!
+ \fn void QLegend::fontChanged(QFont)
+ The font of markers of the legend changed to \a font.
+*/
+
+/*!
+ \fn void QLegend::labelColorChanged(QColor color)
+ This signal is emitted when the color of brush used to draw labels has changed to \a color.
+*/
+
+/*!
+ \fn void QLegend::reverseMarkersChanged(bool)
+ The use of reverse order for the markers in legend is changed to \a reverseMarkers.
+*/
+
+QLegend::QLegend(QChart *chart): QGraphicsWidget(chart),
+ d_ptr(new QLegendPrivate(chart->d_ptr->m_presenter, chart, this))
+{
+ setZValue(ChartPresenter::LegendZValue);
+ setFlags(QGraphicsItem::ItemClipsChildrenToShape);
+ QObject::connect(chart->d_ptr->m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)), d_ptr.data(), SLOT(handleSeriesAdded(QAbstractSeries*)));
+ QObject::connect(chart->d_ptr->m_dataset, SIGNAL(seriesRemoved(QAbstractSeries*)), d_ptr.data(), SLOT(handleSeriesRemoved(QAbstractSeries*)));
+ setLayout(d_ptr->m_layout);
+}
+
+/*!
+ Destroys the legend object. Legend is always owned by a QChart, so an application should never call this.
+*/
+QLegend::~QLegend()
+{
+}
+
+/*!
+ \internal
+ */
+void QLegend::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(option)
+ Q_UNUSED(widget)
+
+ if (!d_ptr->m_backgroundVisible)
+ return;
+
+ painter->setOpacity(opacity());
+ painter->setPen(d_ptr->m_pen);
+ painter->setBrush(d_ptr->m_brush);
+ painter->drawRoundRect(rect(), d_ptr->roundness(rect().width()), d_ptr->roundness(rect().height()));
+}
+
+
+/*!
+ Sets the \a brush of legend. Brush affects the background of legend.
+ */
+void QLegend::setBrush(const QBrush &brush)
+{
+ if (d_ptr->m_brush != brush) {
+ d_ptr->m_brush = brush;
+ update();
+ emit colorChanged(brush.color());
+ }
+}
+
+/*!
+ Returns the brush used by legend.
+ */
+QBrush QLegend::brush() const
+{
+ return d_ptr->m_brush;
+}
+
+void QLegend::setColor(QColor color)
+{
+ QBrush b = d_ptr->m_brush;
+ if (b.style() != Qt::SolidPattern || b.color() != color) {
+ b.setStyle(Qt::SolidPattern);
+ b.setColor(color);
+ setBrush(b);
+ }
+}
+
+QColor QLegend::color()
+{
+ return d_ptr->m_brush.color();
+}
+
+/*!
+ Sets the \a pen of legend. Pen affects the legend borders.
+ */
+void QLegend::setPen(const QPen &pen)
+{
+ if (d_ptr->m_pen != pen) {
+ d_ptr->m_pen = pen;
+ update();
+ emit borderColorChanged(pen.color());
+ }
+}
+
+/*!
+ Returns the pen used by legend.
+ */
+
+QPen QLegend::pen() const
+{
+ return d_ptr->m_pen;
+}
+
+void QLegend::setFont(const QFont &font)
+{
+ if (d_ptr->m_font != font) {
+ // Hide items to avoid flickering
+ d_ptr->items()->setVisible(false);
+ d_ptr->m_font = font;
+ foreach (QLegendMarker *marker, d_ptr->markers()) {
+ marker->setFont(d_ptr->m_font);
+ }
+ layout()->invalidate();
+ emit fontChanged(font);
+ }
+}
+
+QFont QLegend::font() const
+{
+ return d_ptr->m_font;
+}
+
+void QLegend::setBorderColor(QColor color)
+{
+ QPen p = d_ptr->m_pen;
+ if (p.color() != color) {
+ p.setColor(color);
+ setPen(p);
+ }
+}
+
+QColor QLegend::borderColor()
+{
+ return d_ptr->m_pen.color();
+}
+
+/*!
+ Set brush used to draw labels to \a brush.
+*/
+void QLegend::setLabelBrush(const QBrush &brush)
+{
+ if (d_ptr->m_labelBrush != brush) {
+ d_ptr->m_labelBrush = brush;
+ foreach (QLegendMarker *marker, d_ptr->markers()) {
+ marker->setLabelBrush(d_ptr->m_labelBrush);
+ // Note: The pen of the marker rectangle could be exposed in the public QLegend API
+ // instead of mapping it from label brush color
+ marker->setPen(brush.color());
+ }
+ emit labelColorChanged(brush.color());
+ }
+}
+
+/*!
+ Brush used to draw labels.
+*/
+QBrush QLegend::labelBrush() const
+{
+ return d_ptr->m_labelBrush;
+}
+
+void QLegend::setLabelColor(QColor color)
+{
+ QBrush b = d_ptr->m_labelBrush;
+ if (b.style() != Qt::SolidPattern || b.color() != color) {
+ b.setStyle(Qt::SolidPattern);
+ b.setColor(color);
+ setLabelBrush(b);
+ }
+}
+
+QColor QLegend::labelColor() const
+{
+ return d_ptr->m_labelBrush.color();
+}
+
+
+void QLegend::setAlignment(Qt::Alignment alignment)
+{
+ if (d_ptr->m_alignment != alignment) {
+ d_ptr->m_alignment = alignment;
+ layout()->invalidate();
+ }
+}
+
+Qt::Alignment QLegend::alignment() const
+{
+ return d_ptr->m_alignment;
+}
+
+/*!
+ Detaches the legend from chart. Chart won't change layout of the legend.
+ */
+void QLegend::detachFromChart()
+{
+ d_ptr->m_attachedToChart = false;
+// layout()->invalidate();
+ d_ptr->m_chart->layout()->invalidate();
+ setParent(0);
+
+}
+
+/*!
+ Attaches the legend to chart. Chart may change layout of the legend.
+ */
+void QLegend::attachToChart()
+{
+ d_ptr->m_attachedToChart = true;
+// layout()->invalidate();
+ d_ptr->m_chart->layout()->invalidate();
+ setParent(d_ptr->m_chart);
+}
+
+/*!
+ Returns true, if legend is attached to chart.
+ */
+bool QLegend::isAttachedToChart()
+{
+ return d_ptr->m_attachedToChart;
+}
+
+/*!
+ Sets the visibility of legend background to \a visible
+ */
+void QLegend::setBackgroundVisible(bool visible)
+{
+ if (d_ptr->m_backgroundVisible != visible) {
+ d_ptr->m_backgroundVisible = visible;
+ update();
+ emit backgroundVisibleChanged(visible);
+ }
+}
+
+/*!
+ Returns the visibility of legend background
+ */
+bool QLegend::isBackgroundVisible() const
+{
+ return d_ptr->m_backgroundVisible;
+}
+
+/*!
+ Returns the list of markers in legend. The list can be filtered with \a series parameter.
+ If \a series is given, only markers related to that series are returned.
+*/
+QList<QLegendMarker*> QLegend::markers(QAbstractSeries *series) const
+{
+ return d_ptr->markers(series);
+}
+
+bool QLegend::reverseMarkers()
+{
+ return d_ptr->m_reverseMarkers;
+}
+
+void QLegend::setReverseMarkers(bool reverseMarkers)
+{
+ if (d_ptr->m_reverseMarkers != reverseMarkers) {
+ d_ptr->m_reverseMarkers = reverseMarkers;
+ layout()->invalidate();
+ emit reverseMarkersChanged(reverseMarkers);
+ }
+}
+
+/*!
+ \internal \a event see QGraphicsWidget for details
+ */
+void QLegend::hideEvent(QHideEvent *event)
+{
+ if (isAttachedToChart())
+ d_ptr->m_presenter->layout()->invalidate();
+ QGraphicsWidget::hideEvent(event);
+}
+/*!
+ \internal \a event see QGraphicsWidget for details
+ */
+void QLegend::showEvent(QShowEvent *event)
+{
+ if (isAttachedToChart())
+ layout()->invalidate();
+ QGraphicsWidget::showEvent(event);
+ //layout activation will show the items
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+QLegendPrivate::QLegendPrivate(ChartPresenter *presenter, QChart *chart, QLegend *q)
+ : q_ptr(q),
+ m_presenter(presenter),
+ m_layout(new LegendLayout(q)),
+ m_chart(chart),
+ m_items(new QGraphicsItemGroup(q)),
+ m_alignment(Qt::AlignTop),
+ m_brush(QBrush()),
+ m_pen(QPen()),
+ m_labelBrush(QBrush()),
+ m_diameter(5),
+ m_attachedToChart(true),
+ m_backgroundVisible(false),
+ m_reverseMarkers(false)
+{
+ m_items->setHandlesChildEvents(false);
+}
+
+QLegendPrivate::~QLegendPrivate()
+{
+
+}
+
+void QLegendPrivate::setOffset(const QPointF &offset)
+{
+ m_layout->setOffset(offset.x(), offset.y());
+}
+
+QPointF QLegendPrivate::offset() const
+{
+ return m_layout->offset();
+}
+
+int QLegendPrivate::roundness(qreal size)
+{
+ return 100 * m_diameter / int(size);
+}
+
+QList<QLegendMarker*> QLegendPrivate::markers(QAbstractSeries *series)
+{
+ // Return all markers
+ if (!series) {
+ return m_markers;
+ }
+
+ // Create filtered list
+ QList<QLegendMarker *> markers;
+ foreach (QLegendMarker *marker, m_markers) {
+ if (marker->series() == series) {
+ markers.append(marker);
+ }
+ }
+ return markers;
+}
+
+void QLegendPrivate::handleSeriesAdded(QAbstractSeries *series)
+{
+ if (m_series.contains(series)) {
+ return;
+ }
+
+ QList<QLegendMarker*> newMarkers = series->d_ptr->createLegendMarkers(q_ptr);
+ decorateMarkers(newMarkers);
+ addMarkers(newMarkers);
+
+ QObject::connect(series->d_ptr.data(), SIGNAL(countChanged()), this, SLOT(handleCountChanged()));
+ QObject::connect(series, SIGNAL(visibleChanged()), this, SLOT(handleSeriesVisibleChanged()));
+
+ m_series.append(series);
+ m_items->setVisible(false);
+ m_layout->invalidate();
+}
+
+void QLegendPrivate::handleSeriesRemoved(QAbstractSeries *series)
+{
+ if (m_series.contains(series)) {
+ m_series.removeOne(series);
+ }
+
+ // Find out, which markers to remove
+ QList<QLegendMarker *> removed;
+ foreach (QLegendMarker *m, m_markers) {
+ if (m->series() == series) {
+ removed << m;
+ }
+ }
+ removeMarkers(removed);
+
+ QObject::disconnect(series->d_ptr.data(), SIGNAL(countChanged()), this, SLOT(handleCountChanged()));
+ QObject::disconnect(series, SIGNAL(visibleChanged()), this, SLOT(handleSeriesVisibleChanged()));
+
+ m_layout->invalidate();
+}
+
+void QLegendPrivate::handleSeriesVisibleChanged()
+{
+ QAbstractSeries *series = qobject_cast<QAbstractSeries *> (sender());
+ Q_ASSERT(series);
+
+ foreach (QLegendMarker *marker, m_markers) {
+ if (marker->series() == series) {
+ marker->setVisible(series->isVisible());
+ }
+ }
+
+ if (m_chart->isVisible())
+ m_layout->invalidate();
+}
+
+void QLegendPrivate::handleCountChanged()
+{
+ // Here we handle the changes in marker count.
+ // Can happen for example when pieslice(s) have been added to or removed from pieseries.
+
+ QAbstractSeriesPrivate *series = qobject_cast<QAbstractSeriesPrivate *> (sender());
+ QList<QLegendMarker *> createdMarkers = series->createLegendMarkers(q_ptr);
+
+ // Find out removed markers and created markers
+ QList<QLegendMarker *> removedMarkers;
+ foreach (QLegendMarker *oldMarker, m_markers) {
+ // we have marker, which is related to sender.
+ if (oldMarker->series() == series->q_ptr) {
+ bool found = false;
+ foreach(QLegendMarker *newMarker, createdMarkers) {
+ // New marker considered existing if:
+ // - d_ptr->relatedObject() is same for both markers.
+ if (newMarker->d_ptr->relatedObject() == oldMarker->d_ptr->relatedObject()) {
+ // Delete the new marker, since we already have existing marker, that might be connected on user side.
+ found = true;
+ createdMarkers.removeOne(newMarker);
+ delete newMarker;
+ }
+ }
+ if (!found) {
+ // No related object found for marker, add to removedMarkers list
+ removedMarkers << oldMarker;
+ }
+ }
+ }
+
+ removeMarkers(removedMarkers);
+ decorateMarkers(createdMarkers);
+ addMarkers(createdMarkers);
+
+ q_ptr->layout()->invalidate();
+}
+
+void QLegendPrivate::addMarkers(QList<QLegendMarker *> markers)
+{
+ foreach (QLegendMarker *marker, markers) {
+ m_items->addToGroup(marker->d_ptr.data()->item());
+ m_markers << marker;
+ m_markerHash.insert(marker->d_ptr->item(), marker);
+ }
+}
+
+void QLegendPrivate::removeMarkers(QList<QLegendMarker *> markers)
+{
+ foreach (QLegendMarker *marker, markers) {
+ marker->d_ptr->item()->setVisible(false);
+ m_items->removeFromGroup(marker->d_ptr->item());
+ m_markers.removeOne(marker);
+ m_markerHash.remove(marker->d_ptr->item());
+ delete marker;
+ }
+}
+
+void QLegendPrivate::decorateMarkers(QList<QLegendMarker *> markers)
+{
+ foreach (QLegendMarker *marker, markers) {
+ marker->setFont(m_font);
+ marker->setLabelBrush(m_labelBrush);
+ }
+}
+
+
+#include "moc_qlegend.cpp"
+#include "moc_qlegend_p.cpp"
+
+QT_CHARTS_END_NAMESPACE