diff --git a/charts.pro b/charts.pro index 18d71ab..7e121b5 100644 --- a/charts.pro +++ b/charts.pro @@ -3,7 +3,14 @@ } TEMPLATE = subdirs -SUBDIRS += src qmlplugin example test +SUBDIRS += src example test qmlplugin + +integrated_build:{ + message('Configured for integrated build') +} else { + message('Please build example test and qmlplugin after installing library.') +} + CONFIG += ordered QMAKE_CXXFLAGS += -g -Wall unix:QMAKE_DISTCLEAN += -r build bin diff --git a/common.pri b/common.pri index 38921c2..a37e6ba 100644 --- a/common.pri +++ b/common.pri @@ -1,13 +1,15 @@ CONFIG+=integrated_build #remove if you want to build against installed libs -CHART_BUILD_HEADER_DIR = $$PWD/include +CHART_BUILD_PUBLIC_HEADER_DIR = $$PWD/include +CHART_BUILD_PRIVATE_HEADER_DIR = $$CHART_BUILD_PUBLIC_HEADER_DIR/private CHART_BUILD_LIB_DIR = $$PWD/lib CHART_BUILD_DIR = $$PWD/build CHART_BUILD_BIN_DIR = $$PWD/bin # hack to fix windows builds win32:{ - CHART_BUILD_HEADER_DIR = $$replace(CHART_BUILD_HEADER_DIR, "/","\\") + CHART_BUILD_PUBLIC_HEADER_DIR = $$replace(CHART_BUILD_PUBLIC_HEADER_DIR, "/","\\") + CHART_BUILD_PRIVATE_HEADER_DIR = $$replace(CHART_BUILD_PRIVATE_HEADER_DIR, "/","\\") CHART_BUILD_LIB_DIR = $$replace(CHART_BUILD_LIB_DIR, "/","\\") CHART_BUILD_BUILD_DIR = $$replace(CHART_BUILD_BUILD_DIR, "/","\\") CHART_BUILD_BIN_DIR = $$replace(CHART_BUILD_BIN_DIR, "/","\\") diff --git a/example/example.pro b/example/example.pro index db1b164..b6bdd01 100644 --- a/example/example.pro +++ b/example/example.pro @@ -9,4 +9,5 @@ SUBDIRS += linechart \ piechart \ dynamiclinechart \ axischart\ -gdpbarchart + gdpbarchart\ + multichart diff --git a/example/multichart/main.cpp b/example/multichart/main.cpp new file mode 100644 index 0000000..09e97b9 --- /dev/null +++ b/example/multichart/main.cpp @@ -0,0 +1,18 @@ +#include +#include +#include "multichartwidget.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + MultiChartWidget *multi = new MultiChartWidget(); + + // Use the chart widget as the central widget + QMainWindow w; + w.resize(640, 480); + w.setCentralWidget(multi); + w.show(); + + return a.exec(); +} diff --git a/example/multichart/multichart.pro b/example/multichart/multichart.pro new file mode 100644 index 0000000..ae573ac --- /dev/null +++ b/example/multichart/multichart.pro @@ -0,0 +1,21 @@ +!include( ../../common.pri ) { + error( "Couldn't find the common.pri file!" ) +} +!include( ../../integrated.pri ) { + error( "Couldn't find the integrated.pri file !") +} + +QT += core gui + +TARGET = multichart +TEMPLATE = app + +SOURCES += main.cpp \ + multichartwidget.cpp + +HEADERS += \ + multichartwidget.h + + + + diff --git a/example/multichart/multichartwidget.cpp b/example/multichart/multichartwidget.cpp new file mode 100644 index 0000000..eeb5bcd --- /dev/null +++ b/example/multichart/multichartwidget.cpp @@ -0,0 +1,35 @@ +#include "multichartwidget.h" +#include +#include +#include +#include +#include + +QTCOMMERCIALCHART_USE_NAMESPACE + +MultiChartWidget::MultiChartWidget(QWidget *parent) : + QWidget(parent) +{ + QVBoxLayout *l = new QVBoxLayout(this); + + // Create chart 1 and add a simple pie series onto it + QChartView *chartView1 = new QChartView(); + l->addWidget(chartView1); + QPieSeries *pie = new QPieSeries(); + pie->add(1.1, "label1"); + pie->add(1.2, "label2"); + chartView1->addSeries(pie); + + // Create chart 2 and add a simple scatter series onto it + QChartView *chartView2 = new QChartView(); + l->addWidget(chartView2); + QScatterSeries *scatter = new QScatterSeries(); + *scatter << QPointF(0.5, 5.0) + << QPointF(1.0, 4.5) + << QPointF(1.0, 5.5) + << QPointF(1.5, 5.0) + << QPointF(2.0, 4.5) + << QPointF(2.0, 5.5) + << QPointF(2.5, 5.0); + chartView2->addSeries(scatter); +} diff --git a/example/multichart/multichartwidget.h b/example/multichart/multichartwidget.h new file mode 100644 index 0000000..feb6456 --- /dev/null +++ b/example/multichart/multichartwidget.h @@ -0,0 +1,18 @@ +#ifndef MULTICHARTWIDGET_H +#define MULTICHARTWIDGET_H + +#include + +class MultiChartWidget : public QWidget +{ + Q_OBJECT +public: + explicit MultiChartWidget(QWidget *parent = 0); + +signals: + +public slots: + +}; + +#endif // MULTICHARTWIDGET_H diff --git a/example/piechart/customslice.cpp b/example/piechart/customslice.cpp new file mode 100644 index 0000000..46c223e --- /dev/null +++ b/example/piechart/customslice.cpp @@ -0,0 +1,20 @@ +#include "customslice.h" + +CustomSlice::CustomSlice(qreal value, QObject* parent) + :QPieSlice(parent) +{ + setValue(value); + connect(this, SIGNAL(changed()), this, SLOT(updateLabel())); + connect(this, SIGNAL(hoverEnter()), this, SLOT(toggleExploded())); + connect(this, SIGNAL(hoverLeave()), this, SLOT(toggleExploded())); +} + +void CustomSlice::updateLabel() +{ + setLabel(QString::number(this->percentage())); +} + +void CustomSlice::toggleExploded() +{ + setExploded(!isExploded()); +} diff --git a/example/piechart/customslice.h b/example/piechart/customslice.h new file mode 100644 index 0000000..3c6ccf4 --- /dev/null +++ b/example/piechart/customslice.h @@ -0,0 +1,15 @@ +#include + +QTCOMMERCIALCHART_USE_NAMESPACE + +class CustomSlice : public QPieSlice +{ + Q_OBJECT + +public: + CustomSlice(qreal value, QObject* parent = 0); + +public Q_SLOTS: + void updateLabel(); + void toggleExploded(); +}; diff --git a/example/piechart/main.cpp b/example/piechart/main.cpp index 203b6b5..18b737c 100644 --- a/example/piechart/main.cpp +++ b/example/piechart/main.cpp @@ -1,9 +1,10 @@ #include #include -#include #include #include #include +#include +#include "customslice.h" QTCOMMERCIALCHART_USE_NAMESPACE @@ -11,23 +12,31 @@ int main(int argc, char *argv[]) { QApplication a(argc, argv); - // Create widget and scatter series - QChartView *chartWidget = new QChartView(); - QPieSeries *series = qobject_cast(chartWidget->createSeries(QChartSeries::SeriesTypePie)); - Q_ASSERT(series); - - // Add test data to the series - series->add(QPieSlice(1, "test1", true, true, QPen(Qt::red, 2), QBrush(Qt::red))); - series->add(QPieSlice(2, "test2")); - series->add(QPieSlice(3, "test3")); - series->add(QPieSlice(4, "test4")); - series->add(QPieSlice(5, "test5")); - - // Use the chart widget as the central widget - QMainWindow w; - w.resize(640, 480); - w.setCentralWidget(chartWidget); - w.show(); + QMainWindow window; + + QPieSeries *series = new QPieSeries(); + series->add(5, "Slice 1"); + series->add(2, "Slice 2"); + series->add(3, "Slice 3"); + series->add(4, "Slice 4"); + series->add(5, "Slice 5"); + series->add(6, "Slice 6"); + series->add(7, "Slice 7"); + series->add(new CustomSlice(8)); + series->enableClickExplodes(true); + series->enableHoverHighlight(true); + + foreach (QPieSlice*s, series->slices()) + qDebug() << s->angle() << s->span() << s->percentage(); + + QChartView* chartView = new QChartView(&window); + chartView->addSeries(series); + chartView->setChartTitle("simple piechart"); + chartView->setChartTheme(QChart::ChartThemeIcy); + + window.setCentralWidget(chartView); + window.resize(600, 600); + window.show(); return a.exec(); } diff --git a/example/piechart/piechart.pro b/example/piechart/piechart.pro index 2d7c9ad..29de32e 100644 --- a/example/piechart/piechart.pro +++ b/example/piechart/piechart.pro @@ -10,8 +10,10 @@ QT += core gui TARGET = piechart TEMPLATE = app -SOURCES += main.cpp +SOURCES += main.cpp customslice.cpp +HEADERS += customslice.h -HEADERS += +OBJECTS_DIR = tmp +MOC_DIR = tmp diff --git a/example/scatter/main.cpp b/example/scatter/main.cpp index e1ed334..ac6a1d4 100644 --- a/example/scatter/main.cpp +++ b/example/scatter/main.cpp @@ -14,20 +14,38 @@ int main(int argc, char *argv[]) // Create chart widget QChartView *chartWidget = new QChartView(); - // Create scatter series with simple test data + // Add scatter series with simple test data QScatterSeries *scatter = new QScatterSeries(); - *scatter << QPointF(0.5, 2.0) - << QPointF(1.0, 2.5) - << QPointF(1.5, 2.0) - << QPointF(2.0, 2.5); + *scatter << QPointF(0.5, 5.0) + << QPointF(1.0, 4.5) + << QPointF(1.0, 5.5) + << QPointF(1.5, 5.0) + << QPointF(2.0, 4.5) + << QPointF(2.0, 5.5) + << QPointF(2.5, 5.0); chartWidget->addSeries(scatter); - // Add another scatter series with more complex data with random component + // Add another scatter series + // - more data with random component QScatterSeries *scatter2 = new QScatterSeries(); - for (qreal i(0.0); i < 20; i += 0.5) + for (qreal i(0.0); i < 20; i += 0.05) { (*scatter2) << QPointF(i + (qreal)(rand() % 100) / 100.0, - i + (qreal)(rand() % 100) / 100.0); + i + (qreal)(rand() % 100) / 100.0); + } chartWidget->addSeries(scatter2); + // Custom pen and brush (not those defined by the chart theme) + // - uses opaque color + QColor color("#2685BF"); + color.setAlpha(80); + QBrush brush(Qt::SolidPattern); + brush.setColor(color); + scatter2->setMarkerBrush(brush); + QPen pen; + pen.setColor(color); + pen.setWidth(2); + scatter2->setMarkerPen(pen); + // use a rectangle as the marker shape + scatter2->setMarkerShape(QScatterSeries::MarkerShapeRectangle); // Use the chart widget as the central widget QMainWindow w; diff --git a/integrated.pri b/integrated.pri index 8e154a1..f6d4e24 100644 --- a/integrated.pri +++ b/integrated.pri @@ -1,11 +1,17 @@ integrated_build:{ - message('Internal build within charts core source tree') - INCLUDEPATH += $$CHART_BUILD_HEADER_DIR + message('Running integrated build against local libs...') + INCLUDEPATH += $$CHART_BUILD_PUBLIC_HEADER_DIR !win32: { LIBS += -L $$CHART_BUILD_LIB_DIR -Wl,-rpath,$$CHART_BUILD_LIB_DIR }else{ - LIBS += -L $$CHART_BUILD_LIB_DIR + win32-msvc*: { + # hack fix for error: + # "LINK : fatal error LNK1146: no argument specified with option '/LIBPATH:'" + QMAKE_LIBDIR += $$CHART_BUILD_LIB_DIR + }else{ + LIBS += -L $$CHART_BUILD_LIB_DIR + } } DESTDIR = $$CHART_BUILD_BIN_DIR @@ -45,5 +51,6 @@ integrated_build:{ } } else { + message('Running build aginst system libs...') CONFIG+=qtcommercialchart } diff --git a/qmlplugin/declarativechart.cpp b/qmlplugin/declarativechart.cpp index f2ba366..2487e14 100644 --- a/qmlplugin/declarativechart.cpp +++ b/qmlplugin/declarativechart.cpp @@ -7,7 +7,6 @@ DeclarativeChart::DeclarativeChart(QDeclarativeItem *parent) m_chart(new QChart(this)) { setFlag(QGraphicsItem::ItemHasNoContents, false); -// m_chart->setMargin(50); // TODO: should not be needed? } DeclarativeChart::ChartTheme DeclarativeChart::theme() @@ -18,8 +17,21 @@ DeclarativeChart::ChartTheme DeclarativeChart::theme() void DeclarativeChart::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { - if (newGeometry.isValid()) - m_chart->resize(newGeometry.width(), newGeometry.height()); + qDebug() << "geometryChanged " << this << " old geometry: " << oldGeometry; + if (newGeometry.isValid()) { + if (newGeometry.width() > 0 && newGeometry.height() > 0) { + // TODO: setting margin should not be needed to make axis visible? + const int margin = 30; + if (m_chart->margin() == 0 + && newGeometry.width() > (margin * 2) + && newGeometry.height() > (margin * 2)) { + m_chart->setMargin(margin); + m_chart->resize(newGeometry.width(), newGeometry.height()); + } else { + m_chart->resize(newGeometry.width(), newGeometry.height()); + } + } + } } #include "moc_declarativechart.cpp" diff --git a/qmlplugin/declarativescatterseries.cpp b/qmlplugin/declarativescatterseries.cpp new file mode 100644 index 0000000..50925ff --- /dev/null +++ b/qmlplugin/declarativescatterseries.cpp @@ -0,0 +1,69 @@ +#include "declarativescatterseries.h" +#include "declarativechart.h" +#include "qchart.h" +#include "qscatterseries.h" +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +DeclarativeScatterSeries::DeclarativeScatterSeries(QDeclarativeItem *parent) : + QDeclarativeItem(parent), + m_chart(0), + m_series(0) +{ + setFlag(QGraphicsItem::ItemHasNoContents, false); + connect(this, SIGNAL(parentChanged()), + this, SLOT(setParentForSeries())); +} + +void DeclarativeScatterSeries::setParentForSeries() +{ + if (!m_series) + initSeries(); +} + +void DeclarativeScatterSeries::initSeries() +{ + Q_ASSERT(!m_series); + DeclarativeChart *declarativeChart = qobject_cast(parent()); + + if (declarativeChart) { + QChart *chart = qobject_cast(declarativeChart->m_chart); + qDebug() << "creating scatter series for chart: " << chart; + Q_ASSERT(chart); + + m_series = new QScatterSeries(); + Q_ASSERT(m_series); + for (int i(0); i < m_data.count(); i++) { + ScatterElement *element = m_data.at(i); + *m_series << QPointF(element->x(), element->y()); + } + chart->addSeries(m_series); + } +} + +QDeclarativeListProperty DeclarativeScatterSeries::data() +{ + return QDeclarativeListProperty(this, 0, + &DeclarativeScatterSeries::appendData); +} + +void DeclarativeScatterSeries::appendData(QDeclarativeListProperty *list, + ScatterElement *element) +{ + DeclarativeScatterSeries *series = qobject_cast(list->object); + qDebug() << "appendData: " << series; + qDebug() << "appendData: " << element; + qDebug() << "appendData: " << element->x(); + qDebug() << "appendData: " << element->y(); + qDebug() << "appendData: " << series->m_series; + if (series) { + series->m_data.append(element); + if (series->m_series) + series->m_series->addData(QPointF(element->x(), element->y())); + } +} + +#include "moc_declarativescatterseries.cpp" + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/qmlplugin/declarativescatterseries.h b/qmlplugin/declarativescatterseries.h new file mode 100644 index 0000000..fda58c0 --- /dev/null +++ b/qmlplugin/declarativescatterseries.h @@ -0,0 +1,42 @@ +#ifndef DECLARATIVESCATTERSERIES_H +#define DECLARATIVESCATTERSERIES_H + +#include "qchartglobal.h" +#include "scatterelement.h" +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class QChart; +class QScatterSeries; + +class DeclarativeScatterSeries : public QDeclarativeItem +{ + Q_OBJECT + Q_PROPERTY(QDeclarativeListProperty data READ data) + +public: + explicit DeclarativeScatterSeries(QDeclarativeItem *parent = 0); + QDeclarativeListProperty data(); + +signals: + +public slots: + static void appendData(QDeclarativeListProperty *list, + ScatterElement *element); +// void append(ScatterElement element); + +private slots: + void setParentForSeries(); + +public: + void initSeries(); + + QChart *m_chart; + QScatterSeries *m_series; + QList m_data; +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif // DECLARATIVESCATTERSERIES_H diff --git a/qmlplugin/declarativeseries.cpp b/qmlplugin/declarativeseries.cpp index 7dc9dfc..7710083 100644 --- a/qmlplugin/declarativeseries.cpp +++ b/qmlplugin/declarativeseries.cpp @@ -86,15 +86,6 @@ void DeclarativeSeries::initSeries() } } -QVariant DeclarativeSeries::itemChange(GraphicsItemChange change, - const QVariant &value) -{ - // For debugging purposes only: -// qDebug() << QString::number(change) << " : " << value.toString(); - return QGraphicsItem::itemChange(change, value); -} - - #include "moc_declarativeseries.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/qmlplugin/declarativeseries.h b/qmlplugin/declarativeseries.h index 0d57425..0392a95 100644 --- a/qmlplugin/declarativeseries.h +++ b/qmlplugin/declarativeseries.h @@ -34,9 +34,6 @@ signals: public slots: void setParentForSeries(); -public: // from QDeclarativeItem - QVariant itemChange(GraphicsItemChange, const QVariant &); - public: void setSeriesType(SeriesType type); SeriesType seriesType() { return m_seriesType; } diff --git a/qmlplugin/plugin.cpp b/qmlplugin/plugin.cpp index d9140f3..545952c 100644 --- a/qmlplugin/plugin.cpp +++ b/qmlplugin/plugin.cpp @@ -2,6 +2,8 @@ #include #include "declarativechart.h" #include "declarativeseries.h" +#include "scatterelement.h" +#include "declarativescatterseries.h" QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -14,7 +16,8 @@ public: Q_ASSERT(QLatin1String(uri) == QLatin1String("QtCommercial.Chart")); qmlRegisterType(uri, 1, 0, "Chart"); qmlRegisterType(uri, 1, 0, "Series"); - //qmlRegisterUncreatableType(uri, 1, 0, "Series.Se", QLatin1String("Do not create objects of this type.")); + qmlRegisterType(uri, 1, 0, "ScatterSeries"); + qmlRegisterType(uri, 1, 0, "ScatterElement"); } }; diff --git a/qmlplugin/qmlplugin.pro b/qmlplugin/qmlplugin.pro index cde7f93..6a452a8 100644 --- a/qmlplugin/qmlplugin.pro +++ b/qmlplugin/qmlplugin.pro @@ -24,10 +24,14 @@ RCC_DIR = $$CHART_BUILD_DIR/lib SOURCES += \ plugin.cpp \ declarativechart.cpp \ - declarativeseries.cpp + declarativeseries.cpp \ + declarativescatterseries.cpp \ + scatterelement.cpp HEADERS += \ declarativechart.h \ - declarativeseries.h + declarativeseries.h \ + declarativescatterseries.h \ + scatterelement.h TARGETPATH = QtCommercial/Chart target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH @@ -37,3 +41,17 @@ qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH INSTALLS += target qmldir + + + + + + + + + + + + + + diff --git a/qmlplugin/scatterelement.cpp b/qmlplugin/scatterelement.cpp new file mode 100644 index 0000000..f1c3aa4 --- /dev/null +++ b/qmlplugin/scatterelement.cpp @@ -0,0 +1,12 @@ +#include "scatterelement.h" + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +ScatterElement::ScatterElement(QObject *parent) : + QObject(parent) +{ +} + +#include "moc_scatterelement.cpp" + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/qmlplugin/scatterelement.h b/qmlplugin/scatterelement.h new file mode 100644 index 0000000..ad91c92 --- /dev/null +++ b/qmlplugin/scatterelement.h @@ -0,0 +1,30 @@ +#ifndef SCATTERELEMENT_H +#define SCATTERELEMENT_H + +#include "qchartglobal.h" +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class ScatterElement : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal x READ x WRITE setX /*NOTIFY dataXChanged*/) + Q_PROPERTY(qreal y READ y WRITE setY /*NOTIFY dataYChanged*/) + +public: + explicit ScatterElement(QObject *parent = 0); + + void setX(qreal x) {m_x = x;} + qreal x() {return m_x;} + void setY(qreal y) {m_y = y;} + qreal y() {return m_y;} + +public: + qreal m_x; + qreal m_y; +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif // SCATTERELEMENT_H diff --git a/src/chartdataset.cpp b/src/chartdataset.cpp index bd3bcb4..af0ae36 100644 --- a/src/chartdataset.cpp +++ b/src/chartdataset.cpp @@ -29,6 +29,7 @@ void ChartDataSet::addSeries(QChartSeries* series) { // TODO: we should check the series not already added m_chartSeries << series; + series->setParent(this); // take ownership m_domainIndex = 0; m_domains.resize(1); diff --git a/src/chartpresenter.cpp b/src/chartpresenter.cpp index 45735dd..07463b1 100644 --- a/src/chartpresenter.cpp +++ b/src/chartpresenter.cpp @@ -18,7 +18,7 @@ #include "percentbargroup.h" #include "linechartanimationitem_p.h" #include "piepresenter.h" -#include "scatterpresenter.h" +#include "scatterpresenter_p.h" QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -127,9 +127,6 @@ void ChartPresenter::handleSeriesAdded(QChartSeries* series) QObject::connect(m_dataset, SIGNAL(domainChanged(const Domain&)), scatterPresenter, SLOT(handleDomainChanged(const Domain&))); m_chartTheme->decorate(scatterPresenter, scatterSeries, m_chartItems.count()); -// scatterSeries->d->m_theme = m_chartTheme->themeForSeries(); -// scatterSeries->d->setParentItem(this); -// scatterSeries->d->m_boundingRect = m_rect.adjusted(margin(),margin(), -margin(), -margin()); m_chartItems.insert(scatterSeries, scatterPresenter); break; } diff --git a/src/charttheme.cpp b/src/charttheme.cpp index cfe5bd3..8d3b5d3 100644 --- a/src/charttheme.cpp +++ b/src/charttheme.cpp @@ -10,6 +10,7 @@ #include "qlinechartseries.h" #include "qscatterseries.h" #include "qpieseries.h" +#include "qpieslice.h" //items #include "axisitem_p.h" @@ -17,7 +18,7 @@ #include "stackedbargroup.h" #include "linechartitem_p.h" #include "percentbargroup.h" -#include "scatterpresenter.h" +#include "scatterpresenter_p.h" #include "piepresenter.h" //themes @@ -104,6 +105,14 @@ void ChartTheme::decorate(ChartItem* item, QChartSeries* series,int count) decorate(i,s,count); break; } + case QChartSeries::SeriesTypeScatter: { + QScatterSeries* s = qobject_cast(series); + Q_ASSERT(s); + ScatterPresenter* i = static_cast(item); + Q_ASSERT(i); + decorate(i, s, count); + break; + } case QChartSeries::SeriesTypePie: { QPieSeries* s = static_cast(series); PiePresenter* i = static_cast(item); @@ -179,16 +188,16 @@ void ChartTheme::decorate(ScatterPresenter* presenter, QScatterSeries* series, i Q_ASSERT(presenter); Q_ASSERT(series); - presenter->m_markerPen.setColor(m_seriesColor.at(count % m_seriesColor.size())); + QColor color = m_seriesColor.at(count % m_seriesColor.size()); + // TODO: define alpha in the theme? or in the series? + color.setAlpha(120); + + QBrush brush(color, Qt::SolidPattern); + presenter->m_markerBrush = brush; -// QPen pen; -// if(pen != series->pen()){ -// item->setPen(series->pen()); -// return; -// } -// pen.setColor(m_seriesColor.at(count%m_seriesColor.size())); -// pen.setWidthF(2); -// item->setPen(pen); + QPen pen(brush, 1); + pen.setColor(color); + presenter->m_markerPen = pen; } void ChartTheme::decorate(PiePresenter* item, QPieSeries* series, int /*count*/) @@ -224,11 +233,9 @@ void ChartTheme::decorate(PiePresenter* item, QPieSeries* series, int /*count*/) } // finally update colors - foreach (QPieSliceId id, series->ids()) { - QPieSlice s = series->slice(id); - s.setPen(QPen(Qt::black)); // TODO: get from theme - s.setBrush(colors.takeFirst()); - series->update(s); + foreach (QPieSlice* s, series->slices()) { + s->setPen(QPen(Qt::black)); // TODO: get from theme + s->setBrush(colors.takeFirst()); } } diff --git a/src/piechart/piechart.pri b/src/piechart/piechart.pri index 133f19c..d5018df 100644 --- a/src/piechart/piechart.pri +++ b/src/piechart/piechart.pri @@ -5,7 +5,8 @@ SOURCES += \ $$PWD/qpieseries.cpp \ $$PWD/pieslice.cpp \ $$PWD/piepresenter.cpp \ - $$PWD/pieslicelabel.cpp + $$PWD/pieslicelabel.cpp \ + $$PWD/qpieslice.cpp PRIVATE_HEADERS += \ $$PWD/piepresenter.h \ @@ -13,4 +14,5 @@ PRIVATE_HEADERS += \ $$PWD/pieslicelabel.h PUBLIC_HEADERS += \ - $$PWD/qpieseries.h + $$PWD/qpieseries.h \ + $$PWD/qpieslice.h diff --git a/src/piechart/piepresenter.cpp b/src/piechart/piepresenter.cpp index 87f0701..362f828 100644 --- a/src/piechart/piepresenter.cpp +++ b/src/piechart/piepresenter.cpp @@ -1,6 +1,7 @@ #include "piepresenter.h" #include "pieslice.h" +#include "qpieslice.h" #include #include @@ -29,140 +30,124 @@ void PiePresenter::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet) { - qDebug() << "PiePresenter::handleSeriesChanged()"; - qDebug() << " added : " << changeSet.m_added; - qDebug() << " changed: " << changeSet.m_changed; - qDebug() << " removed: " << changeSet.m_removed; + //qDebug() << "PiePresenter::handleSeriesChanged()"; + //qDebug() << " added : " << changeSet.added(); + //qDebug() << " changed: " << changeSet.changed(); + //qDebug() << " removed: " << changeSet.removed(); // ignore changeset when there are no visual slices // changeset might not be valid about the added slices if (m_slices.count() == 0) { - foreach (QPieSliceId id, m_series->m_slices.keys()) - addSlice(id); + foreach (QPieSlice* s, m_series->m_slices) + addSlice(s); return; } - foreach (QPieSliceId id, changeSet.m_removed) - deleteSlice(id); + foreach (QPieSlice* s, changeSet.removed()) + deleteSlice(s); - foreach (QPieSliceId id, changeSet.m_changed) - updateSlice(id); + foreach (QPieSlice* s, changeSet.added()) + addSlice(s); +} - foreach (QPieSliceId id, changeSet.m_added) - addSlice(id); +void PiePresenter::handleDomainChanged(const Domain& domain) +{ + // TODO +} + +void PiePresenter::handleGeometryChanged(const QRectF& rect) +{ + m_rect = rect; + updateGeometry(); } void PiePresenter::updateGeometry() { prepareGeometryChange(); - m_pieRect = m_rect; + QRectF pieRect = m_rect; - if (m_pieRect.width() < m_pieRect.height()) { - m_pieRect.setWidth(m_pieRect.width() * m_series->sizeFactor()); - m_pieRect.setHeight(m_pieRect.width()); - m_pieRect.moveCenter(m_rect.center()); + if (pieRect.width() < pieRect.height()) { + pieRect.setWidth(pieRect.width() * m_series->sizeFactor()); + pieRect.setHeight(pieRect.width()); + pieRect.moveCenter(m_rect.center()); } else { - m_pieRect.setHeight(m_pieRect.height() * m_series->sizeFactor()); - m_pieRect.setWidth(m_pieRect.height()); - m_pieRect.moveCenter(m_rect.center()); + pieRect.setHeight(pieRect.height() * m_series->sizeFactor()); + pieRect.setWidth(pieRect.height()); + pieRect.moveCenter(m_rect.center()); } switch (m_series->position()) { case QPieSeries::PiePositionTopLeft: { - m_pieRect.setHeight(m_pieRect.height() / 2); - m_pieRect.setWidth(m_pieRect.height()); - m_pieRect.moveCenter(QPointF(m_rect.center().x() / 2, m_rect.center().y() / 2)); + pieRect.setHeight(pieRect.height() / 2); + pieRect.setWidth(pieRect.height()); + pieRect.moveCenter(QPointF(m_rect.center().x() / 2, m_rect.center().y() / 2)); break; } case QPieSeries::PiePositionTopRight: { - m_pieRect.setHeight(m_pieRect.height() / 2); - m_pieRect.setWidth(m_pieRect.height()); - m_pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, m_rect.center().y() / 2)); + pieRect.setHeight(pieRect.height() / 2); + pieRect.setWidth(pieRect.height()); + pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, m_rect.center().y() / 2)); break; } case QPieSeries::PiePositionBottomLeft: { - m_pieRect.setHeight(m_pieRect.height() / 2); - m_pieRect.setWidth(m_pieRect.height()); - m_pieRect.moveCenter(QPointF(m_rect.center().x() / 2, (m_rect.center().y() / 2) * 3)); + pieRect.setHeight(pieRect.height() / 2); + pieRect.setWidth(pieRect.height()); + pieRect.moveCenter(QPointF(m_rect.center().x() / 2, (m_rect.center().y() / 2) * 3)); break; } case QPieSeries::PiePositionBottomRight: { - m_pieRect.setHeight(m_pieRect.height() / 2); - m_pieRect.setWidth(m_pieRect.height()); - m_pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, (m_rect.center().y() / 2) * 3)); + pieRect.setHeight(pieRect.height() / 2); + pieRect.setWidth(pieRect.height()); + pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, (m_rect.center().y() / 2) * 3)); break; } default: break; } - // update slice geometry - const qreal fullPie = 360; - qreal angle = 0; - foreach (QPieSliceId id, m_slices.keys()) { - qreal span = fullPie * m_series->slice(id).percentage(); - m_slices[id]->updateGeometry(m_pieRect, angle, span); - angle += span; + if (m_pieRect != pieRect) { + m_pieRect = pieRect; + //qDebug() << "PiePresenter::updateGeometry()" << m_pieRect; + foreach (PieSlice* s, m_slices.values()) { + s->setPieRect(m_pieRect); + s->updateGeometry(); + } } - - //qDebug() << "PiePresenter::updateGeometry" << m_rect << m_pieRect; } -void PiePresenter::handleDomainChanged(const Domain& domain) +void PiePresenter::addSlice(QPieSlice* sliceData) { - // TODO -} + //qDebug() << "PiePresenter::addSlice()" << sliceData; -void PiePresenter::handleGeometryChanged(const QRectF& rect) -{ - m_rect = rect; - updateGeometry(); -} - -void PiePresenter::addSlice(QPieSliceId id) -{ - qDebug() << "PiePresenter::addSlice()" << id; - - if (m_slices.contains(id)) { - qWarning() << "PiePresenter::addSlice(): slice already exists!" << id; - updateSlice(id); + if (m_slices.keys().contains(sliceData)) { + //qWarning() << "PiePresenter::addSlice(): slice already exists!" << sliceData; + Q_ASSERT(0); return; } // create slice - PieSlice *slice = new PieSlice(id, m_series, this); - m_slices.insert(id, slice); - - updateGeometry(); + PieSlice *slice = new PieSlice(this); + slice->updateData(sliceData); + m_slices.insert(sliceData, slice); + + // connect signals + connect(sliceData, SIGNAL(changed()), slice, SLOT(handleSliceDataChanged())); + connect(slice, SIGNAL(clicked()), sliceData, SIGNAL(clicked())); + connect(slice, SIGNAL(hoverEnter()), sliceData, SIGNAL(hoverEnter())); + connect(slice, SIGNAL(hoverLeave()), sliceData, SIGNAL(hoverLeave())); } -void PiePresenter::updateSlice(QPieSliceId id) +void PiePresenter::deleteSlice(QPieSlice* sliceData) { - qDebug() << "PiePresenter::updateSlice()" << id; + //qDebug() << "PiePresenter::deleteSlice()" << sliceData; - // TODO: animation - if (m_slices.contains(id)) - m_slices.value(id)->updateData(); + if (m_slices.contains(sliceData)) + delete m_slices.take(sliceData); else { - qWarning() << "PiePresenter::updateSlice(): slice does not exist!" << id; - addSlice(id); + // nothing to remove + Q_ASSERT(0); // TODO: remove before release } - - updateGeometry(); -} - -void PiePresenter::deleteSlice(QPieSliceId id) -{ - qDebug() << "PiePresenter::deleteSlice()" << id; - - // TODO: animation - if (m_slices.contains(id)) - delete m_slices.take(id); - else - qWarning() << "PiePresenter::deleteSlice(): slice does not exist!" << id; - - updateGeometry(); } #include "moc_piepresenter.cpp" diff --git a/src/piechart/piepresenter.h b/src/piechart/piepresenter.h index 50e8a5d..a3348f9 100644 --- a/src/piechart/piepresenter.h +++ b/src/piechart/piepresenter.h @@ -32,13 +32,12 @@ public Q_SLOTS: void updateGeometry(); private: - void addSlice(QPieSliceId id); - void updateSlice(QPieSliceId id); - void deleteSlice(QPieSliceId id); + void addSlice(QPieSlice* sliceData); + void deleteSlice(QPieSlice* sliceData); private: friend class PieSlice; - QHash m_slices; + QHash m_slices; QPieSeries *m_series; QRectF m_rect; QRectF m_pieRect; diff --git a/src/piechart/pieslice.cpp b/src/piechart/pieslice.cpp index 321890d..898e3c3 100644 --- a/src/piechart/pieslice.cpp +++ b/src/piechart/pieslice.cpp @@ -2,6 +2,7 @@ #include "pieslicelabel.h" #include "piepresenter.h" #include "qpieseries.h" +#include "qpieslice.h" #include #include #include @@ -20,27 +21,25 @@ QPointF offset(qreal angle, qreal length) return QPointF(dx, -dy); } -PieSlice::PieSlice(QPieSliceId id, QPieSeries *series, QGraphicsItem* parent) +PieSlice::PieSlice(QGraphicsItem* parent) :QGraphicsObject(parent), - m_id(id), - m_series(series), m_slicelabel(new PieSliceLabel(this)), - m_isHovering(false) + m_angle(0), + m_span(0), + m_isExploded(false) { - Q_ASSERT(series); setAcceptHoverEvents(true); setAcceptedMouseButtons(Qt::LeftButton); - updateData(); } PieSlice::~PieSlice() { - qDebug() << "~PieSlice()" << m_id; + } QRectF PieSlice::boundingRect() const { - return m_rect; + return m_path.boundingRect(); } QPainterPath PieSlice::shape() const @@ -50,50 +49,43 @@ QPainterPath PieSlice::shape() const void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/) { - // set hover brush - // TODO: what if we are using gradients... - QBrush brush = m_data.brush(); - if (m_isHovering) - brush.setColor(brush.color().lighter()); - painter->setRenderHint(QPainter::Antialiasing); - painter->setPen(m_data.pen()); - painter->setBrush(brush); + painter->setPen(m_pen); + painter->setBrush(m_brush); painter->drawPath(m_path); } void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/) { - m_isHovering = true; - update(); - // TODO: emit hoverEnter() + emit hoverEnter(); } void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/) { - m_isHovering = false; - update(); - // TODO: emit hoverLeave() + emit hoverLeave(); } void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/) { - // TODO: emit clicked - // TODO: should we let the user decide if this can be exploded? - m_data.setExploded(!m_data.isExploded()); - m_series->update(m_data); + emit clicked(); +} + +void PieSlice::setPieRect(QRectF rect) +{ + m_pieRect = rect; } -void PieSlice::updateGeometry(QRectF rect, qreal startAngle, qreal span) +void PieSlice::updateGeometry() { prepareGeometryChange(); // calculate center angle - qreal centerAngle = startAngle + (span/2); + qreal centerAngle = m_angle + (m_span/2); // adjust rect for exploding + QRectF rect = m_pieRect; rect.adjust(EXPLODE_OFFSET, EXPLODE_OFFSET, -EXPLODE_OFFSET ,-EXPLODE_OFFSET); - if (m_data.isExploded()) { + if (m_isExploded) { QPointF d = offset((centerAngle), EXPLODE_OFFSET); rect.translate(d.x(), d.y()); } @@ -102,9 +94,9 @@ void PieSlice::updateGeometry(QRectF rect, qreal startAngle, qreal span) // TODO: draw the shape so that it might have a hole in the center QPainterPath path; path.moveTo(rect.center()); - path.arcTo(rect, -startAngle + 90, -span); + path.arcTo(rect, -m_angle + 90, -m_span); + path.closeSubpath(); m_path = path; - m_rect = path.boundingRect(); // update label position qreal radius = rect.height() / 2; @@ -112,27 +104,36 @@ void PieSlice::updateGeometry(QRectF rect, qreal startAngle, qreal span) m_slicelabel->setArmStartPoint(edgeCenter); m_slicelabel->setArmAngle(centerAngle); - m_slicelabel->setArmLength(50); m_slicelabel->updateGeometry(); - //qDebug() << "PieSlice::updateGeometry" << m_rect; + //qDebug() << "PieSlice::updateGeometry" << m_slicelabel->text() << boundingRect() << m_angle << m_span; +} + +void PieSlice::handleSliceDataChanged() +{ + QPieSlice *slice = qobject_cast(sender()); + Q_ASSERT(slice); + updateData(slice); } -void PieSlice::updateData() +void PieSlice::updateData(const QPieSlice* sliceData) { - if (!m_series->m_slices.contains(m_id)) - qWarning() << "PieSlice::updateData(): cannot find slice data!" << m_id; + // TODO: compare what has changes to avoid unneccesary geometry updates - QPieSlice data = m_series->slice(m_id); - // TODO: find out what has changed and trigger some animation - m_data = data; + m_angle = sliceData->angle(); + m_span = sliceData->span(); + m_isExploded = sliceData->isExploded(); + m_pen = sliceData->pen(); + m_brush = sliceData->brush(); + updateGeometry(); update(); - m_slicelabel->setVisible(m_data.isLabelVisible()); - m_slicelabel->setText(m_data.label()); - //m_slicelabel->setPen(m_data.labelPen()); - //m_slicelabel->setFont(m_data.labelFont()); + m_slicelabel->setVisible(sliceData->isLabelVisible()); + m_slicelabel->setText(sliceData->label()); + m_slicelabel->setPen(sliceData->labelPen()); + m_slicelabel->setFont(sliceData->labelFont()); + m_slicelabel->setArmLength(sliceData->labelArmLenght()); m_slicelabel->updateGeometry(); // text size & font modifies the geometry m_slicelabel->update(); } diff --git a/src/piechart/pieslice.h b/src/piechart/pieslice.h index f9c6476..8a67e72 100644 --- a/src/piechart/pieslice.h +++ b/src/piechart/pieslice.h @@ -12,13 +12,14 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE class PiePresenter; class PieSliceLabel; +class QPieSlice; class PieSlice : public QGraphicsObject { Q_OBJECT public: - PieSlice(QPieSliceId id, QPieSeries *series, QGraphicsItem* parent = 0); + PieSlice(QGraphicsItem* parent = 0); ~PieSlice(); public: // from QGraphicsItem @@ -31,19 +32,27 @@ public: // from QGraphicsItem Q_SIGNALS: void clicked(); + void hoverEnter(); + void hoverLeave(); -public: - void updateGeometry(QRectF rect, qreal startAngle, qreal span); - void updateData(); +public Q_SLOTS: + void handleSliceDataChanged(); + void setPieRect(QRectF rect); + void updateGeometry(); + void updateData(const QPieSlice *sliceData); private: - QPieSliceId m_id; - QPieSeries* m_series; - QPieSlice m_data; PieSliceLabel* m_slicelabel; + + QRectF m_pieRect; QPainterPath m_path; - QRectF m_rect; - bool m_isHovering; + + qreal m_angle; + qreal m_span; + bool m_isExploded; + + QPen m_pen; + QBrush m_brush; }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/piechart/qpieseries.cpp b/src/piechart/qpieseries.cpp index ac5eadc..37e9c1e 100644 --- a/src/piechart/qpieseries.cpp +++ b/src/piechart/qpieseries.cpp @@ -1,112 +1,146 @@ #include "qpieseries.h" +#include "qpieslice.h" #include "piepresenter.h" #include "pieslice.h" #include QTCOMMERCIALCHART_BEGIN_NAMESPACE -QPieSeries::QPieSeries(QObject *parent) : - QChartSeries(parent), - m_sizeFactor(1.0), - m_position(PiePositionMaximized), - m_sliceIdSeed(0) +void QPieSeries::ChangeSet::appendAdded(QPieSlice* slice) { + if (!m_added.contains(slice)) + m_added << slice; } -QPieSeries::~QPieSeries() +void QPieSeries::ChangeSet::appendChanged(QPieSlice* slice) +{ + if (!m_changed.contains(slice)) + m_changed << slice; +} + +void QPieSeries::ChangeSet::appendRemoved(QPieSlice* slice) { + if (!m_removed.contains(slice)) + m_removed << slice; +} +QList QPieSeries::ChangeSet::added() const +{ + return m_added; } -bool QPieSeries::setData(QList data) +QList QPieSeries::ChangeSet::changed() const { - // TODO: remove this function - QList slices; - foreach (int value, data) - slices << QPieSlice(value, QString::number(value)); - return set(slices); + return m_changed; } -bool QPieSeries::set(const QList& slices) +QList QPieSeries::ChangeSet::removed() const { - if (!slices.count()) + return m_removed; +} + +bool QPieSeries::ChangeSet::isEmpty() const +{ + if (m_added.count() || m_changed.count() || m_removed.count()) return false; + return true; +} - ChangeSet changeSet; - foreach (QPieSlice s, m_slices.values()) - changeSet.m_removed << s.id(); +QPieSeries::QPieSeries(QObject *parent) : + QChartSeries(parent), + m_sizeFactor(1.0), + m_position(PiePositionMaximized), + m_pieStartAngle(0), + m_pieSpan(360) +{ - m_slices.clear(); +} - foreach (QPieSlice s, slices) { - s.m_id = generateSliceId(); - m_slices.insert(s.id(), s); - changeSet.m_added << s.id(); - } +QPieSeries::~QPieSeries() +{ - updateDerivativeData(); - emit changed(changeSet); +} +bool QPieSeries::setData(QList data) +{ + // TODO: remove this function + QList slices; + foreach (int value, data) + slices << new QPieSlice(value, QString::number(value)); + set(slices); return true; } -bool QPieSeries::add(const QList& slices) +void QPieSeries::set(QList slices) { - if (!slices.count()) - return false; + clear(); + add(slices); +} +void QPieSeries::add(QList slices) +{ ChangeSet changeSet; - foreach (QPieSlice s, slices) { - s.m_id = generateSliceId(); - m_slices.insert(s.id(), s); - changeSet.m_added << s.id(); + foreach (QPieSlice* s, slices) { + s->setParent(this); + m_slices << s; + changeSet.appendAdded(s); } updateDerivativeData(); - emit changed(changeSet); - return true; + foreach (QPieSlice* s, slices) { + connect(s, SIGNAL(changed()), this, SLOT(sliceChanged())); + connect(s, SIGNAL(clicked()), this, SLOT(sliceClicked())); + connect(s, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter())); + connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave())); + } + + emit changed(changeSet); } -bool QPieSeries::add(const QPieSlice& slice) +void QPieSeries::add(QPieSlice* slice) { - return add(QList() << slice); + add(QList() << slice); } -bool QPieSeries::update(const QPieSlice& slice) +QPieSlice* QPieSeries::add(qreal value, QString name) { - if (!m_slices.contains(slice.id())) - return false; // series does not contain this slice + QPieSlice* slice = new QPieSlice(value, name); + add(slice); + return slice; +} - m_slices[slice.id()] = slice; +void QPieSeries::remove(QPieSlice* slice) +{ + if (!m_slices.removeOne(slice)) { + Q_ASSERT(0); // TODO: remove before release + return; + } ChangeSet changeSet; - changeSet.m_changed << slice.id(); - updateDerivativeData(); + changeSet.appendRemoved(slice); emit changed(changeSet); - return true; + delete slice; + slice = NULL; + + updateDerivativeData(); } -bool QPieSeries::remove(QPieSliceId id) +void QPieSeries::clear() { - if (!m_slices.contains(id)) - return false; // series does not contain this slice - - m_slices.remove(id); + if (m_slices.count() == 0) + return; ChangeSet changeSet; - changeSet.m_removed << id; - updateDerivativeData(); + foreach (QPieSlice* s, m_slices) { + changeSet.appendRemoved(s); + m_slices.removeOne(s); + delete s; + } emit changed(changeSet); - - return true; -} - -QPieSlice QPieSeries::slice(QPieSliceId id) const -{ - return m_slices.value(id); + updateDerivativeData(); } void QPieSeries::setSizeFactor(qreal factor) @@ -128,23 +162,136 @@ void QPieSeries::setPosition(PiePosition position) } } -QPieSliceId QPieSeries::generateSliceId() +void QPieSeries::setSpan(qreal startAngle, qreal span) +{ + if (startAngle >= 0 && startAngle < 360 && + span > 0 && span <= 360) { + m_pieStartAngle = startAngle; + m_pieSpan = span; + updateDerivativeData(); + } +} + +void QPieSeries::setLabelsVisible(bool visible) +{ + foreach (QPieSlice* s, m_slices) + s->setLabelVisible(visible); +} + +void QPieSeries::enableClickExplodes(bool enable) { - // Id is quint64 so it should be enough for us. - // Note that id is not unique between pie series. - return m_sliceIdSeed++; + if (enable) + connect(this, SIGNAL(clicked(QPieSlice*)), this, SLOT(toggleExploded(QPieSlice*))); + else + disconnect(this, SLOT(toggleExploded(QPieSlice*))); +} + +void QPieSeries::enableHoverHighlight(bool enable) +{ + if (enable) { + connect(this, SIGNAL(hoverEnter(QPieSlice*)), this, SLOT(highlightOn(QPieSlice*))); + connect(this, SIGNAL(hoverLeave(QPieSlice*)), this, SLOT(highlightOff(QPieSlice*))); + } else { + disconnect(this, SLOT(hoverEnter(QPieSlice*))); + disconnect(this, SLOT(hoverLeave(QPieSlice*))); + } +} + +void QPieSeries::sliceChanged() +{ + QPieSlice* slice = qobject_cast(sender()); + Q_ASSERT(m_slices.contains(slice)); + + ChangeSet changeSet; + changeSet.appendChanged(slice); + emit changed(changeSet); + + updateDerivativeData(); +} + +void QPieSeries::sliceClicked() +{ + QPieSlice* slice = qobject_cast(sender()); + Q_ASSERT(m_slices.contains(slice)); + emit clicked(slice); +} + +void QPieSeries::sliceHoverEnter() +{ + QPieSlice* slice = qobject_cast(sender()); + Q_ASSERT(m_slices.contains(slice)); + emit hoverEnter(slice); +} + +void QPieSeries::sliceHoverLeave() +{ + QPieSlice* slice = qobject_cast(sender()); + Q_ASSERT(m_slices.contains(slice)); + emit hoverLeave(slice); +} + +void QPieSeries::toggleExploded(QPieSlice* slice) +{ + Q_ASSERT(slice); + slice->setExploded(!slice->isExploded()); +} + +void QPieSeries::highlightOn(QPieSlice* slice) +{ + Q_ASSERT(slice); + QColor c = slice->brush().color().lighter(); + slice->setBrush(c); +} + +void QPieSeries::highlightOff(QPieSlice* slice) +{ + Q_ASSERT(slice); + QColor c = slice->brush().color().darker(150); + slice->setBrush(c); } void QPieSeries::updateDerivativeData() { m_total = 0; - foreach (const QPieSlice& s, m_slices.values()) - m_total += s.value(); - Q_ASSERT(m_total > 0); // TODO: remove this before release + // nothing to do? + if (m_slices.count() == 0) + return; + + // calculate total + foreach (QPieSlice* s, m_slices) + m_total += s->value(); + + // we must have some values + Q_ASSERT(m_total > 0); // TODO - foreach (QPieSliceId id, m_slices.keys()) - m_slices[id].m_percentage = m_slices.value(id).value() / m_total; + // update slice attributes + qreal sliceAngle = m_pieStartAngle; + foreach (QPieSlice* s, m_slices) { + + bool changed = false; + + qreal percentage = s->value() / m_total; + if (s->m_percentage != percentage) { + s->m_percentage = percentage; + changed = true; + } + + qreal sliceSpan = m_pieSpan * percentage; + if (s->m_span != sliceSpan) { + s->m_span = sliceSpan; + changed = true; + } + + if (s->m_angle != sliceAngle) { + s->m_angle = sliceAngle; + changed = true; + } + sliceAngle += sliceSpan; + + if (changed) + emit s->changed(); + } } #include "moc_qpieseries.cpp" diff --git a/src/piechart/qpieseries.h b/src/piechart/qpieseries.h index d3400b7..65e3e72 100644 --- a/src/piechart/qpieseries.h +++ b/src/piechart/qpieseries.h @@ -7,69 +7,13 @@ #include #include #include +#include class QGraphicsObject; QTCOMMERCIALCHART_BEGIN_NAMESPACE class PiePresenter; class PieSlice; - -typedef quint64 QPieSliceId; - -class QPieSlice -{ -public: - QPieSlice() - :m_id(-1), m_value(0), m_isLabelVisible(true), m_isExploded(false), m_percentage(0) {} - - QPieSlice(qreal value, QString label = QString(), bool labelVisible = true, bool exploded = false, QPen pen = QPen(), QBrush brush = QBrush()) - :m_id(-1), m_value(value), m_label(label), m_isLabelVisible(labelVisible), m_isExploded(exploded), m_pen(pen), m_brush(brush), m_percentage(0) {} - - QPieSliceId id() const { return m_id; } - - void setValue(qreal value) { m_value = value; } - qreal value() const { return m_value; } - - void setLabel(QString label) { m_label = label; } - QString label() const { return m_label; } - - void setLabelVisible(bool visible) { m_isLabelVisible = visible; } - bool isLabelVisible() const { return m_isLabelVisible; } - - // TODO: - //void setLabelPen(QPen pen) {}; - //QPen labelPen() const {}; - //void setLabelFont(QFont font); - //QFont labelFont() const; - //void setLabelArmLenght(qreal len) {}; - //qreal labelArmLenght() const {}; - - void setExploded(bool exploded) { m_isExploded = exploded; } - bool isExploded() const { return m_isExploded; } - - void setPen(QPen pen) { m_pen = pen; } - QPen pen() const { return m_pen; } - - void setBrush(QBrush brush) { m_brush = brush; } - QBrush brush() const { return m_brush; } - - qreal percentage() const { return m_percentage; } - -private: - - // TODO: use private class - friend class QPieSeries; - - QPieSliceId m_id; - qreal m_value; - QString m_label; - bool m_isLabelVisible; - bool m_isExploded; - - QPen m_pen; - QBrush m_brush; - - qreal m_percentage; // generated content -}; +class QPieSlice; class QTCOMMERCIALCHART_EXPORT QPieSeries : public QChartSeries { @@ -87,42 +31,48 @@ public: class ChangeSet { public: - QList m_added; - QList m_removed; - QList m_changed; + void appendAdded(QPieSlice* slice); + void appendChanged(QPieSlice* slice); + void appendRemoved(QPieSlice* slice); + + QList added() const; + QList changed() const; + QList removed() const; + + bool isEmpty() const; + + private: + QList m_added; + QList m_changed; + QList m_removed; }; public: QPieSeries(QObject *parent = 0); - ~QPieSeries(); + virtual ~QPieSeries(); public: // from QChartSeries QChartSeriesType type() const { return QChartSeries::SeriesTypePie; } virtual bool setData(QList data); // TODO: remove this public: - // TODO: should we return id/bool or what? - // TODO: should we prefer passing a modifiable reference? - bool set(const QList& slices); - bool add(const QList& slices); - bool add(const QPieSlice& slice); - bool update(const QPieSlice& slice); - bool remove(QPieSliceId id); + void set(QList slices); + void add(QList slices); + void add(QPieSlice* slice); + QPieSlice* add(qreal value, QString name); + void remove(QPieSlice* slice); + void clear(); int count() const { return m_slices.count(); } - QList slices() const { return m_slices.values(); } - QList ids() const { return m_slices.keys(); } - QPieSlice slice(QPieSliceId id) const; + QList slices() const { return m_slices; } - // TODO: sorting? + // TODO: find slices? + // QList findByValue(qreal value); + // ... - // TODO: convenience functions? - //void setValue(QPieSliceId id, qreal value); - //void setLabel(QPieSliceId id, QString label); - //void setPen(QPieSliceId id, QPen pen); - //void setBrush(QPieSliceId id, QBrush brush); - //void setExploded(QPieSliceId id, bool exploded); + // TODO: sorting slices? + // void sort(QPieSeries::SortByValue) void setSizeFactor(qreal sizeFactor); qreal sizeFactor() const { return m_sizeFactor; } @@ -130,18 +80,31 @@ public: void setPosition(PiePosition position); PiePosition position() const { return m_position; } + void setSpan(qreal startAngle, qreal span); + + void setLabelsVisible(bool visible); + void enableClickExplodes(bool enable); + void enableHoverHighlight(bool enable); + Q_SIGNALS: void changed(const QPieSeries::ChangeSet& changeSet); + void clicked(QPieSlice* slice); + void hoverEnter(QPieSlice* slice); + void hoverLeave(QPieSlice* slice); void sizeFactorChanged(); void positionChanged(); - // TODO: - //void sliceClicked(QPieSliceId id); - // ?? void sliceHoverEnter(QPieSliceId id); - // ?? void sliceHoverLeave(QPieSliceId id); +private Q_SLOTS: // should be private and not in the interface + void sliceChanged(); + void sliceClicked(); + void sliceHoverEnter(); + void sliceHoverLeave(); + + void toggleExploded(QPieSlice* slice); + void highlightOn(QPieSlice* slice); + void highlightOff(QPieSlice* slice); private: - QPieSliceId generateSliceId(); void updateDerivativeData(); private: @@ -151,11 +114,12 @@ private: friend class PiePresenter; friend class PieSlice; - QHash m_slices; + QList m_slices; qreal m_sizeFactor; PiePosition m_position; qreal m_total; - QPieSliceId m_sliceIdSeed; + qreal m_pieStartAngle; + qreal m_pieSpan; }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/piechart/qpieslice.cpp b/src/piechart/qpieslice.cpp new file mode 100644 index 0000000..595575a --- /dev/null +++ b/src/piechart/qpieslice.cpp @@ -0,0 +1,181 @@ +#include "qpieslice.h" + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +#define DEFAULT_PEN_COLOR Qt::black +#define DEFAULT_BRUSH_COLOR Qt::white +#define DEFAULT_LABEL_ARM_LENGTH 50 + +QPieSlice::QPieSlice(QObject *parent) + :QObject(parent), + m_value(0), + m_isLabelVisible(true), + m_isExploded(false), + m_percentage(0), + m_angle(0), + m_span(0), + m_pen(DEFAULT_PEN_COLOR), + m_brush(DEFAULT_BRUSH_COLOR), + m_labelPen(DEFAULT_PEN_COLOR), + m_labelArmLength(DEFAULT_LABEL_ARM_LENGTH) +{ + +} + +QPieSlice::QPieSlice(qreal value, QString label, bool labelVisible, QObject *parent) + :QObject(parent), + m_value(value), + m_label(label), + m_isLabelVisible(labelVisible), + m_isExploded(false), + m_percentage(0), + m_angle(0), + m_span(0), + m_pen(DEFAULT_PEN_COLOR), + m_brush(DEFAULT_BRUSH_COLOR), + m_labelPen(DEFAULT_PEN_COLOR), + m_labelArmLength(DEFAULT_LABEL_ARM_LENGTH) +{ + +} + +QPieSlice::~QPieSlice() +{ + +} + +qreal QPieSlice::value() const +{ + return m_value; +} + +QString QPieSlice::label() const +{ + return m_label; +} + +bool QPieSlice::isLabelVisible() const +{ + return m_isLabelVisible; +} + +bool QPieSlice::isExploded() const +{ + return m_isExploded; +} + +qreal QPieSlice::percentage() const +{ + return m_percentage; +} + +qreal QPieSlice::angle() const +{ + return m_angle; +} + +qreal QPieSlice::span() const +{ + return m_span; +} + +QPen QPieSlice::pen() const +{ + return m_pen; +} + +QBrush QPieSlice::brush() const +{ + return m_brush; +} + +QPen QPieSlice::labelPen() const +{ + return m_labelPen; +} + +QFont QPieSlice::labelFont() const +{ + return m_labelFont; +} + +qreal QPieSlice::labelArmLenght() const +{ + return m_labelArmLength; +} + +void QPieSlice::setValue(qreal value) +{ + if (m_value != value) { + m_value = value; + emit changed(); + } +} + +void QPieSlice::setLabel(QString label) +{ + if (m_label != label) { + m_label = label; + emit changed(); + } +} + +void QPieSlice::setLabelVisible(bool visible) +{ + if (m_isLabelVisible != visible) { + m_isLabelVisible = visible; + emit changed(); + } +} + +void QPieSlice::setExploded(bool exploded) +{ + if (m_isExploded != exploded) { + m_isExploded = exploded; + emit changed(); + } +} + +void QPieSlice::setPen(QPen pen) +{ + if (m_pen != pen) { + m_pen = pen; + emit changed(); + } +} + +void QPieSlice::setBrush(QBrush brush) +{ + if (m_brush != brush) { + m_brush = brush; + emit changed(); + } +} + +void QPieSlice::setLabelFont(QFont font) +{ + if (m_labelFont != font) { + m_labelFont = font; + emit changed(); + } +} + +void QPieSlice::setLabelPen(QPen pen) +{ + if (m_labelPen != pen) { + m_labelPen = pen; + emit changed(); + } +} + +void QPieSlice::setLabelArmLength(qreal len) +{ + if (m_labelArmLength != len) { + m_labelArmLength = len; + emit changed(); + } +} + +#include "moc_qpieslice.cpp" + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/piechart/qpieslice.h b/src/piechart/qpieslice.h new file mode 100644 index 0000000..4a3bddf --- /dev/null +++ b/src/piechart/qpieslice.h @@ -0,0 +1,86 @@ +#ifndef QPIESLICE_H +#define QPIESLICE_H + +#include +#include +#include +#include +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject +{ + Q_OBJECT + +public: + QPieSlice(QObject *parent = 0); + QPieSlice(qreal value, QString label, bool labelVisible = true, QObject *parent = 0); + virtual ~QPieSlice(); + + // data + qreal value() const; + QString label() const; + bool isLabelVisible() const; + bool isExploded() const; + + // generated data + qreal percentage() const; + qreal angle() const; + qreal span() const; + + // customization + QPen pen() const; + QBrush brush() const; + QPen labelPen() const; + QFont labelFont() const; + qreal labelArmLenght() const; + +Q_SIGNALS: + void clicked(); + void hoverEnter(); + void hoverLeave(); + void changed(); + +public Q_SLOTS: + + // data + void setLabel(QString label); + void setLabelVisible(bool visible); + void setValue(qreal value); + void setExploded(bool exploded); + + // customization + void setPen(QPen pen); + void setBrush(QBrush brush); + void setLabelFont(QFont font); + void setLabelPen(QPen pen); + void setLabelArmLength(qreal len); + +private: + + // TODO: use private class + friend class QPieSeries; + + // data + qreal m_value; + QString m_label; + bool m_isLabelVisible; + bool m_isExploded; + + // generated data + qreal m_percentage; + qreal m_angle; + qreal m_span; + + // customization + QPen m_pen; + QBrush m_brush; + QPen m_labelPen; + QFont m_labelFont; + qreal m_labelArmLength; +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif // QPIESLICE_H diff --git a/src/qchart.cpp b/src/qchart.cpp index 87dc813..2168467 100644 --- a/src/qchart.cpp +++ b/src/qchart.cpp @@ -1,7 +1,4 @@ #include "qchart.h" -#include "qscatterseries.h" -#include "qscatterseries_p.h" -#include "qpieseries.h" #include "qchartaxis.h" #include "chartpresenter_p.h" #include "chartdataset_p.h" @@ -11,6 +8,9 @@ #include "stackedbarchartseries.h" #include "percentbarchartseries.h" #include "qlinechartseries.h" +#include "qscatterseries.h" +//#include "scatterseries_p.h" +#include "qpieseries.h" #include #include diff --git a/src/qchartview.cpp b/src/qchartview.cpp index d1ba37b..a491fac 100644 --- a/src/qchartview.cpp +++ b/src/qchartview.cpp @@ -11,7 +11,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE QChartView::QChartView(QWidget *parent) : QGraphicsView(parent), -m_scene(new QGraphicsScene()), +m_scene(new QGraphicsScene(this)), m_chart(new QChart()), m_rubberBand(0), m_verticalRubberBand(false), diff --git a/src/qchartview.h b/src/qchartview.h index 44fd94f..85296ae 100644 --- a/src/qchartview.h +++ b/src/qchartview.h @@ -24,7 +24,7 @@ public: //implement from QWidget void resizeEvent(QResizeEvent *event); - void addSeries(QChartSeries* series); + void addSeries(QChartSeries* series); // takes ownership // Convenience function QChartSeries* createSeries(QChartSeries::QChartSeriesType type); diff --git a/src/qscatterseries.cpp b/src/scatterseries/qscatterseries.cpp similarity index 77% rename from src/qscatterseries.cpp rename to src/scatterseries/qscatterseries.cpp index 592782b..d9811d2 100644 --- a/src/qscatterseries.cpp +++ b/src/scatterseries/qscatterseries.cpp @@ -1,12 +1,18 @@ #include "qscatterseries.h" -#include "qscatterseries_p.h" +#include "scatterseries_p.h" #include "qchart.h" QTCOMMERCIALCHART_BEGIN_NAMESPACE QScatterSeriesPrivate::QScatterSeriesPrivate() : - m_data(QList()) + m_data(QList()), + m_markerPen(QPen()), + m_markerBrush(QBrush()), + m_markerShape(QScatterSeries::MarkerShapeDefault) { + // Initialize pen color to invalid to use a theme color by default + m_markerPen.setColor(QColor::Invalid); + m_markerBrush.setColor(QColor::Invalid); } QScatterSeries::QScatterSeries(QObject *parent) : @@ -54,6 +60,26 @@ QPen QScatterSeries::markerPen() return d->m_markerPen; } +void QScatterSeries::setMarkerBrush(QBrush brush) +{ + d->m_markerBrush = brush; +} + +QBrush QScatterSeries::markerBrush() +{ + return d->m_markerBrush; +} + +void QScatterSeries::setMarkerShape(MarkerShape shape) +{ + d->m_markerShape = shape; +} + +QScatterSeries::MarkerShape QScatterSeries::markerShape() +{ + return (QScatterSeries::MarkerShape) d->m_markerShape; +} + #include "moc_qscatterseries.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/qscatterseries.h b/src/scatterseries/qscatterseries.h similarity index 75% rename from src/qscatterseries.h rename to src/scatterseries/qscatterseries.h index acbb619..ef65037 100644 --- a/src/qscatterseries.h +++ b/src/scatterseries/qscatterseries.h @@ -11,8 +11,21 @@ class QScatterSeriesPrivate; class QTCOMMERCIALCHART_EXPORT QScatterSeries : public QChartSeries { Q_OBJECT + +public: + enum MarkerShape { + // TODO: to be defined by the graphics design + // TODO: marker shapes: "x", star, rectangle, tilted rect, triangle, circle, dot + MarkerShapeDefault = 0, + MarkerShapePoint, + MarkerShapeX, + MarkerShapeRectangle, + MarkerShapeTiltedRectangle, + MarkerShapeTriangle, + MarkerShapeCircle + }; + public: - //QScatterSeries(QSeriesData *data, QObject *chart); QScatterSeries(QObject *parent = 0); ~QScatterSeries(); @@ -25,17 +38,20 @@ public: QScatterSeries& operator << (const QPointF &value); void setData(QList data); QList data(); - - //TODO? void insertData(int index, QPointF data); + //TODO: insertData? void setMarkerPen(QPen pen); QPen markerPen(); - // TODO: marker shapes: "x", star, rectangle, tilted rect, triangle, circle, dot - //void setMarkerShape(MarkerShape shape); + void setMarkerBrush(QBrush brush); + QBrush markerBrush(); + void setMarkerShape(MarkerShape shape); + MarkerShape markerShape(); + // TODO: marker size? Q_SIGNALS: - // TODO: move to PIMPL? + // TODO: move to PIMPL for simplicity or does the user ever need these signals? // TODO: more finegrained signaling for performance reasons + // (check QPieSeries implementation with change sets) void changed(); //public Q_SLOTS: diff --git a/src/scatterseries/scatter.pri b/src/scatterseries/scatter.pri new file mode 100644 index 0000000..5f3dfb3 --- /dev/null +++ b/src/scatterseries/scatter.pri @@ -0,0 +1,13 @@ +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD + +SOURCES += \ + $$PWD/qscatterseries.cpp \ + $$PWD/scatterpresenter.cpp + +PRIVATE_HEADERS += \ + $$PWD/scatterpresenter_p.h \ + $$PWD/scatterseries_p.h + +PUBLIC_HEADERS += \ + $$PWD/qscatterseries.h diff --git a/src/scatterpresenter.cpp b/src/scatterseries/scatterpresenter.cpp similarity index 68% rename from src/scatterpresenter.cpp rename to src/scatterseries/scatterpresenter.cpp index 06ebafc..0a4598a 100644 --- a/src/scatterpresenter.cpp +++ b/src/scatterseries/scatterpresenter.cpp @@ -1,4 +1,4 @@ -#include "scatterpresenter.h" +#include "scatterpresenter_p.h" #include "qscatterseries.h" #include #include @@ -43,31 +43,49 @@ void ScatterPresenter::handleModelChanged() void ScatterPresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) { - // TODO: The opacity should be user definable? - //brush.setColor(QColor(255, 82, 0, 100)); - //if (m_series->markerPen().isValid()) { - if (false) { - QPen pen = painter->pen(); - QBrush brush = pen.brush(); - brush.setColor(m_series->markerPen().color()); - pen.setBrush(brush); - pen.setWidth(4); - painter->setPen(pen); - } - else { - // TODO: fix this - QPen pen = painter->pen(); - QBrush brush = pen.brush(); - brush.setColor(m_markerPen.color()); - pen.setBrush(brush); - pen.setWidth(4); - painter->setPen(pen); + // TODO: Optimization: avoid setting on every paint method call? + // The custom settings in series override those defined by the theme + if (m_series->markerPen().color().isValid()) { + painter->setPen(m_series->markerPen()); + painter->setBrush(m_series->markerBrush()); + } else { + painter->setPen(m_markerPen); + painter->setBrush(m_markerBrush); } + int shape = m_series->markerShape(); + for (int i(0); i < m_scenex.count() && i < m_sceney.count(); i++) { if (scene()->width() > m_scenex.at(i) && scene()->height() > m_sceney.at(i)) - //painter->drawArc(m_scenex.at(i), m_sceney.at(i), 2, 2, 0, 5760); - painter->drawPoint(m_scenex.at(i), m_sceney.at(i)); + // Paint a shape + switch (shape) { + case QScatterSeries::MarkerShapeDefault: + // Fallthrough, defaults to circle + case QScatterSeries::MarkerShapeCircle: + painter->drawChord(m_scenex.at(i), m_sceney.at(i), 9, 9, 0, 5760); + break; + case QScatterSeries::MarkerShapePoint: + painter->drawPoint(m_scenex.at(i), m_sceney.at(i)); + break; + case QScatterSeries::MarkerShapeRectangle: + painter->drawRect(m_scenex.at(i), m_sceney.at(i), 9, 9); + break; + case QScatterSeries::MarkerShapeTiltedRectangle: { + // TODO: + static const QPointF points[4] = { + QPointF(-1.0 + m_scenex.at(i), 0.0 + m_sceney.at(i)), + QPointF(0.0 + m_scenex.at(i), 1.0 + m_sceney.at(i)), + QPointF(1.0 + m_scenex.at(i), 0.0 + m_sceney.at(i)), + QPointF(0.0 + m_scenex.at(i), -1.0 + m_sceney.at(i)) + }; + painter->drawPolygon(points, 4); + } + break; + default: + // TODO: implement the rest of the shapes + Q_ASSERT(false); + break; + } } } @@ -89,6 +107,6 @@ void ScatterPresenter::changeGeometry() } } -#include "moc_scatterpresenter.cpp" +#include "moc_scatterpresenter_p.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/scatterpresenter.h b/src/scatterseries/scatterpresenter_p.h similarity index 98% rename from src/scatterpresenter.h rename to src/scatterseries/scatterpresenter_p.h index b6d75be..a5f5a2a 100644 --- a/src/scatterpresenter.h +++ b/src/scatterseries/scatterpresenter_p.h @@ -40,6 +40,7 @@ public: QList m_sceney; Domain m_visibleChartArea; QPen m_markerPen; + QBrush m_markerBrush; }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/qscatterseries_p.h b/src/scatterseries/scatterseries_p.h similarity index 95% rename from src/qscatterseries_p.h rename to src/scatterseries/scatterseries_p.h index cbe256f..8ca522e 100644 --- a/src/qscatterseries_p.h +++ b/src/scatterseries/scatterseries_p.h @@ -18,6 +18,8 @@ public: public: QList m_data; QPen m_markerPen; + QBrush m_markerBrush; + int m_markerShape; }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/src.pro b/src/src.pro index 938da8f..ffac271 100644 --- a/src/src.pro +++ b/src/src.pro @@ -22,8 +22,6 @@ SOURCES += barchart/barchartseries.cpp \ linechart/linechartanimationitem.cpp \ linechart/linechartitem.cpp \ linechart/qlinechartseries.cpp \ - qscatterseries.cpp \ - #scatterpresentation.cpp \ qchart.cpp \ axisitem.cpp \ qchartview.cpp \ @@ -32,16 +30,13 @@ SOURCES += barchart/barchartseries.cpp \ charttheme.cpp \ chartdataset.cpp \ chartpresenter.cpp \ - domain.cpp \ - scatterpresenter.cpp + domain.cpp PRIVATE_HEADERS += linechart/linechartitem_p.h \ linechart/linechartanimationitem_p.h \ barchart/barlabel_p.h \ barchart/bar_p.h \ barchart/separator_p.h \ barchart/barchartmodel_p.h \ - qscatterseries_p.h \ - #scatterpresentation.h \ axisitem_p.h \ chartitem_p.h \ charttheme_p.h \ @@ -59,20 +54,19 @@ PUBLIC_HEADERS += linechart/qlinechartseries.h \ barchart/qbarset.h \ barchart/qbarcategory.h \ qchartseries.h \ - qscatterseries.h \ qchart.h \ qchartglobal.h \ qchartview.h \ qchartaxis.h include(piechart/piechart.pri) - +include(scatterseries/scatter.pri) + THEMES += themes/chartthemeicy_p.h \ themes/chartthemegrayscale_p.h \ themes/chartthemescientific_p.h \ themes/chartthemevanilla_p.h -HEADERS += $$PUBLIC_HEADERS \ - scatterpresenter.h +HEADERS += $$PUBLIC_HEADERS HEADERS += $$PRIVATE_HEADERS HEADERS += $$THEMES INCLUDEPATH += linechart \ @@ -89,15 +83,23 @@ public_headers.files = $$PUBLIC_HEADERS target.path = $$[QT_INSTALL_LIBS] INSTALLS += target \ public_headers -install_build_headers.name = bild_headers -install_build_headers.output = $$CHART_BUILD_HEADER_DIR/${QMAKE_FILE_BASE}.h -install_build_headers.input = PUBLIC_HEADERS -install_build_headers.commands = $$QMAKE_COPY \ +install_build_public_headers.name = bild_public_headers +install_build_public_headers.output = $$CHART_BUILD_PUBLIC_HEADER_DIR/${QMAKE_FILE_BASE}.h +install_build_public_headers.input = PUBLIC_HEADERS +install_build_public_headers.commands = $$QMAKE_COPY \ + ${QMAKE_FILE_NAME} \ + $$CHART_BUILD_PUBLIC_HEADER_DIR +install_build_public_headers.CONFIG += target_predeps \ + no_link +install_build_private_headers.name = bild_private_headers +install_build_private_headers.output = $$CHART_BUILD_PRIVATE_HEADER_DIR/${QMAKE_FILE_BASE}.h +install_build_private_headers.input = PRIVATE_HEADERS +install_build_private_headers.commands = $$QMAKE_COPY \ ${QMAKE_FILE_NAME} \ - $$CHART_BUILD_HEADER_DIR -install_build_headers.CONFIG += target_predeps \ + $$CHART_BUILD_PRIVATE_HEADER_DIR +install_build_private_headers.CONFIG += target_predeps \ no_link -QMAKE_EXTRA_COMPILERS += install_build_headers +QMAKE_EXTRA_COMPILERS += install_build_public_headers install_build_private_headers chartversion.target = qchartversion_p.h chartversion.commands = @echo \ "build_time" \ @@ -114,3 +116,4 @@ unix:QMAKE_DISTCLEAN += -r \ win32:QMAKE_DISTCLEAN += /Q \ $$CHART_BUILD_HEADER_DIR \ $$CHART_BUILD_LIB_DIR + diff --git a/test/qmlchart/qml/qmlchart/main.qml b/test/qmlchart/qml/qmlchart/main.qml index 74d4e33..8a75b2d 100644 --- a/test/qmlchart/qml/qmlchart/main.qml +++ b/test/qmlchart/qml/qmlchart/main.qml @@ -4,114 +4,93 @@ import QtCommercial.Chart 1.0 Rectangle { width: 360 height: 360 - Text { - text: qsTr("Hello World") - anchors.centerIn: parent - } + // Another option for QML data api: // ListModel { // id: listModelForPie // // PieDataElement // ListElement { // label: "Apple" -// value: 40.3 -// } -// ListElement { -// label: "Pumpkin" -// value: 10.1 +// value: 4.3 // } // ListElement { -// label: "Raspberry" +// label: "Blackberry" // value: 15.1 // } -// ListElement { -// label: "Strawberry" -// value: 29.9 -// } // } -// ChartModel { -// id: chartModel -// ListElement { -// label: "dada" -// x: 1.1 -// y: 3.2 -// } -// } - -// ChartModel { -// ScatterElement {x: 1.1; y: 1.2} -// ScatterElement {x: 1.3; y: 1.9} -// ScatterElement {x: 1.1; y: 1.2} -// } - - ListModel { - id: listModelScatter - ListElement { - height: 154 - weight: 54 - } - ListElement { - height: 166 - weight: 64 - } - ListElement { - height: 199 - weight: 97 - } + Component.onCompleted: { +// console.log("Component.onCompleted: " + scatterElement.x); +// console.log("Component.onCompleted: " + scatterElement.y); +// console.log("Component.onCompleted: " + scatterElement.dataX); +// console.log("Component.onCompleted: " + scatterElement.dataY); + //console.log("Component.onCompleted: " + chartModel.get(0).x); + //console.log("Component.onCompleted: " + chartModel.scatterElements); +// console.log("Component.onCompleted: " + elementt.dataX); +// console.log("Component.onCompleted: " + chartModel.get(0).dataX); } -// Chart { -// anchors.fill: parent -// theme: Chart.ThemeIcy -// ScatterSeries { -// model: listModelScatter -// name: "scatter" -// xValue: x -// yValue: y -// } -// } - Chart { - anchors.fill: parent + id: chart1 + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: parent.height / 2 theme: Chart.ThemeIcy +// opacity: 0.3 -// PieSeries { -// labels: ["point1", "point2", "point3", "point4", "point5"] -// datax: [2, 1.5, 3, 3, 3] -// } -// PieSeries { -// name: "raspberry pie" -// seriesLabels: ["point1", "point2", "point3", "point4", "point5"] -// seriesData: [2, 1.5, 3, 3, 3] -// } -// ScatterSeries { -// name: "scatter1" -// datax: [2, 1.5, 3, 3, 3] -// datay: [2, 1.5, 3, 3, 3] -// } -// Series { -// labels: ["point1", "point2", "point3", "point4", "point5"] -// datax: [2, 1.5, 3, 3, 3] -// seriesType: Series.SeriesTypePie -// } Series { seriesType: Series.SeriesTypePie - //model: listModelForPie - //seriesData: {11.0, 6.4, 12.6, 22.4} - //seriesLabels: {"Strawberry", "Blackberry", "Apple", "Pumpkin"} } - Series { -// data: {[1.2], "y":2.2 } - seriesType: Series.SeriesTypeScatter - } - Series { - seriesType: Series.SeriesTypeLine - } + // TODO: a bug: drawing order affects the drawing; if you draw chart1 first (by changing the + // z-order), then chart2 is not shown at all. By drawing chart2 first, both are visible. + // Also, if you don't draw line series on chart1 (only pie), both charts are visible. +// Series { +// seriesType: Series.SeriesTypeLine +// } // TODO: // Series { // seriesType: Series.SeriesTypeBar // } } + + + Chart { + id: chart2 + anchors.top: chart1.bottom + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + theme: Chart.ThemeScientific + + ScatterSeries { + data: [ + ScatterElement { x: 1.1; y: 2.1 }, + ScatterElement { x: 1.2; y: 2.0 }, + ScatterElement { x: 1.4; y: 2.3 } + ] + } + ScatterSeries { + data: [ + ScatterElement { x: 1.2; y: 2.2 }, + ScatterElement { x: 1.3; y: 2.2 }, + ScatterElement { x: 1.7; y: 2.6 } + ] + } + ScatterSeries { + data: [ + ScatterElement { x: 1.3; y: 2.3 }, + ScatterElement { x: 1.5; y: 2.4 }, + ScatterElement { x: 2.0; y: 2.9 } + ] + } + ScatterSeries { + data: [ + ScatterElement { x: 1.4; y: 2.4 }, + ScatterElement { x: 1.8; y: 2.7 }, + ScatterElement { x: 2.5; y: 3.2 } + ] + } + } }