legendlayout.cpp
381 lines
| 12.8 KiB
| text/x-c
|
CppLexer
Michal Klocek
|
r1535 | /**************************************************************************** | ||
** | ||||
** Copyright (C) 2012 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 Commercial Charts Add-on. | ||||
** | ||||
** $QT_BEGIN_LICENSE$ | ||||
** Licensees holding valid Qt Commercial licenses may use this file in | ||||
** accordance with the Qt Commercial 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$ | ||||
** | ||||
****************************************************************************/ | ||||
Michal Klocek
|
r1534 | #include "legendlayout_p.h" | ||
#include "chartpresenter_p.h" | ||||
#include "legendmarker_p.h" | ||||
#include "qlegend_p.h" | ||||
Michal Klocek
|
r1535 | |||
Michal Klocek
|
r1534 | QTCOMMERCIALCHART_BEGIN_NAMESPACE | ||
LegendLayout::LegendLayout(QLegend* legend): | ||||
m_legend(legend) | ||||
{ | ||||
} | ||||
LegendLayout::~LegendLayout() | ||||
{ | ||||
} | ||||
void LegendLayout::setOffset(qreal x, qreal y) | ||||
{ | ||||
bool scrollHorizontal = true; | ||||
switch(m_legend->alignment()) { | ||||
case Qt::AlignTop: | ||||
case Qt::AlignBottom: { | ||||
scrollHorizontal = true; | ||||
break; | ||||
} | ||||
case Qt::AlignLeft: | ||||
case Qt::AlignRight: { | ||||
scrollHorizontal = false; | ||||
break; | ||||
} | ||||
} | ||||
// If detached, the scrolling direction is vertical instead of horizontal and vice versa. | ||||
if (!m_legend->isAttachedToChart()) { | ||||
scrollHorizontal = !scrollHorizontal; | ||||
} | ||||
QRectF boundingRect = geometry(); | ||||
// Limit offset between m_minOffset and m_maxOffset | ||||
if (scrollHorizontal) { | ||||
if(m_width<=boundingRect.width()) return; | ||||
if (x != m_offsetX) { | ||||
m_offsetX = qBound(m_minOffsetX, x, m_maxOffsetX); | ||||
m_legend->d_ptr->items()->setPos(-m_offsetX,boundingRect.top()); | ||||
} | ||||
} | ||||
else { | ||||
if(m_height<=boundingRect.height()) return; | ||||
if (y != m_offsetY) { | ||||
m_offsetY = qBound(m_minOffsetY, y, m_maxOffsetY); | ||||
m_legend->d_ptr->items()->setPos(boundingRect.left(),-m_offsetY); | ||||
} | ||||
} | ||||
} | ||||
QPointF LegendLayout::offset() const | ||||
{ | ||||
return QPointF(m_offsetX,m_offsetY); | ||||
} | ||||
void LegendLayout::setGeometry(const QRectF& rect) | ||||
{ | ||||
Michal Klocek
|
r1837 | m_legend->d_ptr->items()->setVisible(m_legend->isVisible()); | ||
Michal Klocek
|
r1534 | |||
if(m_legend->isAttachedToChart()) { | ||||
Michal Klocek
|
r1837 | |||
Michal Klocek
|
r1534 | setAttachedGeometry(rect); | ||
} | ||||
else { | ||||
setDettachedGeometry(rect); | ||||
} | ||||
Michal Klocek
|
r1837 | |||
QGraphicsLayout::setGeometry(rect); | ||||
Michal Klocek
|
r1534 | } | ||
void LegendLayout::setAttachedGeometry(const QRectF& rect) | ||||
{ | ||||
Michal Klocek
|
r1538 | if (!rect.isValid()) return; | ||
Michal Klocek
|
r1534 | |||
m_offsetX=0; | ||||
m_offsetY=0; | ||||
QSizeF size(0,0); | ||||
if( m_legend->d_ptr->markers().isEmpty()) return; | ||||
m_width=0; | ||||
m_height=0; | ||||
switch(m_legend->alignment()) { | ||||
case Qt::AlignTop: | ||||
case Qt::AlignBottom: { | ||||
QPointF point(0,0); | ||||
foreach (LegendMarker* marker, m_legend->d_ptr->markers()) { | ||||
if (marker->isVisible()) { | ||||
Michal Klocek
|
r1773 | marker->setGeometry(QRectF(QPointF(0,0),marker->effectiveSizeHint(Qt::PreferredSize))); | ||
Michal Klocek
|
r1534 | marker->setPos(point.x(),rect.height()/2 - marker->boundingRect().height()/2); | ||
const QRectF& rect = marker->boundingRect(); | ||||
size = size.expandedTo(rect.size()); | ||||
qreal w = rect.width(); | ||||
m_width+=w; | ||||
point.setX(point.x() + w); | ||||
} | ||||
} | ||||
if(m_width<rect.width()) { | ||||
m_legend->d_ptr->items()->setPos(rect.width()/2-m_width/2,rect.top()); | ||||
} | ||||
else { | ||||
m_legend->d_ptr->items()->setPos(rect.topLeft()); | ||||
} | ||||
m_height=size.height(); | ||||
} | ||||
break; | ||||
case Qt::AlignLeft: | ||||
case Qt::AlignRight: { | ||||
QPointF point(0,0); | ||||
foreach (LegendMarker* marker, m_legend->d_ptr->markers()) { | ||||
if (marker->isVisible()) { | ||||
Michal Klocek
|
r1773 | marker->setGeometry(QRectF(QPointF(0,0),marker->effectiveSizeHint(Qt::PreferredSize))); | ||
Michal Klocek
|
r1534 | marker->setPos(point); | ||
const QRectF& rect = marker->boundingRect(); | ||||
qreal h = rect.height(); | ||||
size = size.expandedTo(rect.size()); | ||||
m_height+=h; | ||||
point.setY(point.y() + h); | ||||
} | ||||
} | ||||
if(m_height<rect.height()) { | ||||
m_legend->d_ptr->items()->setPos(rect.left(),rect.height()/2-m_height/2); | ||||
} | ||||
else { | ||||
m_legend->d_ptr->items()->setPos(rect.topLeft()); | ||||
} | ||||
m_width=size.width(); | ||||
} | ||||
break; | ||||
} | ||||
m_minOffsetX = 0; | ||||
m_minOffsetY = 0; | ||||
m_maxOffsetX = m_width - rect.width(); | ||||
m_maxOffsetY = m_height - rect.height(); | ||||
} | ||||
void LegendLayout::setDettachedGeometry(const QRectF& rect) | ||||
{ | ||||
Michal Klocek
|
r1538 | if (!rect.isValid()) return; | ||
Michal Klocek
|
r1534 | // Detached layout is different. | ||
// In detached mode legend may have multiple rows and columns, so layout calculations | ||||
// differ a log from attached mode. | ||||
// Also the scrolling logic is bit different. | ||||
m_offsetX=0; | ||||
m_offsetY=0; | ||||
QSizeF size(0,0); | ||||
Michal Klocek
|
r1536 | QList<LegendMarker *> markers = m_legend->d_ptr->markers(); | ||
Michal Klocek
|
r1534 | |||
Michal Klocek
|
r1536 | if(markers.isEmpty()) return; | ||
Michal Klocek
|
r1534 | |||
switch (m_legend->alignment()) { | ||||
case Qt::AlignTop: { | ||||
QPointF point = rect.topLeft(); | ||||
m_width = 0; | ||||
m_height = 0; | ||||
Michal Klocek
|
r1536 | for (int i=0; i<markers.count(); i++) { | ||
LegendMarker *marker = markers.at(i); | ||||
if (marker->isVisible()) { | ||||
Michal Klocek
|
r1773 | marker->setGeometry(QRectF(QPointF(0,0),marker->effectiveSizeHint(Qt::PreferredSize))); | ||
Michal Klocek
|
r1536 | marker->setPos(point.x(),point.y()); | ||
const QRectF& boundingRect = marker->boundingRect(); | ||||
Michal Klocek
|
r1534 | qreal w = boundingRect.width(); | ||
qreal h = boundingRect.height(); | ||||
m_width = qMax(m_width,w); | ||||
m_height = qMax(m_height,h); | ||||
point.setX(point.x() + w); | ||||
if (point.x() + w > rect.topLeft().x() + rect.width()) { | ||||
// Next item would go off rect. | ||||
point.setX(rect.topLeft().x()); | ||||
point.setY(point.y() + h); | ||||
Michal Klocek
|
r1536 | if (i+1 < markers.count()) { | ||
Michal Klocek
|
r1534 | m_height += h; | ||
} | ||||
} | ||||
} | ||||
} | ||||
m_legend->d_ptr->items()->setPos(rect.topLeft()); | ||||
m_minOffsetX = 0; | ||||
m_minOffsetY = 0; | ||||
m_maxOffsetX = m_width - rect.width(); | ||||
m_maxOffsetY = m_height - rect.height(); | ||||
} | ||||
break; | ||||
case Qt::AlignBottom: { | ||||
QPointF point = rect.bottomLeft(); | ||||
m_width = 0; | ||||
m_height = 0; | ||||
Michal Klocek
|
r1536 | for (int i=0; i<markers.count(); i++) { | ||
LegendMarker *marker = markers.at(i); | ||||
if (marker->isVisible()) { | ||||
Michal Klocek
|
r1773 | marker->setGeometry(QRectF(QPointF(0,0),marker->effectiveSizeHint(Qt::PreferredSize))); | ||
Michal Klocek
|
r1536 | const QRectF& boundingRect = marker->boundingRect(); | ||
Michal Klocek
|
r1534 | qreal w = boundingRect.width(); | ||
qreal h = boundingRect.height(); | ||||
m_width = qMax(m_width,w); | ||||
m_height = qMax(m_height,h); | ||||
Michal Klocek
|
r1536 | marker->setPos(point.x(),point.y() - h); | ||
Michal Klocek
|
r1534 | point.setX(point.x() + w); | ||
if (point.x() + w > rect.bottomLeft().x() + rect.width()) { | ||||
// Next item would go off rect. | ||||
point.setX(rect.bottomLeft().x()); | ||||
point.setY(point.y() - h); | ||||
Michal Klocek
|
r1536 | if (i+1 < markers.count()) { | ||
Michal Klocek
|
r1534 | m_height += h; | ||
} | ||||
} | ||||
} | ||||
} | ||||
m_legend->d_ptr->items()->setPos(rect.topLeft()); | ||||
m_minOffsetX = 0; | ||||
m_minOffsetY = qMin(rect.topLeft().y(), rect.topLeft().y() - m_height + rect.height()); | ||||
m_maxOffsetX = m_width - rect.width(); | ||||
m_maxOffsetY = 0; | ||||
} | ||||
break; | ||||
case Qt::AlignLeft: { | ||||
QPointF point = rect.topLeft(); | ||||
m_width = 0; | ||||
m_height = 0; | ||||
qreal maxWidth = 0; | ||||
Michal Klocek
|
r1536 | for (int i=0; i<markers.count(); i++) { | ||
LegendMarker *marker = markers.at(i); | ||||
if (marker->isVisible()) { | ||||
Michal Klocek
|
r1773 | marker->setGeometry(QRectF(QPointF(0,0),marker->effectiveSizeHint(Qt::PreferredSize))); | ||
Michal Klocek
|
r1536 | const QRectF& boundingRect = marker->boundingRect(); | ||
Michal Klocek
|
r1534 | qreal w = boundingRect.width(); | ||
qreal h = boundingRect.height(); | ||||
m_height = qMax(m_height,h); | ||||
maxWidth = qMax(maxWidth,w); | ||||
Michal Klocek
|
r1536 | marker->setPos(point.x(),point.y()); | ||
Michal Klocek
|
r1534 | point.setY(point.y() + h); | ||
if (point.y() + h > rect.topLeft().y() + rect.height()) { | ||||
// Next item would go off rect. | ||||
point.setX(point.x() + maxWidth); | ||||
point.setY(rect.topLeft().y()); | ||||
Michal Klocek
|
r1536 | if (i+1 < markers.count()) { | ||
Michal Klocek
|
r1534 | m_width += maxWidth; | ||
maxWidth = 0; | ||||
} | ||||
} | ||||
} | ||||
} | ||||
m_width += maxWidth; | ||||
m_legend->d_ptr->items()->setPos(rect.topLeft()); | ||||
m_minOffsetX = 0; | ||||
m_minOffsetY = 0; | ||||
m_maxOffsetX = m_width - rect.width(); | ||||
m_maxOffsetY = m_height - rect.height(); | ||||
} | ||||
break; | ||||
case Qt::AlignRight: { | ||||
QPointF point = rect.topRight(); | ||||
m_width = 0; | ||||
m_height = 0; | ||||
qreal maxWidth = 0; | ||||
Michal Klocek
|
r1536 | for (int i=0; i<markers.count(); i++) { | ||
LegendMarker *marker = markers.at(i); | ||||
if (marker->isVisible()) { | ||||
Michal Klocek
|
r1773 | marker->setGeometry(QRectF(QPointF(0,0),marker->effectiveSizeHint(Qt::PreferredSize))); | ||
Michal Klocek
|
r1536 | const QRectF& boundingRect = marker->boundingRect(); | ||
Michal Klocek
|
r1534 | qreal w = boundingRect.width(); | ||
qreal h = boundingRect.height(); | ||||
m_height = qMax(m_height,h); | ||||
maxWidth = qMax(maxWidth,w); | ||||
Michal Klocek
|
r1536 | marker->setPos(point.x() - w,point.y()); | ||
Michal Klocek
|
r1534 | point.setY(point.y() + h); | ||
if (point.y() + h > rect.topLeft().y() + rect.height()) { | ||||
// Next item would go off rect. | ||||
point.setX(point.x() - maxWidth); | ||||
point.setY(rect.topLeft().y()); | ||||
Michal Klocek
|
r1536 | if (i+1 < markers.count()) { | ||
Michal Klocek
|
r1534 | m_width += maxWidth; | ||
maxWidth = 0; | ||||
} | ||||
} | ||||
} | ||||
} | ||||
m_width += maxWidth; | ||||
m_legend->d_ptr->items()->setPos(rect.topLeft()); | ||||
m_minOffsetX = qMin(rect.topLeft().x(), rect.topLeft().x() - m_width + rect.width()); | ||||
m_minOffsetY = 0; | ||||
m_maxOffsetX = 0; | ||||
m_maxOffsetY = m_height - rect.height(); | ||||
} | ||||
break; | ||||
default: | ||||
break; | ||||
} | ||||
} | ||||
QSizeF LegendLayout::sizeHint ( Qt::SizeHint which, const QSizeF & constraint) const | ||||
{ | ||||
QSizeF size(0, 0); | ||||
qreal left, top, right, bottom; | ||||
getContentsMargins(&left, &top, &right, &bottom); | ||||
Michal Klocek
|
r1538 | if(which!=Qt::PreferredSize) return QSizeF(-1,-1); | ||
Michal Klocek
|
r1534 | if(constraint.isValid()) { | ||
foreach(LegendMarker* marker, m_legend->d_ptr->markers()) { | ||||
size = size.expandedTo(marker->effectiveSizeHint(which)); | ||||
} | ||||
size = size.boundedTo(constraint); | ||||
} | ||||
else if (constraint.width() >= 0) { | ||||
qreal width = 0; | ||||
qreal height = 0; | ||||
foreach(LegendMarker* marker, m_legend->d_ptr->markers()) { | ||||
width+=marker->effectiveSizeHint(which).width(); | ||||
height=qMax(height,marker->effectiveSizeHint(which).height()); | ||||
} | ||||
size = QSizeF(qMin(constraint.width(),width), height); | ||||
} | ||||
else if (constraint.height() >= 0) { | ||||
qreal width = 0; | ||||
qreal height = 0; | ||||
foreach(LegendMarker* marker, m_legend->d_ptr->markers()) { | ||||
width=qMax(width,marker->effectiveSizeHint(which).width()); | ||||
height+=height,marker->effectiveSizeHint(which).height(); | ||||
} | ||||
size = QSizeF(width,qMin(constraint.height(),height)); | ||||
} | ||||
else { | ||||
foreach(LegendMarker* marker, m_legend->d_ptr->markers()) { | ||||
size = size.expandedTo(marker->effectiveSizeHint(which)); | ||||
} | ||||
} | ||||
size += QSize(left + right, top + bottom); | ||||
Michal Klocek
|
r1538 | |||
Michal Klocek
|
r1534 | return size; | ||
Michal Klocek
|
r1538 | |||
Michal Klocek
|
r1534 | } | ||
QTCOMMERCIALCHART_END_NAMESPACE | ||||