From 7bf1a442df6a5764f01c3860cf47441e24e311e3 2012-06-13 12:39:30 From: Jani Honkonen Date: 2012-06-13 12:39:30 Subject: [PATCH] pie: add label position to slice --- diff --git a/demos/piechartcustomization/mainwidget.cpp b/demos/piechartcustomization/mainwidget.cpp index e630421..f68316c 100644 --- a/demos/piechartcustomization/mainwidget.cpp +++ b/demos/piechartcustomization/mainwidget.cpp @@ -154,6 +154,9 @@ MainWidget::MainWidget(QWidget* parent) m_font = new QPushButton(); m_labelBrush = new QPushButton(); m_labelBrushTool = new BrushTool("Label brush", this); + m_labelPosition = new QComboBox(this); + m_labelPosition->addItem("Outside", QPieSlice::LabelOutside); + m_labelPosition->addItem("Inside", QPieSlice::LabelInside); QPushButton *removeSlice = new QPushButton("Remove slice"); QFormLayout* sliceSettingsLayout = new QFormLayout(); @@ -163,7 +166,8 @@ MainWidget::MainWidget(QWidget* parent) sliceSettingsLayout->addRow("Brush", m_brush); sliceSettingsLayout->addRow("Label visible", m_sliceLabelVisible); sliceSettingsLayout->addRow("Label font", m_font); - sliceSettingsLayout->addRow("Label pen", m_labelBrush); + sliceSettingsLayout->addRow("Label brush", m_labelBrush); + sliceSettingsLayout->addRow("Label position", m_labelPosition); sliceSettingsLayout->addRow("Label arm length", m_sliceLabelArmFactor); sliceSettingsLayout->addRow("Exploded", m_sliceExploded); sliceSettingsLayout->addRow("Explode distance", m_sliceExplodedFactor); @@ -184,6 +188,7 @@ MainWidget::MainWidget(QWidget* parent) connect(m_sliceLabelArmFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings())); connect(m_sliceExploded, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings())); connect(m_sliceExplodedFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings())); + connect(m_labelPosition, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSliceSettings())); connect(removeSlice, SIGNAL(clicked()), this, SLOT(removeSlice())); // create chart view @@ -244,6 +249,7 @@ void MainWidget::updateSliceSettings() m_slice->setLabelBrush(m_labelBrushTool->brush()); m_slice->setLabelVisible(m_sliceLabelVisible->isChecked()); m_slice->setLabelArmLengthFactor(m_sliceLabelArmFactor->value()); + m_slice->setLabelPosition((QPieSlice::LabelPosition)m_labelPosition->currentIndex()); // assumes that index is in sync with the enum m_slice->setExploded(m_sliceExploded->isChecked()); m_slice->setExplodeDistanceFactor(m_sliceExplodedFactor->value()); @@ -279,6 +285,9 @@ void MainWidget::handleSliceClicked(QPieSlice* slice) m_sliceLabelArmFactor->blockSignals(true); m_sliceLabelArmFactor->setValue(slice->labelArmLengthFactor()); m_sliceLabelArmFactor->blockSignals(false); + m_labelPosition->blockSignals(true); + m_labelPosition->setCurrentIndex(slice->labelPosition()); // assumes that index is in sync with the enum + m_labelPosition->blockSignals(false); // exploded m_sliceExploded->blockSignals(true); diff --git a/demos/piechartcustomization/mainwidget.h b/demos/piechartcustomization/mainwidget.h index 8daaf84..401104c 100644 --- a/demos/piechartcustomization/mainwidget.h +++ b/demos/piechartcustomization/mainwidget.h @@ -85,6 +85,7 @@ private: PenTool *m_penTool; QPushButton *m_font; QPushButton *m_labelBrush; + QComboBox *m_labelPosition; BrushTool *m_labelBrushTool; }; diff --git a/src/piechart/piechartitem.cpp b/src/piechart/piechartitem.cpp index aba71e7..2d7fa7c 100644 --- a/src/piechart/piechartitem.cpp +++ b/src/piechart/piechartitem.cpp @@ -145,6 +145,7 @@ void PieChartItem::handleSlicesAdded(QList slices) connect(slice, SIGNAL(brushChanged()), this, SLOT(handleSliceChanged())); connect(slice, SIGNAL(labelBrushChanged()), this, SLOT(handleSliceChanged())); connect(slice, SIGNAL(labelFontChanged()), this, SLOT(handleSliceChanged())); + connect(slice, SIGNAL(labelPositionChanged()), this, SLOT(handleSliceChanged())); connect(slice, SIGNAL(labelArmLengthFactorChanged()), this, SLOT(handleSliceChanged())); connect(slice, SIGNAL(explodeDistanceFactorChanged()), this, SLOT(handleSliceChanged())); diff --git a/src/piechart/pieslicedata_p.h b/src/piechart/pieslicedata_p.h index 1302647..ea99772 100644 --- a/src/piechart/pieslicedata_p.h +++ b/src/piechart/pieslicedata_p.h @@ -75,6 +75,7 @@ public: m_explodeDistanceFactor = 0.15; m_isLabelVisible = false; + m_labelPosition = QPieSlice::LabelOutside; m_labelArmLengthFactor = 0.15; m_percentage = 0; @@ -99,6 +100,7 @@ public: if (m_isLabelVisible != other.m_isLabelVisible || m_labelText != other.m_labelText || m_labelFont != other.m_labelFont || + m_labelPosition != other.m_labelPosition || !qFuzzyIsNull(m_labelArmLengthFactor - other.m_labelArmLengthFactor) || m_labelBrush != other.m_labelBrush) return true; @@ -124,6 +126,7 @@ public: bool m_isLabelVisible; QString m_labelText; Themed m_labelFont; + QPieSlice::LabelPosition m_labelPosition; qreal m_labelArmLengthFactor; Themed m_labelBrush; diff --git a/src/piechart/piesliceitem.cpp b/src/piechart/piesliceitem.cpp index f97eb8b..49781cb 100644 --- a/src/piechart/piesliceitem.cpp +++ b/src/piechart/piesliceitem.cpp @@ -78,13 +78,20 @@ void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*op if (m_data.m_isLabelVisible) { painter->save(); - painter->setClipRect(parentItem()->boundingRect()); + // Pen for label arm not defined in the QPieSeries api, let's use brush's color instead // Also, the drawText actually uses the pen color for the text color (unlike QGraphicsSimpleTextItem) painter->setPen(m_data.m_labelBrush.color()); - painter->drawPath(m_labelArmPath); + painter->setBrush(m_data.m_labelBrush); painter->setFont(m_data.m_labelFont); - painter->drawText(m_labelTextRect.bottomLeft(), m_data.m_labelText); + if (m_data.m_labelPosition == QPieSlice::LabelOutside) { + painter->setClipRect(parentItem()->boundingRect()); + painter->strokePath(m_labelArmPath, m_data.m_labelBrush.color()); + } else { // QPieSlice::LabelInside + painter->setClipPath(m_slicePath); + } + painter->drawText(m_labelTextRect, Qt::AlignCenter, m_data.m_labelText); + painter->restore(); } } @@ -120,22 +127,28 @@ void PieSliceItem::updateGeometry() prepareGeometryChange(); - // update slice path + // slice path qreal centerAngle; QPointF armStart; m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, ¢erAngle, &armStart); - // update text rect - m_labelTextRect = labelTextRect(m_data.m_labelFont, m_data.m_labelText); + // text rect + QFontMetricsF fm(m_data.m_labelFont); + m_labelTextRect = QRectF(0, 0, fm.width(m_data.m_labelText), fm.height()); - // update label arm path + // label arm path QPointF labelTextStart; m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart); - // update text position - m_labelTextRect.moveBottomLeft(labelTextStart); + // text position + if (m_data.m_labelPosition == QPieSlice::LabelOutside) + m_labelTextRect.moveBottomLeft(labelTextStart); + else {// QPieSlice::LabelInside + QPointF sliceCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2); + m_labelTextRect.moveCenter(sliceCenter); + } - // update bounding rect + // bounding rect if (m_data.m_isLabelVisible) m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect); else @@ -208,9 +221,6 @@ QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length *textStart = parm2; } - // elevate the text position a bit so that it does not hit the line - *textStart += QPointF(0, -3); - QPainterPath path; path.moveTo(start); path.lineTo(parm1); @@ -219,12 +229,6 @@ QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length return path; } -QRectF PieSliceItem::labelTextRect(QFont font, QString text) -{ - QFontMetricsF fm(font); - return fm.boundingRect(text); -} - #include "moc_piesliceitem_p.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/piechart/piesliceitem_p.h b/src/piechart/piesliceitem_p.h index 3492ee8..a508fb8 100644 --- a/src/piechart/piesliceitem_p.h +++ b/src/piechart/piesliceitem_p.h @@ -73,7 +73,6 @@ private: void updateGeometry(); QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart); QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart); - QRectF labelTextRect(QFont font, QString text); private: PieSliceData m_data; diff --git a/src/piechart/qpieslice.cpp b/src/piechart/qpieslice.cpp index 9f8878a..a7e5933 100644 --- a/src/piechart/qpieslice.cpp +++ b/src/piechart/qpieslice.cpp @@ -39,6 +39,16 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE */ /*! + \enum QPieSlice::LabelPosition + + This enum describes the position of the slice label. + + \value LabelOutside Label is outside the slice with an arm. + \value LabelInside Label is centered inside the slice. + + */ + +/*! \property QPieSlice::label Label of the slice. @@ -239,6 +249,22 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE */ /*! + \property QPieSlice::labelPosition + + Position of the slice label. + + \sa label, labelVisible +*/ + +/*! + \fn void QPieSlice::labelPositionChanged() + + This signal is emitted when the label position of the slice has changed. + + \sa labelPosition +*/ + +/*! \property QPieSlice::labelArmLengthFactor Defines the length of the label arm. @@ -438,6 +464,19 @@ void QPieSlice::setExploded(bool exploded) } } +QPieSlice::LabelPosition QPieSlice::labelPosition() +{ + return d_ptr->m_data.m_labelPosition; +} + +void QPieSlice::setLabelPosition(LabelPosition position) +{ + if (d_ptr->m_data.m_labelPosition != position) { + d_ptr->m_data.m_labelPosition = position; + emit labelPositionChanged(); + } +} + bool QPieSlice::isExploded() const { return d_ptr->m_data.m_isExploded; diff --git a/src/piechart/qpieslice.h b/src/piechart/qpieslice.h index 9a8d100..91f090f 100644 --- a/src/piechart/qpieslice.h +++ b/src/piechart/qpieslice.h @@ -34,9 +34,11 @@ class QPieSeries; class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject { Q_OBJECT + Q_ENUMS(LabelPosition) Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged) Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged) Q_PROPERTY(bool labelVisible READ isLabelVisible WRITE setLabelVisible NOTIFY labelVisibleChanged) + Q_PROPERTY(LabelPosition labelPosition READ labelPosition WRITE setLabelPosition NOTIFY labelPositionChanged) Q_PROPERTY(bool exploded READ isExploded WRITE setExploded NOTIFY explodedChanged) Q_PROPERTY(QPen pen READ pen WRITE setPen NOTIFY penChanged) Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor NOTIFY borderColorChanged) @@ -53,6 +55,12 @@ class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject Q_PROPERTY(qreal angleSpan READ angleSpan NOTIFY angleSpanChanged) public: + enum LabelPosition { + LabelOutside, + LabelInside + }; + +public: explicit QPieSlice(QObject *parent = 0); QPieSlice(QString label, qreal value, QObject *parent = 0); virtual ~QPieSlice(); @@ -66,6 +74,9 @@ public: void setLabelVisible(bool visible = true); bool isLabelVisible() const; + LabelPosition labelPosition(); + void setLabelPosition(LabelPosition position); + void setExploded(bool exploded = true); bool isExploded() const; @@ -109,6 +120,7 @@ Q_SIGNALS: void labelChanged(); void valueChanged(); void labelVisibleChanged(); + void labelPositionChanged(); void explodedChanged(); void penChanged(); void brushChanged(); diff --git a/tests/auto/qpieslice/tst_qpieslice.cpp b/tests/auto/qpieslice/tst_qpieslice.cpp index ad232a9..ccf80c2 100644 --- a/tests/auto/qpieslice/tst_qpieslice.cpp +++ b/tests/auto/qpieslice/tst_qpieslice.cpp @@ -115,6 +115,7 @@ void tst_qpieslice::changedSignals() QSignalSpy brushSpy(&slice, SIGNAL(brushChanged())); QSignalSpy labelBrushSpy(&slice, SIGNAL(labelBrushChanged())); QSignalSpy labelFontSpy(&slice, SIGNAL(labelFontChanged())); + QSignalSpy labelPositionSpy(&slice, SIGNAL(labelPositionChanged())); QSignalSpy labelArmLengthFactorSpy(&slice, SIGNAL(labelArmLengthFactorChanged())); QSignalSpy explodeDistanceFactorSpy(&slice, SIGNAL(explodeDistanceFactorChanged())); QSignalSpy colorSpy(&slice, SIGNAL(colorChanged())); @@ -142,6 +143,8 @@ void tst_qpieslice::changedSignals() slice.setLabelBrush(QBrush(Qt::green)); slice.setLabelFont(QFont("Tahoma")); slice.setLabelFont(QFont("Tahoma")); + slice.setLabelPosition(QPieSlice::LabelInside); + slice.setLabelPosition(QPieSlice::LabelInside); slice.setLabelArmLengthFactor(0.1); slice.setLabelArmLengthFactor(0.1); slice.setExplodeDistanceFactor(0.1); @@ -154,6 +157,7 @@ void tst_qpieslice::changedSignals() TRY_COMPARE(brushSpy.count(), 1); TRY_COMPARE(labelBrushSpy.count(), 1); TRY_COMPARE(labelFontSpy.count(), 1); + TRY_COMPARE(labelPositionSpy.count(), 1); TRY_COMPARE(labelArmLengthFactorSpy.count(), 1); TRY_COMPARE(explodeDistanceFactorSpy.count(), 1); TRY_COMPARE(colorSpy.count(), 1); diff --git a/tests/qmlchartproperties/qml/qmlchartproperties/PieEditor.qml b/tests/qmlchartproperties/qml/qmlchartproperties/PieEditor.qml index f25c5c1..8986d6a 100644 --- a/tests/qmlchartproperties/qml/qmlchartproperties/PieEditor.qml +++ b/tests/qmlchartproperties/qml/qmlchartproperties/PieEditor.qml @@ -50,6 +50,7 @@ Flow { ignoreUnknownSignals: true onValueChanged: console.log("slice.onValueChanged: " + series.at(0).value); onLabelVisibleChanged: console.log("slice.onLabelVisibleChanged: " + series.at(0).labelVisible); + onLabelPositionChanged: console.log("slice.onLabelPositionChanged: " + series.at(0).labelPosition); onExplodedChanged: console.log("slice.onExplodedChanged: " + series.at(0).exploded); onPenChanged: console.log("slice.onPenChanged: " + series.at(0).pen); onBorderColorChanged: console.log("slice.onBorderColorChanged: " + series.at(0).borderColor); @@ -131,6 +132,14 @@ Flow { onClicked: series.at(0).labelVisible = !series.at(0).labelVisible; } Button { + text: "slice label position inside" + onClicked: series.at(0).labelPosition = PieSlice.LabelInside; + } + Button { + text: "slice label position outside" + onClicked: series.at(0).labelPosition = PieSlice.LabelOutside; + } + Button { text: "slice label arm len +" onClicked: series.at(0).labelArmLengthFactor += 0.1; }