diff --git a/examples/legend/mainwidget.cpp b/examples/legend/mainwidget.cpp index f9c2d0b..80d51d4 100644 --- a/examples/legend/mainwidget.cpp +++ b/examples/legend/mainwidget.cpp @@ -27,6 +27,7 @@ #include #include #include +#include QTCOMMERCIALCHART_USE_NAMESPACE @@ -49,25 +50,52 @@ MainWidget::MainWidget(QWidget *parent) : connect(removeBarsetButton, SIGNAL(clicked()), this, SLOT(removeBarset())); m_buttonLayout->addWidget(removeBarsetButton, 3, 0); + QPushButton *leftButton = new QPushButton("Align legend left"); + connect(leftButton, SIGNAL(clicked()), this, SLOT(setLegendLeft())); + m_buttonLayout->addWidget(leftButton, 4, 0); + + QPushButton *rightButton = new QPushButton("Align legend right"); + connect(rightButton, SIGNAL(clicked()), this, SLOT(setLegendRight())); + m_buttonLayout->addWidget(rightButton, 5, 0); + + QPushButton *topButton = new QPushButton("Align legend top"); + connect(topButton, SIGNAL(clicked()), this, SLOT(setLegendTop())); + m_buttonLayout->addWidget(topButton, 6, 0); + + QPushButton *bottomButton = new QPushButton("Align legend bottom"); + connect(bottomButton, SIGNAL(clicked()), this, SLOT(setLegendBottom())); + m_buttonLayout->addWidget(bottomButton, 7, 0); + + m_legendPosX = new QDoubleSpinBox(); + m_legendPosY = new QDoubleSpinBox(); + m_legendWidth = new QDoubleSpinBox(); + m_legendHeight = new QDoubleSpinBox(); + + connect(m_legendPosX, SIGNAL(valueChanged(double)), this, SLOT(updateLegendLayout())); + connect(m_legendPosY, SIGNAL(valueChanged(double)), this, SLOT(updateLegendLayout())); + connect(m_legendWidth, SIGNAL(valueChanged(double)), this, SLOT(updateLegendLayout())); + connect(m_legendHeight, SIGNAL(valueChanged(double)), this, SLOT(updateLegendLayout())); + + QFormLayout* legendLayout = new QFormLayout(); + legendLayout->addRow("Horizontal position", m_legendPosX); + legendLayout->addRow("Vertical position", m_legendPosY); + legendLayout->addRow("Width", m_legendWidth); + legendLayout->addRow("Height", m_legendHeight); + m_legendSettings = new QGroupBox("Detached legend"); + m_legendSettings->setLayout(legendLayout); + m_buttonLayout->addWidget(m_legendSettings); + m_legendSettings->setVisible(false); + // Create chart view with the chart //![1] m_chart = new QChart(); m_chartView = new QChartView(m_chart, this); - m_chartView->setRubberBand(QChartView::HorizonalRubberBand); //![1] - // Create custom scene and view, where detached legend will be drawn -//![2] - m_customView = new QGraphicsView(this); - m_customScene = new QGraphicsScene(this); - m_customView->setScene(m_customScene); -//![2] - // Create layout for grid and detached legend m_mainLayout = new QGridLayout(); m_mainLayout->addLayout(m_buttonLayout, 0, 0); m_mainLayout->addWidget(m_chartView, 0, 1, 3, 1); - m_mainLayout->addWidget(m_customView, 0, 2, 3, 1); setLayout(m_mainLayout); createSeries(); @@ -93,43 +121,61 @@ void MainWidget::createSeries() //![3] } +void MainWidget::showLegendSpinbox() +{ + m_legendSettings->setVisible(true); + QRectF chartViewRect = m_chartView->rect(); + QRectF legendRect = m_chart->legend()->boundingRect(); + + m_legendPosX->setMinimum(0); + m_legendPosX->setMaximum(chartViewRect.width()); + m_legendPosX->setValue(150); + + m_legendPosY->setMinimum(0); + m_legendPosY->setMaximum(chartViewRect.height()); + m_legendPosY->setValue(150); + + m_legendWidth->setMinimum(0); + m_legendWidth->setMaximum(chartViewRect.width()); + m_legendWidth->setValue(150); + + m_legendHeight->setMinimum(0); + m_legendHeight->setMaximum(chartViewRect.height()); + m_legendHeight->setValue(64); +} + +void MainWidget::hideLegendSpinbox() +{ + m_legendSettings->setVisible(false); +} + + void MainWidget::detachLegend() { - // Detach legend from chart and - // put legend to our custom scene //![4] QLegend *legend = m_chart->legend(); legend->detachFromChart(); - legend->setGeometry(m_customView->rect()); - m_customScene->addItem(legend); + + m_chart->legend()->setBackgroundVisible(true); + m_chart->legend()->setBrush(QBrush(QColor(128,128,128,128))); //![4] - // This forces redraw - QSize delta(1,1); - resize(size() + delta); - resize(size() - delta); + showLegendSpinbox(); + updateLegendLayout(); + update(); } void MainWidget::attachLegend() { - // Remove legend from custom scene and put it back to chartview scene. - // Attach legend back to chart, so that layout works. - //![5] QLegend *legend = m_chart->legend(); - - if (m_customScene->items().contains(legend)) { - m_customScene->removeItem(legend); - m_chartView->scene()->addItem(legend); - legend->attachToChart(); - } + legend->attachToChart(); + m_chart->legend()->setBackgroundVisible(false); //![5] - // This forces redraw - QSize delta(1,1); - resize(size() + delta); - resize(size() - delta); + hideLegendSpinbox(); + update(); } void MainWidget::addBarset() @@ -147,3 +193,32 @@ void MainWidget::removeBarset() m_series->remove(sets.at(sets.count()-1)); } } + +void MainWidget::setLegendLeft() +{ + m_chart->legend()->setAlignment(Qt::AlignLeft); +} + +void MainWidget::setLegendRight() +{ + m_chart->legend()->setAlignment(Qt::AlignRight); +} + +void MainWidget::setLegendTop() +{ + m_chart->legend()->setAlignment(Qt::AlignTop); +} + +void MainWidget::setLegendBottom() +{ + m_chart->legend()->setAlignment(Qt::AlignBottom); +} + +void MainWidget::updateLegendLayout() +{ + m_chart->legend()->setGeometry(m_legendPosX->value() + ,m_legendPosY->value() + ,m_legendWidth->value() + ,m_legendHeight->value()); + m_chart->legend()->update(); +} diff --git a/examples/legend/mainwidget.h b/examples/legend/mainwidget.h index 8b20716..43cf415 100644 --- a/examples/legend/mainwidget.h +++ b/examples/legend/mainwidget.h @@ -28,6 +28,8 @@ #include #include #include +#include +#include QTCOMMERCIALCHART_USE_NAMESPACE @@ -36,9 +38,10 @@ class MainWidget : public QWidget Q_OBJECT public: explicit MainWidget(QWidget *parent = 0); - void createSeries(); - + void showLegendSpinbox(); + void hideLegendSpinbox(); + signals: public slots: @@ -47,6 +50,13 @@ public slots: void addBarset(); void removeBarset(); + void setLegendLeft(); + void setLegendRight(); + void setLegendTop(); + void setLegendBottom(); + + void updateLegendLayout(); + private: QChart *m_chart; @@ -56,8 +66,12 @@ private: QGridLayout *m_mainLayout; QGridLayout *m_buttonLayout; - QGraphicsView *m_customView; - QGraphicsScene *m_customScene; + // For detached layout + QGroupBox* m_legendSettings; + QDoubleSpinBox *m_legendPosX; + QDoubleSpinBox *m_legendPosY; + QDoubleSpinBox *m_legendWidth; + QDoubleSpinBox *m_legendHeight; }; #endif // MAINWIDGET_H diff --git a/src/chartpresenter.cpp b/src/chartpresenter.cpp index e8b32e7..5695cc6 100644 --- a/src/chartpresenter.cpp +++ b/src/chartpresenter.cpp @@ -318,8 +318,6 @@ void ChartPresenter::updateLayout() // recalculate legend position if (legend != 0 && legend->isAttachedToChart() && legend->isEnabled()) { - QRect legendRect; - // Reserve some space for legend switch (legend->alignment()) { @@ -382,7 +380,9 @@ void ChartPresenter::updateLayout() QRectF chartRect = m_rect.adjusted(m_chartMargins.left(),m_chartMargins.top(),-m_chartMargins.right(),-m_chartMargins.bottom()); - legend->setGeometry(m_rect.adjusted(m_legendMargins.left(),m_legendMargins.top(),-m_legendMargins.right(),-m_legendMargins.bottom())); + if (legend != 0 && legend->isAttachedToChart() && legend->isEnabled()) { + legend->setGeometry(m_rect.adjusted(m_legendMargins.left(),m_legendMargins.top(),-m_legendMargins.right(),-m_legendMargins.bottom())); + } if(m_chartRect!=chartRect && chartRect.isValid()){ m_chartRect=chartRect; diff --git a/src/legend/qlegend.cpp b/src/legend/qlegend.cpp index dd7d462..094da40 100644 --- a/src/legend/qlegend.cpp +++ b/src/legend/qlegend.cpp @@ -320,29 +320,38 @@ QLegendPrivate::~QLegendPrivate() void QLegendPrivate::setOffset(qreal x, qreal y) { - + bool scrollHorizontal = true; switch(m_alignment) { - case Qt::AlignTop: case Qt::AlignBottom: { - if(m_width<=m_rect.width()) return; - - if (x != m_offsetX) { - m_offsetX = qBound(qreal(0), x, m_width - m_rect.width()); - m_markers->setPos(-m_offsetX,m_rect.top()); - } + scrollHorizontal = true; break; } case Qt::AlignLeft: case Qt::AlignRight: { + scrollHorizontal = false; + break; + } + } - if(m_height<=m_rect.height()) return; + // If detached, the scrolling and layout logic is inverted. + if (!m_attachedToChart) { + scrollHorizontal = !scrollHorizontal; + } - if (y != m_offsetY) { - m_offsetY = qBound(qreal(0), y, m_height - m_rect.height()); - m_markers->setPos(m_rect.left(),-m_offsetY); - } - break; + if (scrollHorizontal) { + if(m_width<=m_rect.width()) return; + + if (x != m_offsetX) { + m_offsetX = qBound(qreal(0), x, m_width - m_rect.width()); + m_markers->setPos(-m_offsetX,m_rect.top()); + } + } else { + if(m_height<=m_rect.height()) return; + + if (y != m_offsetY) { + m_offsetY = qBound(qreal(0), y, m_height - m_rect.height()); + m_markers->setPos(m_rect.left(),-m_offsetY); } } } @@ -350,6 +359,11 @@ void QLegendPrivate::setOffset(qreal x, qreal y) void QLegendPrivate::updateLayout() { + if (!m_attachedToChart) { + updateDetachedLayout(); + return; + } + m_offsetX=0; QList items = m_markers->childItems(); @@ -406,8 +420,136 @@ void QLegendPrivate::updateLayout() break; } - if (m_attachedToChart) { - m_presenter->updateLayout(); + m_presenter->updateLayout(); +} + +void QLegendPrivate::updateDetachedLayout() +{ + m_offsetX=0; + QList items = m_markers->childItems(); + + if(items.isEmpty()) return; + + m_minWidth = 0; + m_minHeight = 0; + + switch (m_alignment) { + case Qt::AlignTop: { + QPointF point = m_rect.topLeft(); + m_width = 0; + m_height = 0; + for (int i=0; iboundingRect(); + qreal w = rect.width(); + qreal h = rect.height(); + m_minWidth = qMax(m_minWidth,w); + m_minHeight = qMax(m_minHeight,rect.height()); + m_height = qMax(m_height,h); + item->setPos(point.x(),point.y()); + point.setX(point.x() + w); + if (point.x() + w > m_rect.topLeft().x() + m_rect.width()) { + // Next item would go off rect. + point.setX(m_rect.topLeft().x()); + point.setY(point.y() + h); + if (i+1 < items.count()) { + m_height += h; + } + } + } + m_markers->setPos(m_rect.topLeft()); + m_width = m_minWidth; + } + break; + case Qt::AlignBottom: { + QPointF point = m_rect.bottomLeft(); + m_width = 0; + m_height = 0; + for (int i=0; iboundingRect(); + qreal w = rect.width(); + qreal h = rect.height(); + m_minWidth = qMax(m_minWidth,w); + m_minHeight = qMax(m_minHeight,rect.height()); + m_height = qMax(m_height,h); + item->setPos(point.x(),point.y() - h); + point.setX(point.x() + w); + if (point.x() + w > m_rect.bottomLeft().x() + m_rect.width()) { + // Next item would go off rect. + point.setX(m_rect.bottomLeft().x()); + point.setY(point.y() - h); + if (i+1 < items.count()) { + m_height += h; + } + } + } + m_markers->setPos(m_rect.topLeft()); + m_width = m_minWidth; + } + break; + case Qt::AlignLeft: { + QPointF point = m_rect.topLeft(); + m_width = 0; + m_height = 0; + qreal maxWidth = 0; + for (int i=0; iboundingRect(); + qreal w = rect.width(); + qreal h = rect.height(); + m_minWidth = qMax(m_minWidth,rect.width()); + m_minHeight = qMax(m_minHeight,h); + maxWidth = qMax(maxWidth,w); + m_width = qMax(m_width, maxWidth); + item->setPos(point.x(),point.y()); + point.setY(point.y() + h); + if (point.y() + h > m_rect.topLeft().y() + m_rect.height()) { + // Next item would go off rect. + point.setX(point.x() + maxWidth); + point.setY(m_rect.topLeft().y()); + if (i+1 < items.count()) { + m_width += maxWidth; + maxWidth = 0; + } + } + } + m_markers->setPos(m_rect.topLeft()); + m_height = m_minHeight; + } + break; + case Qt::AlignRight: { + QPointF point = m_rect.topRight(); + m_width = 0; + m_height = 0; + qreal maxWidth = 0; + for (int i=0; iboundingRect(); + qreal w = rect.width(); + qreal h = rect.height(); + m_minWidth = qMax(m_minWidth,rect.width()); + m_minHeight = qMax(m_minHeight,h); + maxWidth = qMax(maxWidth,w); + m_width = qMax(m_width, maxWidth); + item->setPos(point.x() - w,point.y()); + point.setY(point.y() + h); + if (point.y() + h > m_rect.topLeft().y() + m_rect.height()) { + // Next item would go off rect. + point.setX(point.x() - maxWidth); + point.setY(m_rect.topLeft().y()); + if (i+1 < items.count()) { + m_width += maxWidth; + maxWidth = 0; + } + } + } + m_markers->setPos(m_rect.topLeft()); + m_height = m_minHeight; + } + break; + default: + break; } } diff --git a/src/legend/qlegend_p.h b/src/legend/qlegend_p.h index 4dc6f71..4305712 100644 --- a/src/legend/qlegend_p.h +++ b/src/legend/qlegend_p.h @@ -47,6 +47,7 @@ public: void setOffset(qreal x, qreal y); void updateLayout(); + void updateDetachedLayout(); void attachToChart(); public Q_SLOTS: