axisitem.cpp
430 lines
| 10.6 KiB
| text/x-c
|
CppLexer
Michal Klocek
|
r67 | #include "axisitem_p.h" | ||
Michal Klocek
|
r140 | #include "qchartaxis.h" | ||
Michal Klocek
|
r262 | #include "chartpresenter_p.h" | ||
Michal Klocek
|
r67 | #include <QPainter> | ||
#include <QDebug> | ||||
Michal Klocek
|
r176 | static int label_padding = 5; | ||
Michal Klocek
|
r85 | |||
Michal Klocek
|
r67 | QTCOMMERCIALCHART_BEGIN_NAMESPACE | ||
Michal Klocek
|
r439 | AxisItem::AxisItem(QChartAxis* axis,AxisType type,QGraphicsItem* parent) : | ||
Michal Klocek
|
r176 | ChartItem(parent), | ||
Michal Klocek
|
r439 | m_chartAxis(axis), | ||
Michal Klocek
|
r176 | m_type(type), | ||
m_labelsAngle(0), | ||||
Michal Klocek
|
r184 | m_grid(parent), | ||
m_shades(parent), | ||||
Michal Klocek
|
r262 | m_labels(parent), | ||
Michal Klocek
|
r502 | m_axis(parent), | ||
m_min(0), | ||||
m_max(0), | ||||
Michal Klocek
|
r513 | m_ticksCount(0), | ||
m_zoomFactor(0) | ||||
Michal Klocek
|
r67 | { | ||
Michal Klocek
|
r145 | //initial initialization | ||
Michal Klocek
|
r272 | m_axis.setZValue(ChartPresenter::AxisZValue); | ||
Michal Klocek
|
r262 | m_shades.setZValue(ChartPresenter::ShadesZValue); | ||
m_grid.setZValue(ChartPresenter::GridZValue); | ||||
Michal Klocek
|
r272 | setFlags(QGraphicsItem::ItemHasNoContents); | ||
Michal Klocek
|
r439 | |||
QObject::connect(m_chartAxis,SIGNAL(updated()),this,SLOT(handleAxisUpdated())); | ||||
Michal Klocek
|
r497 | QObject::connect(m_chartAxis->categories(),SIGNAL(updated()),this,SLOT(handleAxisCategoriesUpdated())); | ||
Michal Klocek
|
r502 | |||
handleAxisUpdated(); | ||||
Michal Klocek
|
r67 | } | ||
AxisItem::~AxisItem() | ||||
{ | ||||
} | ||||
QRectF AxisItem::boundingRect() const | ||||
{ | ||||
Michal Klocek
|
r291 | return QRectF(); | ||
Michal Klocek
|
r67 | } | ||
Michal Klocek
|
r223 | void AxisItem::createItems(int count) | ||
Michal Klocek
|
r176 | { | ||
Michal Klocek
|
r291 | if(m_axis.children().size()==0) | ||
m_axis.addToGroup(new QGraphicsLineItem()); | ||||
Michal Klocek
|
r223 | for (int i = 0; i < count; ++i) { | ||
Michal Klocek
|
r291 | m_grid.addToGroup(new QGraphicsLineItem()); | ||
m_labels.addToGroup(new QGraphicsSimpleTextItem()); | ||||
if(m_grid.childItems().size()%2) m_shades.addToGroup(new QGraphicsRectItem()); | ||||
m_axis.addToGroup(new QGraphicsLineItem()); | ||||
Michal Klocek
|
r176 | } | ||
} | ||||
Michal Klocek
|
r502 | void AxisItem::deleteItems(int count) | ||
Michal Klocek
|
r176 | { | ||
Michal Klocek
|
r291 | QList<QGraphicsItem *> lines = m_grid.childItems(); | ||
QList<QGraphicsItem *> labels = m_labels.childItems(); | ||||
QList<QGraphicsItem *> shades = m_shades.childItems(); | ||||
QList<QGraphicsItem *> axis = m_axis.childItems(); | ||||
Michal Klocek
|
r176 | |||
Michal Klocek
|
r291 | for (int i = 0; i < count; ++i) { | ||
delete(lines.takeLast()); | ||||
delete(labels.takeLast()); | ||||
if(lines.size()%2) delete(shades.takeLast()); | ||||
delete(axis.takeLast()); | ||||
Michal Klocek
|
r272 | } | ||
Michal Klocek
|
r176 | } | ||
Michal Klocek
|
r502 | void AxisItem::updateLayout(QVector<qreal>& layout) | ||
Michal Klocek
|
r176 | { | ||
Michal Klocek
|
r452 | setLayout(layout); | ||
Michal Klocek
|
r85 | } | ||
Michal Klocek
|
r176 | |||
Michal Klocek
|
r502 | QStringList AxisItem::createLabels(int ticks, qreal min, qreal max) const | ||
Michal Klocek
|
r85 | { | ||
Michal Klocek
|
r439 | Q_ASSERT(max>=min); | ||
Michal Klocek
|
r502 | Q_ASSERT(ticks>0); | ||
Michal Klocek
|
r85 | |||
Michal Klocek
|
r439 | QStringList labels; | ||
Michal Klocek
|
r85 | |||
Michal Klocek
|
r497 | QChartAxisCategories* categories = m_chartAxis->categories(); | ||
Michal Klocek
|
r291 | |||
Michal Klocek
|
r502 | for(int i=0; i< ticks; i++) { | ||
qreal value = min + (i * (max - min)/ (ticks-1)); | ||||
Michal Klocek
|
r497 | if(categories->count()==0) { | ||
Michal Klocek
|
r439 | labels << QString::number(value); | ||
} | ||||
else { | ||||
Michal Klocek
|
r497 | QString label = categories->label(value); | ||
Michal Klocek
|
r439 | labels << label; | ||
} | ||||
Michal Klocek
|
r223 | } | ||
Michal Klocek
|
r439 | return labels; | ||
Michal Klocek
|
r176 | } | ||
Michal Klocek
|
r85 | |||
Michal Klocek
|
r184 | void AxisItem::setAxisOpacity(qreal opacity) | ||
{ | ||||
m_axis.setOpacity(opacity); | ||||
} | ||||
qreal AxisItem::axisOpacity() const | ||||
{ | ||||
return m_axis.opacity(); | ||||
} | ||||
Michal Klocek
|
r176 | void AxisItem::setGridOpacity(qreal opacity) | ||
{ | ||||
m_grid.setOpacity(opacity); | ||||
} | ||||
Michal Klocek
|
r85 | |||
Michal Klocek
|
r176 | qreal AxisItem::gridOpacity() const | ||
{ | ||||
return m_grid.opacity(); | ||||
} | ||||
Michal Klocek
|
r85 | |||
Michal Klocek
|
r176 | void AxisItem::setLabelsOpacity(qreal opacity) | ||
{ | ||||
m_labels.setOpacity(opacity); | ||||
} | ||||
Michal Klocek
|
r85 | |||
Michal Klocek
|
r176 | qreal AxisItem::labelsOpacity() const | ||
{ | ||||
return m_labels.opacity(); | ||||
} | ||||
Michal Klocek
|
r85 | |||
Michal Klocek
|
r176 | void AxisItem::setShadesOpacity(qreal opacity) | ||
{ | ||||
m_shades.setOpacity(opacity); | ||||
} | ||||
Michal Klocek
|
r85 | |||
Michal Klocek
|
r176 | qreal AxisItem::shadesOpacity() const | ||
{ | ||||
return m_shades.opacity(); | ||||
} | ||||
Michal Klocek
|
r67 | |||
Michal Klocek
|
r176 | void AxisItem::setLabelsAngle(int angle) | ||
{ | ||||
foreach(QGraphicsItem* item , m_labels.childItems()) { | ||||
QPointF center = item->boundingRect().center(); | ||||
item->setRotation(angle); | ||||
Michal Klocek
|
r145 | } | ||
Michal Klocek
|
r176 | |||
m_labelsAngle=angle; | ||||
Michal Klocek
|
r67 | } | ||
Michal Klocek
|
r176 | void AxisItem::setLabelsPen(const QPen& pen) | ||
Michal Klocek
|
r140 | { | ||
Michal Klocek
|
r176 | foreach(QGraphicsItem* item , m_labels.childItems()) { | ||
static_cast<QGraphicsSimpleTextItem*>(item)->setPen(pen); | ||||
} | ||||
Michal Klocek
|
r140 | } | ||
Michal Klocek
|
r176 | void AxisItem::setLabelsBrush(const QBrush& brush) | ||
Michal Klocek
|
r140 | { | ||
Michal Klocek
|
r176 | foreach(QGraphicsItem* item , m_labels.childItems()) { | ||
static_cast<QGraphicsSimpleTextItem*>(item)->setBrush(brush); | ||||
} | ||||
Michal Klocek
|
r140 | } | ||
Michal Klocek
|
r176 | void AxisItem::setLabelsFont(const QFont& font) | ||
Michal Klocek
|
r140 | { | ||
Michal Klocek
|
r176 | foreach(QGraphicsItem* item , m_labels.childItems()) { | ||
static_cast<QGraphicsSimpleTextItem*>(item)->setFont(font); | ||||
} | ||||
Michal Klocek
|
r140 | } | ||
Michal Klocek
|
r176 | void AxisItem::setShadesBrush(const QBrush& brush) | ||
Michal Klocek
|
r140 | { | ||
Michal Klocek
|
r176 | foreach(QGraphicsItem* item , m_shades.childItems()) { | ||
static_cast<QGraphicsRectItem*>(item)->setBrush(brush); | ||||
} | ||||
Michal Klocek
|
r140 | } | ||
Michal Klocek
|
r176 | void AxisItem::setShadesPen(const QPen& pen) | ||
Michal Klocek
|
r140 | { | ||
Michal Klocek
|
r176 | foreach(QGraphicsItem* item , m_shades.childItems()) { | ||
static_cast<QGraphicsRectItem*>(item)->setPen(pen); | ||||
} | ||||
} | ||||
Michal Klocek
|
r184 | void AxisItem::setAxisPen(const QPen& pen) | ||
{ | ||||
Michal Klocek
|
r272 | foreach(QGraphicsItem* item , m_axis.childItems()) { | ||
static_cast<QGraphicsLineItem*>(item)->setPen(pen); | ||||
} | ||||
Michal Klocek
|
r184 | } | ||
Michal Klocek
|
r176 | void AxisItem::setGridPen(const QPen& pen) | ||
{ | ||||
foreach(QGraphicsItem* item , m_grid.childItems()) { | ||||
static_cast<QGraphicsLineItem*>(item)->setPen(pen); | ||||
} | ||||
} | ||||
Michal Klocek
|
r393 | QVector<qreal> AxisItem::calculateLayout() const | ||
Michal Klocek
|
r291 | { | ||
Michal Klocek
|
r502 | Q_ASSERT(m_ticksCount>=2); | ||
Michal Klocek
|
r393 | QVector<qreal> points; | ||
Michal Klocek
|
r502 | points.resize(m_ticksCount); | ||
Michal Klocek
|
r393 | |||
Michal Klocek
|
r291 | switch (m_type) | ||
{ | ||||
case X_AXIS: | ||||
{ | ||||
Michal Klocek
|
r502 | const qreal deltaX = m_rect.width()/(m_ticksCount-1); | ||
for (int i = 0; i < m_ticksCount; ++i) { | ||||
Michal Klocek
|
r291 | int x = i * deltaX + m_rect.left(); | ||
Michal Klocek
|
r393 | points[i] = x; | ||
Michal Klocek
|
r291 | } | ||
} | ||||
break; | ||||
case Y_AXIS: | ||||
{ | ||||
Michal Klocek
|
r502 | const qreal deltaY = m_rect.height()/(m_ticksCount-1); | ||
for (int i = 0; i < m_ticksCount; ++i) { | ||||
Michal Klocek
|
r291 | int y = i * -deltaY + m_rect.bottom(); | ||
Michal Klocek
|
r393 | points[i] = y; | ||
Michal Klocek
|
r291 | } | ||
} | ||||
break; | ||||
} | ||||
Michal Klocek
|
r393 | return points; | ||
Michal Klocek
|
r291 | } | ||
Michal Klocek
|
r502 | void AxisItem::setLayout(QVector<qreal>& layout) | ||
Michal Klocek
|
r291 | { | ||
Michal Klocek
|
r502 | int diff = m_layoutVector.size() - layout.size(); | ||
if(diff>0) { | ||||
deleteItems(diff); | ||||
} | ||||
else if(diff<0) { | ||||
createItems(-diff); | ||||
} | ||||
Michal Klocek
|
r513 | if(diff!=0) handleAxisUpdated(); | ||
QStringList ticksList = createLabels(m_ticksCount,m_min,m_max); | ||||
Michal Klocek
|
r502 | QList<QGraphicsItem *> lines = m_grid.childItems(); | ||
QList<QGraphicsItem *> labels = m_labels.childItems(); | ||||
QList<QGraphicsItem *> shades = m_shades.childItems(); | ||||
QList<QGraphicsItem *> axis = m_axis.childItems(); | ||||
Michal Klocek
|
r513 | Q_ASSERT(labels.size() == ticksList.size()); | ||
Q_ASSERT(layout.size() == ticksList.size()); | ||||
Michal Klocek
|
r502 | |||
switch (m_type) | ||||
{ | ||||
case X_AXIS: | ||||
{ | ||||
QGraphicsLineItem *lineItem = static_cast<QGraphicsLineItem*>(axis.at(0)); | ||||
lineItem->setLine(m_rect.left(), m_rect.bottom(), m_rect.right(), m_rect.bottom()); | ||||
for (int i = 0; i < layout.size(); ++i) { | ||||
QGraphicsLineItem *lineItem = static_cast<QGraphicsLineItem*>(lines.at(i)); | ||||
lineItem->setLine(layout[i], m_rect.top(), layout[i], m_rect.bottom()); | ||||
QGraphicsSimpleTextItem *labelItem = static_cast<QGraphicsSimpleTextItem*>(labels.at(i)); | ||||
Michal Klocek
|
r513 | labelItem->setText(ticksList.at(i)); | ||
Michal Klocek
|
r502 | QPointF center = labelItem->boundingRect().center(); | ||
labelItem->setTransformOriginPoint(center.x(), center.y()); | ||||
labelItem->setPos(layout[i] - center.x(), m_rect.bottom() + label_padding); | ||||
if(i%2 && i+1 < layout.size()) { | ||||
QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem*>(shades.at(i/2)); | ||||
rectItem->setRect(layout[i],m_rect.top(),layout[i+1]-layout[i],m_rect.height()); | ||||
} | ||||
lineItem = static_cast<QGraphicsLineItem*>(axis.at(i+1)); | ||||
lineItem->setLine(layout[i],m_rect.bottom(),layout[i],m_rect.bottom()+5); | ||||
} | ||||
} | ||||
break; | ||||
case Y_AXIS: | ||||
{ | ||||
QGraphicsLineItem *lineItem = static_cast<QGraphicsLineItem*>(axis.at(0)); | ||||
lineItem->setLine(m_rect.left() , m_rect.top(), m_rect.left(), m_rect.bottom()); | ||||
for (int i = 0; i < layout.size(); ++i) { | ||||
QGraphicsLineItem *lineItem = static_cast<QGraphicsLineItem*>(lines.at(i)); | ||||
lineItem->setLine(m_rect.left() , layout[i], m_rect.right(), layout[i]); | ||||
QGraphicsSimpleTextItem *labelItem = static_cast<QGraphicsSimpleTextItem*>(labels.at(i)); | ||||
Michal Klocek
|
r513 | labelItem->setText(ticksList.at(i)); | ||
Michal Klocek
|
r502 | QPointF center = labelItem->boundingRect().center(); | ||
labelItem->setTransformOriginPoint(center.x(), center.y()); | ||||
labelItem->setPos(m_rect.left() - labelItem->boundingRect().width() - label_padding , layout[i]-center.y()); | ||||
if(i%2 && i+1 < layout.size()) { | ||||
QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem*>(shades.at(i/2)); | ||||
rectItem->setRect(m_rect.left(),layout[i],m_rect.width(),layout[i]-layout[i+1]); | ||||
} | ||||
lineItem = static_cast<QGraphicsLineItem*>(axis.at(i+1)); | ||||
lineItem->setLine(m_rect.left()-5,layout[i],m_rect.left(),layout[i]); | ||||
} | ||||
} | ||||
break; | ||||
default: | ||||
qDebug()<<"Unknown axis type"; | ||||
break; | ||||
} | ||||
Michal Klocek
|
r513 | //if(diff!=0) handleAxisUpdated(); | ||
Michal Klocek
|
r502 | m_layoutVector=layout; | ||
} | ||||
Michal Klocek
|
r291 | |||
Michal Klocek
|
r502 | bool AxisItem::isEmpty() | ||
{ | ||||
return m_rect.isEmpty() || m_min==m_max || m_ticksCount==0; | ||||
Michal Klocek
|
r291 | } | ||
Michal Klocek
|
r140 | |||
Michal Klocek
|
r439 | //handlers | ||
Michal Klocek
|
r497 | void AxisItem::handleAxisCategoriesUpdated() | ||
{ | ||||
Michal Klocek
|
r502 | if(isEmpty()) return; | ||
updateLayout(m_layoutVector); | ||||
Michal Klocek
|
r497 | } | ||
Michal Klocek
|
r439 | void AxisItem::handleAxisUpdated() | ||
{ | ||||
Michal Klocek
|
r497 | |||
int count = m_chartAxis->ticksCount(); | ||||
Michal Klocek
|
r502 | if(m_ticksCount!=count){ | ||
Michal Klocek
|
r513 | //handleTicksCountChanged(count); | ||
Michal Klocek
|
r497 | } | ||
Michal Klocek
|
r452 | if(isEmpty()) return; | ||
Michal Klocek
|
r439 | |||
if(m_chartAxis->isAxisVisible()) { | ||||
setAxisOpacity(100); | ||||
} | ||||
else { | ||||
setAxisOpacity(0); | ||||
} | ||||
if(m_chartAxis->isGridVisible()) { | ||||
setGridOpacity(100); | ||||
} | ||||
else { | ||||
setGridOpacity(0); | ||||
} | ||||
if(m_chartAxis->labelsVisible()) | ||||
{ | ||||
setLabelsOpacity(100); | ||||
} | ||||
else { | ||||
setLabelsOpacity(0); | ||||
} | ||||
if(m_chartAxis->shadesVisible()) { | ||||
setShadesOpacity(m_chartAxis->shadesOpacity()); | ||||
} | ||||
else { | ||||
setShadesOpacity(0); | ||||
} | ||||
setLabelsAngle(m_chartAxis->labelsAngle()); | ||||
setAxisPen(m_chartAxis->axisPen()); | ||||
setLabelsPen(m_chartAxis->labelsPen()); | ||||
setLabelsBrush(m_chartAxis->labelsBrush()); | ||||
setLabelsFont(m_chartAxis->labelsFont()); | ||||
setGridPen(m_chartAxis->gridPen()); | ||||
setShadesPen(m_chartAxis->shadesPen()); | ||||
setShadesBrush(m_chartAxis->shadesBrush()); | ||||
Michal Klocek
|
r452 | |||
Michal Klocek
|
r439 | } | ||
Michal Klocek
|
r502 | void AxisItem::handleTicksCountChanged(int count) | ||
{ | ||||
m_ticksCount=count; | ||||
if(isEmpty()) return; | ||||
QVector<qreal> layout = calculateLayout(); | ||||
updateLayout(layout); | ||||
} | ||||
Michal Klocek
|
r439 | void AxisItem::handleRangeChanged(qreal min, qreal max) | ||
{ | ||||
Michal Klocek
|
r513 | if(m_min<min || m_max>max){ | ||
m_zoomFactor = (min + (max-min)/2 - m_min)/(m_max - m_min); | ||||
} | ||||
else | ||||
m_zoomFactor=-1; | ||||
Michal Klocek
|
r452 | m_min = min; | ||
m_max = max; | ||||
Michal Klocek
|
r439 | |||
Michal Klocek
|
r513 | m_ticksCount = qrand()%10; | ||
while(m_ticksCount<2){ | ||||
m_ticksCount = qrand()%10; | ||||
} | ||||
qDebug()<<"Warning : This is testing . Simulating new random ticks "<< m_ticksCount; | ||||
//m_chartAxis->setTicksCount(m_ticksCount); | ||||
Michal Klocek
|
r452 | if(isEmpty()) return; | ||
Michal Klocek
|
r502 | QVector<qreal> layout = calculateLayout(); | ||
updateLayout(layout); | ||||
Michal Klocek
|
r439 | |||
Michal Klocek
|
r452 | } | ||
Michal Klocek
|
r439 | |||
void AxisItem::handleGeometryChanged(const QRectF& rect) | ||||
{ | ||||
Michal Klocek
|
r502 | |||
Michal Klocek
|
r439 | m_rect = rect; | ||
Michal Klocek
|
r452 | if(isEmpty()) return; | ||
Michal Klocek
|
r502 | QVector<qreal> layout = calculateLayout(); | ||
updateLayout(layout); | ||||
Michal Klocek
|
r452 | } | ||
Michal Klocek
|
r439 | |||
Michal Klocek
|
r502 | //painter | ||
void AxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) | ||||
Michal Klocek
|
r452 | { | ||
Michal Klocek
|
r502 | Q_UNUSED(painter); | ||
Q_UNUSED(option); | ||||
Q_UNUSED(widget); | ||||
Michal Klocek
|
r439 | } | ||
Michal Klocek
|
r67 | //TODO "nice numbers algorithm" | ||
Michal Klocek
|
r140 | #include "moc_axisitem_p.cpp" | ||
Michal Klocek
|
r67 | |||
QTCOMMERCIALCHART_END_NAMESPACE | ||||